Back to index

webcit  8.12-dfsg
webcit.c
Go to the documentation of this file.
00001 /*
00002  * This is the main transaction loop of the web service.  It maintains a
00003  * persistent session to the Citadel server, handling HTTP WebCit requests as
00004  * they arrive and presenting a user interface.
00005  *
00006  * Copyright (c) 1996-2012 by the citadel.org team
00007  *
00008  * This program is open source software.  You can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License, version 3.
00010  */
00011 
00012 #define SHOW_ME_VAPPEND_PRINTF
00013 #include <stdio.h>
00014 #include <stdarg.h>
00015 #include "webcit.h"
00016 #include "dav.h"
00017 #include "webserver.h"
00018 
00019 StrBuf *csslocal = NULL;
00020 HashList *HandlerHash = NULL;
00021 
00022 void stuff_to_cookie(int unset_cookie);
00023 extern int GetConnected(void);
00024 
00025 
00026 void PutRequestLocalMem(void *Data, DeleteHashDataFunc DeleteIt)
00027 {
00028         wcsession *WCC = WC;
00029        int n;
00030        
00031        n = GetCount(WCC->Hdr->HTTPHeaders);
00032        Put(WCC->Hdr->HTTPHeaders, IKEY(n), Data, DeleteIt);
00033 }
00034 
00035 void DeleteWebcitHandler(void *vHandler)
00036 {
00037        WebcitHandler *Handler = (WebcitHandler*) vHandler;
00038        FreeStrBuf(&Handler->Name);
00039        FreeStrBuf(&Handler->DisplayName);
00040        free (Handler);
00041 }
00042 
00043 void WebcitAddUrlHandler(const char * UrlString, long UrlSLen, 
00044                       const char *DisplayName, long dslen,
00045                       WebcitHandlerFunc F, 
00046                       long Flags)
00047 {
00048        WebcitHandler *NewHandler;  
00049        NewHandler = (WebcitHandler*) malloc(sizeof(WebcitHandler));
00050        NewHandler->F = F;
00051        NewHandler->Flags = Flags;
00052        NewHandler->Name = NewStrBufPlain(UrlString, UrlSLen);
00053        StrBufShrinkToFit(NewHandler->Name, 1);
00054        NewHandler->DisplayName = NewStrBufPlain(DisplayName, dslen);
00055        StrBufShrinkToFit(NewHandler->DisplayName, 1);
00056        Put(HandlerHash, UrlString, UrlSLen, NewHandler, DeleteWebcitHandler);
00057 }
00058 
00059 void tmplput_HANDLER_DISPLAYNAME(StrBuf *Target, WCTemplputParams *TP) 
00060 {
00061        wcsession *WCC = WC;
00062        if (WCC->Hdr->HR.Handler != NULL)
00063               StrBufAppendTemplate(Target, TP, WCC->Hdr->HR.Handler->DisplayName, 0);
00064 }
00065 
00066 
00067 /*
00068  * web-printing funcion. uses our vsnprintf wrapper
00069  */
00070 #ifdef UBER_VERBOSE_DEBUGGING
00071 void wcc_printf(const char *FILE, const char *FUNCTION, long LINE, const char *format,...)
00072 #else
00073 void wc_printf(const char *format,...)
00074 #endif
00075 {
00076        wcsession *WCC = WC;
00077        va_list arg_ptr;
00078 
00079        if (WCC->WBuf == NULL)
00080               WCC->WBuf = NewStrBuf();
00081 #ifdef UBER_VERBOSE_DEBUGGING
00082        StrBufAppendPrintf(WCC->WBuf, "\n%s:%s:%d[", FILE, FUNCTION, LINE);
00083 #endif
00084 
00085        va_start(arg_ptr, format);
00086        StrBufVAppendPrintf(WCC->WBuf, format, arg_ptr);
00087        va_end(arg_ptr);
00088 #ifdef UBER_VERBOSE_DEBUGGING
00089        StrBufAppendPrintf(WCC->WBuf, "]\n");
00090 #endif
00091 }
00092 
00093 /*
00094  * http-header-printing funcion. uses our vsnprintf wrapper
00095  */
00096 void hprintf(const char *format,...)
00097 {
00098        wcsession *WCC = WC;
00099        va_list arg_ptr;
00100 
00101        va_start(arg_ptr, format);
00102        StrBufVAppendPrintf(WCC->HBuf, format, arg_ptr);
00103        va_end(arg_ptr);
00104 }
00105 
00106 
00107 
00108 /*
00109  * wrap up an HTTP session, closes tags, etc.
00110  *
00111  * print_standard_html_footer should be set to:
00112  * 0          - to transmit only,
00113  * nonzero    - to append the closing tags
00114  */
00115 void wDumpContent(int print_standard_html_footer)
00116 {
00117        if (print_standard_html_footer) {
00118               wc_printf("</div> <!-- end of 'content' div -->\n");
00119               do_template("trailing");
00120        }
00121 
00122        /* If we've been saving it all up for one big output burst,
00123         * go ahead and do that now.
00124         */
00125        end_burst();
00126 }
00127 
00128 
00129  
00130 
00131 /*
00132  * Output HTTP headers and leading HTML for a page
00133  */
00134 void output_headers( int do_httpheaders,  /* 1 = output HTTP headers                  */
00135                      int do_htmlhead,     /* 1 = output HTML <head> section and <body> opener */
00136                      int do_room_banner,  /* 1 = include the room banner and <div id="content"></div> */
00137                      int unset_cookies,   /* 1 = session is terminating, so unset the cookies */
00138                      int suppress_check,  /* 1 = suppress check for instant messages         */
00139                      int cache            /* 1 = allow browser to cache this page        */
00140 ) {
00141        wcsession *WCC = WC;
00142        char httpnow[128];
00143 
00144        hprintf("HTTP/1.1 200 OK\n");
00145        http_datestring(httpnow, sizeof httpnow, time(NULL));
00146 
00147        if (do_httpheaders) {
00148               if (WCC->serv_info != NULL)
00149                      hprintf("Content-type: text/html; charset=utf-8\r\n"
00150                             "Server: %s / %s\n"
00151                             "Connection: close\r\n",
00152                             PACKAGE_STRING, 
00153                             ChrPtr(WCC->serv_info->serv_software));
00154               else
00155                      hprintf("Content-type: text/html; charset=utf-8\r\n"
00156                             "Server: %s / [n/a]\n"
00157                             "Connection: close\r\n",
00158                             PACKAGE_STRING);
00159        }
00160 
00161        if (cache > 0) {
00162               char httpTomorow[128];
00163 
00164               http_datestring(httpTomorow, sizeof httpTomorow, 
00165                             time(NULL) + 60 * 60 * 24 * 2);
00166 
00167               hprintf("Pragma: public\r\n"
00168                      "Cache-Control: max-age=3600, must-revalidate\r\n"
00169                      "Last-modified: %s\r\n"
00170                      "Expires: %s\r\n",
00171                      httpnow,
00172                      httpTomorow
00173               );
00174        }
00175        else {
00176               hprintf("Pragma: no-cache\r\n"
00177                      "Cache-Control: no-store\r\n"
00178                      "Expires: -1\r\n"
00179               );
00180        }
00181 
00182        if (cache < 2) stuff_to_cookie(unset_cookies);
00183 
00184        if (do_htmlhead) {
00185               begin_burst();
00186               do_template("head");
00187               if ( (WCC->logged_in) && (!unset_cookies) ) {
00188                      DoTemplate(HKEY("paging"), NULL, &NoCtx);
00189               }
00190               if (do_room_banner) {
00191                      tmplput_roombanner(NULL, NULL);
00192               }
00193        }
00194 
00195        if (do_room_banner) {
00196               wc_printf("<div id=\"content\">\n");
00197        }
00198 }
00199 
00200 void output_custom_content_header(const char *ctype) {
00201        hprintf("HTTP/1.1 200 OK\r\n");
00202        hprintf("Content-type: %s; charset=utf-8\r\n",ctype);
00203        hprintf("Server: %s / %s\r\n", PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software));
00204        hprintf("Connection: close\r\n");
00205 }
00206 
00207 
00208 /*
00209  * Generic function to do an HTTP redirect.  Easy and fun.
00210  */
00211 void http_redirect(const char *whichpage) {
00212        hprintf("HTTP/1.1 302 Moved Temporarily\n");
00213        hprintf("Location: %s\r\n", whichpage);
00214        hprintf("URI: %s\r\n", whichpage);
00215        hprintf("Content-type: text/html; charset=utf-8\r\n");
00216        stuff_to_cookie(0);
00217        begin_burst();
00218        wc_printf("<html><body>");
00219        wc_printf("Go <a href=\"%s\">here</A>.", whichpage);
00220        wc_printf("</body></html>\n");
00221        end_burst();
00222 }
00223 
00224 
00225 
00226 /*
00227  * Output a piece of content to the web browser using conformant HTTP and MIME semantics.
00228  *
00229  * If this function is called, it is expected that begin_burst() has already been called
00230  * and some sort of content has been fed into the buffer.  This function will transmit a
00231  * bunch of headers to the client.  end_burst() will add some headers of its own, and then
00232  * transmit the buffered content to the client.
00233  */
00234 void http_transmit_thing(const char *content_type, int is_static)
00235 {
00236        syslog(9, "http_transmit_thing(%s)%s", content_type, ((is_static > 0) ? " (static)" : ""));
00237        output_headers(0, 0, 0, 0, 0, is_static);
00238 
00239        hprintf("Content-type: %s\r\n"
00240               "Server: %s\r\n"
00241               "Connection: close\r\n",
00242               content_type,
00243               PACKAGE_STRING);
00244 
00245        end_burst();
00246 }
00247 
00248 
00249 /*
00250  * Convenience functions to display a page containing only a string
00251  *
00252  * titlebarcolor     color of the titlebar of the frame
00253  * titlebarmsg              text to display in the title bar
00254  * messagetext              body of the box
00255  */
00256 void convenience_page(const char *titlebarcolor, const char *titlebarmsg, const char *messagetext)
00257 {
00258        hprintf("HTTP/1.1 200 OK\n");
00259        output_headers(1, 1, 1, 0, 0, 0);
00260        wc_printf("<div id=\"room_banner_override\">\n");
00261        wc_printf("<table width=100%% border=0 bgcolor=\"#%s\"><tr><td>", titlebarcolor);
00262        wc_printf("<span class=\"titlebar\">%s</span>\n", titlebarmsg);
00263        wc_printf("</td></tr></table>\n");
00264        wc_printf("</div>\n<div id=\"content\">\n");
00265        escputs(messagetext);
00266        wc_printf("<hr />\n");
00267        wDumpContent(1);
00268 }
00269 
00270 
00271 /*
00272  * Display a blank page.
00273  */
00274 void blank_page(void) {
00275        output_headers(1, 1, 0, 0, 0, 0);
00276        wDumpContent(2);
00277 }
00278 
00279 
00280 /*
00281  * A template has been requested
00282  */
00283 void url_do_template(void) {
00284        const StrBuf *MimeType;
00285        const StrBuf *Tmpl = sbstr("template");
00286        begin_burst();
00287        MimeType = DoTemplate(SKEY(Tmpl), NULL, &NoCtx);
00288        http_transmit_thing(ChrPtr(MimeType), 0);
00289 }
00290 
00291 
00292 
00293 /*
00294  * convenience function to indicate success
00295  */
00296 void display_success(const char *successmessage)
00297 {
00298        convenience_page("007700", "OK", successmessage);
00299 }
00300 
00301 
00302 /*
00303  * Authorization required page (sends a 401, causing the browser to request login credentials)
00304  */
00305 void authorization_required(void)
00306 {
00307        wcsession *WCC = WC;
00308        const char *message = "";
00309 
00310        hprintf("HTTP/1.1 401 Authorization Required\r\n");
00311        hprintf(
00312               "Server: %s / %s\r\n"
00313               "Connection: close\r\n",
00314               PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software)
00315        );
00316        hprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n", ChrPtr(WC->serv_info->serv_humannode));
00317        hprintf("Content-Type: text/html\r\n");
00318        begin_burst();
00319        wc_printf("<h1>");
00320        wc_printf(_("Authorization Required"));
00321        wc_printf("</h1>\r\n");
00322 
00323        if (WCC->ImportantMsg != NULL) {
00324               message = ChrPtr(WCC->ImportantMsg);
00325        }
00326 
00327        wc_printf(
00328               _("The resource you requested requires a valid username and password. "
00329               "You could not be logged in: %s\n"),
00330               message
00331        );
00332        wDumpContent(0);
00333 }
00334 
00335 
00336 /*
00337  * Convenience functions to wrap around asynchronous ajax responses
00338  */
00339 void begin_ajax_response(void) {
00340        wcsession *WCC = WC;
00341 
00342        FlushStrBuf(WCC->HBuf);
00343        output_headers(0, 0, 0, 0, 0, 0);
00344 
00345        hprintf("Content-type: text/html; charset=UTF-8\r\n"
00346               "Server: %s\r\n"
00347               "Connection: close\r\n"
00348               ,
00349               PACKAGE_STRING);
00350        begin_burst();
00351 }
00352 
00353 
00354 /*
00355  * print ajax response footer 
00356  */
00357 void end_ajax_response(void) {
00358        wDumpContent(0);
00359 }
00360 
00361 
00362 /*
00363  * Wraps a Citadel server command in an AJAX transaction.
00364  */
00365 void ajax_servcmd(void)
00366 {
00367        wcsession *WCC = WC;
00368        int Done = 0;
00369        StrBuf *Buf;
00370        char *junk;
00371        size_t len;
00372 
00373        syslog(LOG_DEBUG, "ajax_servcmd() g_cmd=\"%s\"", bstr("g_cmd") );
00374        begin_ajax_response();
00375        Buf = NewStrBuf();
00376        serv_puts(bstr("g_cmd"));
00377        StrBuf_ServGetln(Buf);
00378        StrBufAppendBuf(WCC->WBuf, Buf, 0);
00379        StrBufAppendBufPlain(WCC->WBuf, HKEY("\n"), 0);
00380        
00381        switch (GetServerStatus(Buf, NULL)) {
00382        case 8:
00383               serv_puts("\n\n000");
00384               if ( (StrLength(Buf)==3) && 
00385                    !strcmp(ChrPtr(Buf), "000")) {
00386                      StrBufAppendBufPlain(WCC->WBuf, HKEY("\000"), 0);
00387                      break;
00388               }
00389        case 1:
00390               while (!Done) {
00391                      if (StrBuf_ServGetln(Buf) < 0)
00392                             break;
00393                      if ( (StrLength(Buf)==3) && 
00394                           !strcmp(ChrPtr(Buf), "000")) {
00395                             Done = 1;
00396                      }
00397                      StrBufAppendBuf(WCC->WBuf, Buf, 0);
00398                      StrBufAppendBufPlain(WCC->WBuf, HKEY("\n"), 0);
00399               }
00400               break;
00401        case 4:
00402               text_to_server(bstr("g_input"));
00403               serv_puts("000");
00404               break;
00405        case 6:
00406               len = atol(&ChrPtr(Buf)[4]);
00407               StrBuf_ServGetBLOBBuffered(Buf, len);
00408               break;
00409        case 7:
00410               len = atol(&ChrPtr(Buf)[4]);
00411               junk = malloc(len);
00412               memset(junk, 0, len);
00413               serv_write(junk, len);
00414               free(junk);
00415        }
00416        
00417        end_ajax_response();
00418        
00419        /*
00420         * This is kind of an ugly hack, but this is the only place it can go.
00421         * If the command was GEXP, then the instant messenger window must be
00422         * running, so reset the "last_pager_check" watchdog timer so
00423         * that page_popup() doesn't try to open it a second time. TODO: page_popup isn't with us anymore.
00424         */
00425        if (!strncasecmp(bstr("g_cmd"), "GEXP", 4)) {
00426               WCC->last_pager_check = time(NULL);
00427        }
00428        FreeStrBuf(&Buf);
00429 }
00430 
00431 
00432 /*
00433  * Helper function for the asynchronous check to see if we need
00434  * to open the instant messenger window.
00435  */
00436 void seconds_since_last_gexp(void)
00437 {
00438        char buf[256];
00439 
00440        if ( (time(NULL) - WC->last_pager_check) < 30) {
00441               wc_printf("NO\n");
00442        }
00443        else {
00444               memset(buf, 0, 5);
00445               serv_puts("NOOP");
00446               serv_getln(buf, sizeof buf);
00447               if (buf[3] == '*') {
00448                      wc_printf("YES");
00449               }
00450               else {
00451                      wc_printf("NO");
00452               }
00453        }
00454 }
00455 
00456 
00457 /*
00458  * Save a URL destination so we can go to it later
00459  */
00460 void push_destination(void) {
00461        wcsession *WCC = WC;
00462 
00463        if (!WCC) {
00464               wc_printf("no session");
00465               return;
00466        }
00467 
00468        FreeStrBuf(&WCC->PushedDestination);
00469        WCC->PushedDestination = NewStrBufDup(SBSTR("url"));
00470        syslog(9, "Push: %s", ChrPtr(WCC->PushedDestination));
00471        wc_printf("OK");
00472 }
00473 
00474 
00475 /*
00476  * Go to the URL saved by push_destination()
00477  */
00478 void pop_destination(void) {
00479        wcsession *WCC = WC;
00480 
00481        /*
00482         * If we are in the middle of a new user signup, the server may request that
00483         * we first pass through a registration screen.
00484         */
00485        if ((WCC) && (WCC->need_regi)) {
00486               if ((WCC->PushedDestination != NULL) && (StrLength(WCC->PushedDestination) > 0)) {
00487                      /* Registering will take us to the My Citadel Config room, so save our place */
00488                      StrBufAppendBufPlain(WCC->PushedDestination, HKEY("?go="), 0);
00489                      StrBufUrlescAppend(WCC->PushedDestination, WCC->CurRoom.name, NULL);
00490               }
00491               WCC->need_regi = 0;
00492               display_reg(1);
00493               return;
00494        }
00495 
00496        /*
00497         * Do something reasonable if we somehow ended up requesting a pop without
00498         * having first done a push.
00499         */
00500        if ( (!WCC) || (WCC->PushedDestination == NULL) || (StrLength(WCC->PushedDestination) == 0) ) {
00501               do_welcome();
00502               return;
00503        }
00504 
00505        /*
00506         * All righty then!  We have a destination saved, so go there now.
00507         */
00508        syslog(9, "Pop: %s", ChrPtr(WCC->PushedDestination));
00509        http_redirect(ChrPtr(WCC->PushedDestination));
00510 }
00511 
00512 
00513 
00514 int ReadPostData(void)
00515 {
00516        int rc;
00517        int urlencoded_post = 0;
00518        wcsession *WCC = WC;
00519        StrBuf *content = NULL;
00520        
00521        urlencoded_post = (strncasecmp(ChrPtr(WCC->Hdr->HR.ContentType), "application/x-www-form-urlencoded", 33) == 0) ;
00522 
00523        content = NewStrBufPlain(NULL, WCC->Hdr->HR.ContentLength + 256);
00524 
00525        if (!urlencoded_post)
00526        {
00527               StrBufPrintf(content, 
00528                    "Content-type: %s\n"
00529                           "Content-length: %ld\n\n",
00530                           ChrPtr(WCC->Hdr->HR.ContentType), 
00531                           WCC->Hdr->HR.ContentLength);
00532        }
00533 
00535        rc = client_read_to(WCC->Hdr, content, 
00536                          WCC->Hdr->HR.ContentLength,
00537                          SLEEPING);
00538        if (rc < 0)
00539               return rc;
00540               
00541        
00542        if (urlencoded_post) {
00543               ParseURLParams(content);
00544        } else if (!strncasecmp(ChrPtr(WCC->Hdr->HR.ContentType), "multipart", 9)) {
00545               char *Buf;
00546               char *BufEnd;
00547               long len;
00548 
00549               len = StrLength(content);
00550               Buf = SmashStrBuf(&content);
00551               BufEnd = Buf + len;
00552               mime_parser(Buf, BufEnd, *upload_handler, NULL, NULL, NULL, 0);
00553               free(Buf);
00554        } else if (WCC->Hdr->HR.ContentLength > 0) {
00555               WCC->upload = content;
00556               WCC->upload_length = StrLength(WCC->upload);
00557               content = NULL;
00558        }
00559        FreeStrBuf(&content);
00560        return 1;
00561 }
00562 
00563 
00564 int Conditional_REST_DEPTH(StrBuf *Target, WCTemplputParams *TP)
00565 {
00566        long Depth, IsDepth;
00567        long offset = 0;
00568        wcsession *WCC = WC;
00569 
00570        if (WCC->Hdr->HR.Handler != NULL)
00571               offset ++;
00572        Depth = GetTemplateTokenNumber(Target, TP, 2, 0);
00573        IsDepth = GetCount(WCC->Directory) + offset;
00574 
00575 //     LogTemplateError(Target, "bla", 1, TP, "REST_DEPTH: %ld : %ld\n", Depth, IsDepth);
00576        if (Depth < 0) {
00577               Depth = -Depth;
00578               return IsDepth > Depth;
00579        }
00580        else 
00581               return Depth == IsDepth;
00582 }
00583 
00584 
00585 
00586 /*
00587  * Entry point for WebCit transaction
00588  */
00589 void session_loop(void)
00590 {
00591        int xhttp;
00592        StrBuf *Buf;
00593        
00594        /*
00595         * We stuff these with the values coming from the client cookies,
00596         * so we can use them to reconnect a timed out session if we have to.
00597         */
00598        wcsession *WCC;
00599       
00600        WCC= WC;
00601        WCC->upload_length = 0;
00602        WCC->upload = NULL;
00603        WCC->Hdr->nWildfireHeaders = 0;
00604 
00605        if (WCC->Hdr->HR.ContentLength > 0) {
00606               if (ReadPostData() < 0) {
00607                      return;
00608               }
00609        }
00610 
00611        Buf = NewStrBuf();
00612        WCC->trailing_javascript = NewStrBuf();
00613 
00614        /* Convert base64-encoded URL's back to plain text */
00615        if (!strncmp(ChrPtr(WCC->Hdr->this_page), "/B64", 4)) {
00616               StrBufCutLeft(WCC->Hdr->this_page, 4);
00617               StrBufDecodeBase64(WCC->Hdr->this_page);
00618               http_redirect(ChrPtr(WCC->Hdr->this_page));
00619               goto SKIP_ALL_THIS_CRAP;
00620        }
00621 
00622        /* If there are variables in the URL, we must grab them now */
00623        if (WCC->Hdr->PlainArgs != NULL)
00624               ParseURLParams(WCC->Hdr->PlainArgs);
00625 
00626        /* If the client sent a nonce that is incorrect, kill the request. */
00627        if (havebstr("nonce")) {
00628               syslog(9, "Comparing supplied nonce %s to session nonce %d", 
00629                      bstr("nonce"), WCC->nonce
00630               );
00631               if (ibstr("nonce") != WCC->nonce) {
00632                      syslog(9, "Ignoring request with mismatched nonce.");
00633                      hprintf("HTTP/1.1 404 Security check failed\r\n");
00634                      hprintf("Content-Type: text/plain\r\n");
00635                      begin_burst();
00636                      wc_printf("Security check failed.\r\n");
00637                      end_burst();
00638                      goto SKIP_ALL_THIS_CRAP;
00639               }
00640        }
00641 
00642        /*
00643         * If we're not connected to a Citadel server, try to hook up the connection now.
00644         */
00645        if (!WCC->connected) {
00646               if (GetConnected()) {
00647                      hprintf("HTTP/1.1 503 Service Unavailable\r\n");
00648                      hprintf("Content-Type: text/html\r\n");
00649                      begin_burst();
00650                      wc_printf("<html><head><title>503 Service Unavailable</title></head><body>\n");
00651                      wc_printf(_("This program was unable to connect or stay "
00652                             "connected to the Citadel server.  Please report "
00653                             "this problem to your system administrator.")
00654                      );
00655                      wc_printf("<br>");
00656                      wc_printf("<a href=\"http://www.citadel.org/doku.php/"
00657                             "faq:generalquestions:webcit_unable_to_connect\">%s</a>",
00658                             _("Read More...")
00659                      );
00660                      wc_printf("</body></html>\n");
00661                      end_burst();
00662                      goto SKIP_ALL_THIS_CRAP;
00663               }
00664        }
00665 
00666        /*
00667         * If we're not logged in, but we have authentication data (either from
00668         * a cookie or from http-auth), try logging in to Citadel using that.
00669         */
00670        if (   (!WCC->logged_in)
00671               && (StrLength(WCC->Hdr->c_username) > 0)
00672               && (StrLength(WCC->Hdr->c_password) > 0)
00673        ) {
00674               long Status;
00675 
00676               FlushStrBuf(Buf);
00677               serv_printf("USER %s", ChrPtr(WCC->Hdr->c_username));
00678               StrBuf_ServGetln(Buf);
00679               if (GetServerStatus(Buf, &Status) == 3) {
00680                      serv_printf("PASS %s", ChrPtr(WCC->Hdr->c_password));
00681                      StrBuf_ServGetln(Buf);
00682                      if (GetServerStatus(Buf, NULL) == 2) {
00683                             become_logged_in(WCC->Hdr->c_username,
00684                                            WCC->Hdr->c_password, Buf);
00685                      } else {
00686                             /* Should only display when password is wrong */
00687                             WCC->ImportantMsg = NewStrBufPlain(ChrPtr(Buf) + 4, StrLength(Buf) - 4);
00688                             authorization_required();
00689                             FreeStrBuf(&Buf);
00690                             goto SKIP_ALL_THIS_CRAP;
00691                      }
00692               }
00693               else if (Status == 541) {
00694                      WCC->logged_in = 1;
00695               }
00696        }
00697 
00698        xhttp = (WCC->Hdr->HR.eReqType != eGET) &&
00699               (WCC->Hdr->HR.eReqType != ePOST) &&
00700               (WCC->Hdr->HR.eReqType != eHEAD);
00701 
00702        /*
00703         * If a 'go' (or 'gotofirst') parameter has been specified, attempt to goto that room
00704         * prior to doing anything else.
00705         */
00706        if (havebstr("go")) {
00707               int ret;
00708               syslog(9, "Explicit room selection: %s", bstr("go"));
00709               ret = gotoroom(sbstr("go"));       /* do quietly to avoid session output! */
00710               if ((ret/100) != 2) {
00711                      syslog(1, "Unable to change to [%s]; Reason: %d", bstr("go"), ret);
00712               }
00713        }
00714        else if (havebstr("gotofirst")) {
00715               int ret;
00716               syslog(9, "Explicit room selection: %s", bstr("gotofirst"));
00717               ret = gotoroom(sbstr("gotofirst"));       /* do quietly to avoid session output! */
00718               if ((ret/100) != 2) {
00719                      syslog(1, "Unable to change to [%s]; Reason: %d", bstr("gotofirst"), ret);
00720               }
00721        }
00722 
00723        /*
00724         * If we aren't in any room yet, but we have cookie data telling us where we're
00725         * supposed to be, and 'go' was not specified, then go there.
00726         */
00727        else if ( (StrLength(WCC->CurRoom.name) == 0) && ( (StrLength(WCC->Hdr->c_roomname) > 0) )) {
00728               int ret;
00729 
00730               syslog(9, "We are in '%s' but cookie indicates '%s', going there...",
00731                      ChrPtr(WCC->CurRoom.name),
00732                      ChrPtr(WCC->Hdr->c_roomname)
00733               );
00734               ret = gotoroom(WCC->Hdr->c_roomname);     /* do quietly to avoid session output! */
00735               if ((ret/100) != 2) {
00736                      syslog(1, "COOKIEGOTO: Unable to change to [%s]; Reason: %d",
00737                             ChrPtr(WCC->Hdr->c_roomname), ret);
00738               }
00739        }
00740 
00741        if (WCC->Hdr->HR.Handler != NULL) {
00742               if (   (!WCC->logged_in)
00743                      && ((WCC->Hdr->HR.Handler->Flags & ANONYMOUS) == 0)
00744                      && (WCC->serv_info->serv_supports_guest == 0)
00745               ) {
00746                      display_login();
00747               }
00748               else {
00749                      if ((WCC->Hdr->HR.Handler->Flags & AJAX) != 0) {
00750                             begin_ajax_response();
00751                      }
00752                      WCC->Hdr->HR.Handler->F();
00753                      if ((WCC->Hdr->HR.Handler->Flags & AJAX) != 0) {
00754                             end_ajax_response();
00755                      }
00756               }
00757        }
00758        /* When all else fails, display the default landing page or a main menu. */
00759        else {
00760               /* 
00761                * ordinary browser users get a nice login screen, DAV etc. requsets
00762                * are given a 401 so they can handle it appropriate.
00763                */
00764               if (!WCC->logged_in)  {
00765                      if (xhttp) {
00766                             authorization_required();
00767                      }
00768                      else {
00769                             display_default_landing_page();
00770                      }
00771               }
00772               /*
00773                * Toplevel dav requests? or just a flat browser request? 
00774                */
00775               else {
00776                      if (xhttp) {
00777                             dav_main();
00778                      }
00779                      else {
00780                             display_main_menu();
00781                      }
00782               }
00783        }
00784 
00785 SKIP_ALL_THIS_CRAP:
00786        FreeStrBuf(&Buf);
00787        fflush(stdout);
00788 }
00789 
00790 
00791 
00792 /*
00793  * Display the appropriate landing page for this site.
00794  */
00795 void display_default_landing_page(void) {
00796        wcsession *WCC = WC;
00797 
00798        if (WCC && WCC->serv_info && WCC->serv_info->serv_supports_guest) {
00799               /* default action */
00800 
00801               if (havebstr("go")) {
00802                      syslog(9, "Explicit room selection: %s", bstr("go"));
00803                      StrBuf *teh_room = NewStrBufPlain(bstr("go"), strlen(bstr("go")));
00804                      smart_goto(teh_room);
00805                      FreeStrBuf(&teh_room);
00806               }
00807               else if (default_landing_page) {
00808                      http_redirect(default_landing_page);
00809               }
00810               else {
00811                      StrBuf *teh_lobby = NewStrBufPlain(HKEY("_BASEROOM_"));
00812                      smart_goto(teh_lobby);
00813                      FreeStrBuf(&teh_lobby);
00814               }
00815        }
00816        else {
00817               display_login();
00818        }
00819 }
00820 
00821 
00822 /*
00823  * Replacement for sleep() that uses select() in order to avoid SIGALRM
00824  */
00825 void sleeeeeeeeeep(int seconds)
00826 {
00827        struct timeval tv;
00828 
00829        tv.tv_sec = seconds;
00830        tv.tv_usec = 0;
00831        select(0, NULL, NULL, NULL, &tv);
00832 }
00833 
00834 int Conditional_IS_HTTPS(StrBuf *Target, WCTemplputParams *TP)
00835 {
00836        return is_https != 0;
00837 }
00838 
00839 void AppendImportantMessage(const char *pch, long len)
00840 {
00841        wcsession *WCC = WC;
00842 
00843        if (StrLength(WCC->ImportantMsg) > 0) {
00844               StrBufAppendBufPlain(WCC->ImportantMsg, HKEY("\n"), 0);
00845        }
00846               
00847        StrBufAppendBufPlain(WCC->ImportantMsg, pch, len, 0);
00848 }
00849 
00850 int ConditionalImportantMesage(StrBuf *Target, WCTemplputParams *TP)
00851 {
00852        wcsession *WCC = WC;
00853        if (WCC != NULL)
00854               return (StrLength(WCC->ImportantMsg) > 0);
00855        else
00856               return 0;
00857 }
00858 
00859 void tmplput_importantmessage(StrBuf *Target, WCTemplputParams *TP)
00860 {
00861        wcsession *WCC = WC;
00862        
00863        if (WCC != NULL) {
00864               if (StrLength(WCC->ImportantMsg) > 0) {
00865                      StrEscAppend(Target, WCC->ImportantMsg, NULL, 0, 0);
00866                      FlushStrBuf(WCC->ImportantMsg);
00867               }
00868        }
00869 }
00870 
00871 void tmplput_trailing_javascript(StrBuf *Target, WCTemplputParams *TP)
00872 {
00873        wcsession *WCC = WC;
00874 
00875        if (WCC != NULL)
00876               StrBufAppendTemplate(Target, TP, WCC->trailing_javascript, 0);
00877 }
00878 
00879 void tmplput_csslocal(StrBuf *Target, WCTemplputParams *TP)
00880 {
00881        StrBufAppendBuf(Target, 
00882                      csslocal, 0);
00883 }
00884 
00885 void tmplput_packagestring(StrBuf *Target, WCTemplputParams *TP)
00886 {
00887        StrBufAppendBufPlain(Target, 
00888                           HKEY(PACKAGE_STRING), 0);
00889 }
00890 
00891 extern char static_local_dir[PATH_MAX];
00892 
00893 
00894 void 
00895 InitModule_WEBCIT
00896 (void)
00897 {
00898        char dir[SIZ];
00899        WebcitAddUrlHandler(HKEY("blank"), "", 0, blank_page, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
00900        WebcitAddUrlHandler(HKEY("landing"), "", 0, display_default_landing_page, ANONYMOUS|COOKIEUNNEEDED);
00901        WebcitAddUrlHandler(HKEY("do_template"), "", 0, url_do_template, ANONYMOUS);
00902        WebcitAddUrlHandler(HKEY("sslg"), "", 0, seconds_since_last_gexp, AJAX|LOGCHATTY);
00903        WebcitAddUrlHandler(HKEY("ajax_servcmd"), "", 0, ajax_servcmd, 0);
00904        WebcitAddUrlHandler(HKEY("webcit"), "", 0, blank_page, URLNAMESPACE);
00905        WebcitAddUrlHandler(HKEY("push"), "", 0, push_destination, AJAX);
00906        WebcitAddUrlHandler(HKEY("pop"), "", 0, pop_destination, 0);
00907 
00908        WebcitAddUrlHandler(HKEY("401"), "", 0, authorization_required, ANONYMOUS|COOKIEUNNEEDED);
00909        RegisterConditional(HKEY("COND:IMPMSG"), 0, ConditionalImportantMesage, CTX_NONE);
00910        RegisterConditional(HKEY("COND:REST:DEPTH"), 0, Conditional_REST_DEPTH, CTX_NONE);
00911        RegisterConditional(HKEY("COND:IS_HTTPS"), 0, Conditional_IS_HTTPS, CTX_NONE);
00912 
00913        RegisterNamespace("CSSLOCAL", 0, 0, tmplput_csslocal, NULL, CTX_NONE);
00914        RegisterNamespace("IMPORTANTMESSAGE", 0, 0, tmplput_importantmessage, NULL, CTX_NONE);
00915        RegisterNamespace("TRAILING_JAVASCRIPT", 0, 0, tmplput_trailing_javascript, NULL, CTX_NONE);
00916        RegisterNamespace("URL:DISPLAYNAME", 0, 1, tmplput_HANDLER_DISPLAYNAME, NULL, CTX_NONE);
00917        RegisterNamespace("PACKAGESTRING", 0, 1, tmplput_packagestring, NULL, CTX_NONE);
00918 
00919        
00920        snprintf(dir, SIZ, "%s/webcit.css", static_local_dir);
00921        if (!access(dir, R_OK)) {
00922               syslog(9, "Using local Stylesheet [%s]", dir);
00923               csslocal = NewStrBufPlain(HKEY("<link href=\"static.local/webcit.css\" rel=\"stylesheet\" type=\"text/css\" />"));
00924        }
00925        else
00926               syslog(9, "No Site-local Stylesheet [%s] installed.", dir);
00927 
00928 }
00929 
00930 void
00931 ServerStartModule_WEBCIT
00932 (void)
00933 {
00934        HandlerHash = NewHash(1, NULL);
00935 }
00936 
00937 
00938 void 
00939 ServerShutdownModule_WEBCIT
00940 (void)
00941 {
00942        FreeStrBuf(&csslocal);
00943        DeleteHash(&HandlerHash);
00944 }
00945 
00946 
00947 
00948 void
00949 SessionNewModule_WEBCIT
00950 (wcsession *sess)
00951 {
00952        sess->ImportantMsg = NewStrBuf();
00953        sess->WBuf = NewStrBufPlain(NULL, SIZ * 4);
00954        sess->HBuf = NewStrBufPlain(NULL, SIZ / 4);
00955 }
00956 
00957 void
00958 SessionDetachModule_WEBCIT
00959 (wcsession *sess)
00960 {
00961        DeleteHash(&sess->Directory);
00962 
00963        FreeStrBuf(&sess->upload);
00964        sess->upload_length = 0;
00965        
00966        FreeStrBuf(&sess->trailing_javascript);
00967 
00968        if (StrLength(sess->WBuf) > SIZ * 30) /* Bigger than 120K? release. */
00969        {
00970               FreeStrBuf(&sess->WBuf);
00971               sess->WBuf = NewStrBuf();
00972        }
00973        else
00974               FlushStrBuf(sess->WBuf);
00975        FlushStrBuf(sess->HBuf);
00976 }
00977 
00978 void 
00979 SessionDestroyModule_WEBCIT
00980 (wcsession *sess)
00981 {
00982        FreeStrBuf(&sess->WBuf);
00983        FreeStrBuf(&sess->HBuf);
00984        FreeStrBuf(&sess->ImportantMsg);
00985        FreeStrBuf(&sess->PushedDestination);
00986 }
00987