Back to index

webcit  8.12-dfsg
notes.c
Go to the documentation of this file.
00001 
00002 #include "webcit.h"
00003 #include "dav.h"
00004 #include "webserver.h"
00005 
00006 int pastel_palette[9][3] = {
00007        { 0x80, 0x80, 0x80 },
00008        { 0xff, 0x80, 0x80 },
00009        { 0x80, 0x80, 0xff },
00010        { 0xff, 0xff, 0x80 },
00011        { 0x80, 0xff, 0x80 },
00012        { 0xff, 0x80, 0xff },
00013        { 0x80, 0xff, 0xff },
00014        { 0xff, 0x80, 0x80 },
00015        { 0x80, 0x80, 0x80 }
00016 };
00017 
00018 
00019 /*
00020  * Fetch a message from the server and extract a vNote from it
00021  */
00022 struct vnote *vnote_new_from_msg(long msgnum,int unread) 
00023 {
00024        StrBuf *Buf;
00025        StrBuf *Data = NULL;
00026        const char *bptr;
00027        int Done = 0;
00028        char uid_from_headers[256];
00029        char mime_partnum[256];
00030        char mime_filename[256];
00031        char mime_content_type[256];
00032        char mime_disposition[256];
00033        char relevant_partnum[256];
00034        int phase = 0;                            /* 0 = citadel headers, 1 = mime headers, 2 = body */
00035        char msg4_content_type[256] = "";
00036        char msg4_content_encoding[256] = "";
00037        int msg4_content_length = 0;
00038        struct vnote *vnote_from_body = NULL;
00039        int vnote_inline = 0;                     /* 1 = MSG4 gave us a text/x-vnote top level */
00040 
00041        relevant_partnum[0] = '\0';
00042        serv_printf("MSG4 %ld", msgnum);   /* we need the mime headers */
00043        Buf = NewStrBuf();
00044        StrBuf_ServGetln(Buf);
00045        if (GetServerStatus(Buf, NULL) != 1) {
00046               FreeStrBuf (&Buf);
00047               return NULL;
00048        }
00049        while ((StrBuf_ServGetln(Buf)>=0) && !Done) {
00050               if ( (StrLength(Buf)==3) && 
00051                    !strcmp(ChrPtr(Buf), "000")) {
00052                      Done = 1;
00053                      break;
00054               }
00055               bptr = ChrPtr(Buf);
00056               switch (phase) {
00057               case 0:
00058                      if (!strncasecmp(bptr, "exti=", 5)) {
00059                             safestrncpy(uid_from_headers, &(ChrPtr(Buf)[5]), sizeof uid_from_headers);
00060                      }
00061                      else if (!strncasecmp(bptr, "part=", 5)) {
00062                             extract_token(mime_filename, &bptr[5], 1, '|', sizeof mime_filename);
00063                             extract_token(mime_partnum, &bptr[5], 2, '|', sizeof mime_partnum);
00064                             extract_token(mime_disposition, &bptr[5], 3, '|', sizeof mime_disposition);
00065                             extract_token(mime_content_type, &bptr[5], 4, '|', sizeof mime_content_type);
00066 
00067                             if (!strcasecmp(mime_content_type, "text/vnote")) {
00068                                    strcpy(relevant_partnum, mime_partnum);
00069                             }
00070                      }
00071                      else if ((phase == 0) && (!strncasecmp(bptr, "text", 4))) {
00072                             phase = 1;
00073                      }
00074               break;
00075               case 1:
00076                      if (!IsEmptyStr(bptr)) {
00077                             if (!strncasecmp(bptr, "Content-type: ", 14)) {
00078                                    safestrncpy(msg4_content_type, &bptr[14], sizeof msg4_content_type);
00079                                    striplt(msg4_content_type);
00080                             }
00081                             else if (!strncasecmp(bptr, "Content-transfer-encoding: ", 27)) {
00082                                    safestrncpy(msg4_content_encoding, &bptr[27], sizeof msg4_content_encoding);
00083                                    striplt(msg4_content_type);
00084                             }
00085                             else if ((!strncasecmp(bptr, "Content-length: ", 16))) {
00086                                    msg4_content_length = atoi(&bptr[16]);
00087                             }
00088                             break;
00089                      }
00090                      else {
00091                             phase++;
00092                             if ((msg4_content_length > 0)
00093                                 && ( !strcasecmp(msg4_content_encoding, "7bit"))
00094                                 && (!strcasecmp(msg4_content_type, "text/vnote"))
00095                             ) { 
00096                                    vnote_inline = 1;
00097                             }
00098                      }
00099               case 2:
00100                      if (vnote_inline) {
00101                             Data = NewStrBufPlain(NULL, msg4_content_length * 2);
00102                             if (msg4_content_length > 0) {
00103                                    StrBuf_ServGetBLOBBuffered(Data, msg4_content_length);
00104                                    phase ++;
00105                             }
00106                             else {
00107                                    StrBufAppendBuf(Data, Buf, 0);
00108                                    StrBufAppendBufPlain(Data, "\r\n", 1, 0);
00109                             }
00110                      }
00111               case 3:
00112                      if (vnote_inline) {
00113                             StrBufAppendBuf(Data, Buf, 0);
00114                      }
00115               }
00116        }
00117        FreeStrBuf(&Buf);
00118 
00119        /* If MSG4 didn't give us the part we wanted, but we know that we can find it
00120         * as one of the other MIME parts, attempt to load it now.
00121         */
00122        if ((!vnote_inline) && (!IsEmptyStr(relevant_partnum))) {
00123               Data = load_mimepart(msgnum, relevant_partnum);
00124        }
00125 
00126        if (StrLength(Data) > 0) {
00127               if (IsEmptyStr(uid_from_headers)) {
00128                      /* Convert an old-style note to a vNote */
00129                      vnote_from_body = vnote_new();
00130                      vnote_from_body->uid = strdup(uid_from_headers);
00131                      vnote_from_body->color_red = pastel_palette[3][0];
00132                      vnote_from_body->color_green = pastel_palette[3][1];
00133                      vnote_from_body->color_blue = pastel_palette[3][2];
00134                      vnote_from_body->body = malloc(StrLength(Data) + 1);
00135                      vnote_from_body->body[0] = 0;
00136                      memcpy(vnote_from_body->body, ChrPtr(Data), StrLength(Data) + 1);
00137                      FreeStrBuf(&Data);
00138                      return vnote_from_body;
00139               }
00140               else {
00141                      char *Buf = SmashStrBuf(&Data);
00142                      
00143                      struct vnote *v = vnote_new_from_str(Buf);
00144                      free(Buf);
00145                      return(v);
00146               }
00147        }
00148        return NULL;
00149 }
00150 
00151 
00152 
00153 /*
00154  * Serialize a vnote and write it to the server
00155  */
00156 void write_vnote_to_server(struct vnote *v) 
00157 {
00158        char buf[1024];
00159        char *pch;
00160        char boundary[256];
00161        static int seq = 0;
00162 
00163        snprintf(boundary, sizeof boundary, "Citadel--Multipart--%s--%04x--%04x",
00164               ChrPtr(WC->serv_info->serv_fqdn),
00165               getpid(),
00166               ++seq
00167        );
00168 
00169        serv_puts("ENT0 1|||4");
00170        serv_getln(buf, sizeof buf);
00171        if (buf[0] == '4') {
00172               /* Remember, serv_printf() appends an extra newline */
00173               serv_printf("Content-type: multipart/alternative; "
00174                      "boundary=\"%s\"\n", boundary);
00175               serv_printf("This is a multipart message in MIME format.\n");
00176               serv_printf("--%s", boundary);
00177        
00178               serv_puts("Content-type: text/plain; charset=utf-8");
00179               serv_puts("Content-Transfer-Encoding: 7bit");
00180               serv_puts("");
00181               serv_puts(v->body);
00182               serv_puts("");
00183        
00184               serv_printf("--%s", boundary);
00185               serv_puts("Content-type: text/vnote");
00186               serv_puts("Content-Transfer-Encoding: 7bit");
00187               serv_puts("");
00188               pch = vnote_serialize(v);
00189               serv_puts(pch);
00190               free(pch);
00191               serv_printf("--%s--", boundary);
00192               serv_puts("000");
00193        }
00194 }
00195 
00196 
00197 
00198 
00199 /*
00200  * Background ajax call to receive updates from the browser when a note is moved, resized, or updated.
00201  */
00202 void ajax_update_note(void) {
00203 
00204        char buf[1024];
00205        int msgnum;
00206        struct vnote *v = NULL;
00207 
00208         if (!havebstr("note_uid")) {
00209               begin_ajax_response();
00210               wc_printf("Received ajax_update_note() request without a note UID.");
00211               end_ajax_response();
00212               return;
00213        }
00214 
00215        serv_printf("EUID %s", bstr("note_uid"));
00216        serv_getln(buf, sizeof buf);
00217        if (buf[0] != '2') {
00218               begin_ajax_response();
00219               wc_printf("Cannot find message containing vNote with the requested uid!");
00220               end_ajax_response();
00221               return;
00222        }
00223        msgnum = atol(&buf[4]);
00224        
00225        /* Was this request a delete operation?  If so, nuke it... */
00226        if (havebstr("deletenote")) {
00227               if (!strcasecmp(bstr("deletenote"), "yes")) {
00228                      serv_printf("DELE %d", msgnum);
00229                      serv_getln(buf, sizeof buf);
00230                      begin_ajax_response();
00231                      wc_printf("%s", buf);
00232                      end_ajax_response();
00233                      return;
00234               }
00235        }
00236 
00237        /* If we get to this point it's an update, not a delete */
00238        v = vnote_new_from_msg(msgnum, 0);
00239        if (!v) {
00240               begin_ajax_response();
00241               wc_printf("Cannot locate a vNote within message %d\n", msgnum);
00242               end_ajax_response();
00243               return;
00244        }
00245 
00246        /* Make any requested changes */
00247         if (havebstr("top")) {
00248               v->pos_top = atoi(bstr("top"));
00249        }
00250         if (havebstr("left")) {
00251               v->pos_left = atoi(bstr("left"));
00252        }
00253         if (havebstr("height")) {
00254               v->pos_height = atoi(bstr("height"));
00255        }
00256         if (havebstr("width")) {
00257               v->pos_width = atoi(bstr("width"));
00258        }
00259         if (havebstr("red")) {
00260               v->color_red = atoi(bstr("red"));
00261        }
00262         if (havebstr("green")) {
00263               v->color_green = atoi(bstr("green"));
00264        }
00265         if (havebstr("blue")) {
00266               v->color_blue = atoi(bstr("blue"));
00267        }
00268         if (havebstr("value")) {   /* I would have preferred 'body' but InPlaceEditor hardcodes 'value' */
00269               if (v->body) free(v->body);
00270               v->body = strdup(bstr("value"));
00271        }
00272 
00273        /* Serialize it and save it to the message base.  Server will delete the old one. */
00274        write_vnote_to_server(v);
00275 
00276        begin_ajax_response();
00277        if (v->body) {
00278               escputs(v->body);
00279        }
00280        end_ajax_response();
00281 
00282        vnote_free(v);
00283 }
00284 
00285 
00286 
00287 
00288 /*
00289  * display sticky notes
00290  *
00291  * msgnum = Message number on the local server of the note to be displayed
00292  */
00293 /*TODO: wrong hook */
00294 int notes_LoadMsgFromServer(SharedMessageStatus *Stat, 
00295                          void **ViewSpecific, 
00296                          message_summary* Msg, 
00297                          int is_new, 
00298                          int i)
00299 {
00300        struct vnote *v;
00301        WCTemplputParams TP;
00302 
00303        memset(&TP, 0, sizeof(WCTemplputParams));
00304        TP.Filter.ContextType = CTX_VNOTE;
00305        v = vnote_new_from_msg(Msg->msgnum, is_new);
00306        if (v) {
00307               TP.Context = v;
00308               DoTemplate(HKEY("vnoteitem"),
00309                         WC->WBuf, &TP);
00310                      
00311 
00312               /* uncomment these lines to see ugly debugging info 
00313               StrBufAppendPrintf(WC->trailing_javascript,
00314                      "document.write('L: ' + $('note-%s').style.left + '; ');", v->uid);
00315               StrBufAppendPrintf(WC->trailing_javascript,
00316                      "document.write('T: ' + $('note-%s').style.top + '; ');", v->uid);
00317               StrBufAppendPrintf(WC->trailing_javascript,
00318                      "document.write('W: ' + $('note-%s').style.width + '; ');", v->uid);
00319               StrBufAppendPrintf(WC->trailing_javascript,
00320                      "document.write('H: ' + $('note-%s').style.height + '<br>');", v->uid);
00321               */
00322 
00323               vnote_free(v);
00324        }
00325        return 0;
00326 }
00327 
00328 
00329 
00330 /*
00331  * Create a new note
00332  */
00333 void add_new_note(void) {
00334        struct vnote *v;
00335 
00336        v = vnote_new();
00337        if (v) {
00338               v->uid = malloc(128);
00339               generate_uuid(v->uid);
00340               v->color_red = pastel_palette[3][0];
00341               v->color_green = pastel_palette[3][1];
00342               v->color_blue = pastel_palette[3][2];
00343               v->body = strdup(_("Click on any note to edit it."));
00344               write_vnote_to_server(v);
00345               vnote_free(v);
00346        }
00347        
00348        readloop(readfwd, eUseDefault);
00349 }
00350 
00351 
00352 void tmpl_vcard_put_posleft(StrBuf *Target, WCTemplputParams *TP)
00353 {
00354        struct vnote *v = (struct vnote *) CTX;
00355        StrBufAppendPrintf(Target, "%d", v->pos_left);
00356 }
00357 
00358 void tmpl_vcard_put_postop(StrBuf *Target, WCTemplputParams *TP)
00359 {
00360        struct vnote *v = (struct vnote *) CTX;
00361        StrBufAppendPrintf(Target, "%d", v->pos_top);
00362 }
00363 
00364 void tmpl_vcard_put_poswidth(StrBuf *Target, WCTemplputParams *TP)
00365 {
00366        struct vnote *v = (struct vnote *) CTX;
00367        StrBufAppendPrintf(Target, "%d", v->pos_width);
00368 }
00369 
00370 void tmpl_vcard_put_posheight(StrBuf *Target, WCTemplputParams *TP)
00371 {
00372        struct vnote *v = (struct vnote *) CTX;
00373        StrBufAppendPrintf(Target, "%d", v->pos_height);
00374 }
00375 
00376 void tmpl_vcard_put_posheight2(StrBuf *Target, WCTemplputParams *TP)
00377 {
00378        struct vnote *v = (struct vnote *) CTX;
00379        StrBufAppendPrintf(Target, "%d", (v->pos_height / 16) - 5);
00380 }
00381 
00382 void tmpl_vcard_put_width2(StrBuf *Target, WCTemplputParams *TP)
00383 {
00384        struct vnote *v = (struct vnote *) CTX;
00385        StrBufAppendPrintf(Target, "%d", (v->pos_width / 9) - 1);
00386 }
00387 
00388 void tmpl_vcard_put_color(StrBuf *Target, WCTemplputParams *TP)
00389 {
00390        struct vnote *v = (struct vnote *) CTX;
00391        StrBufAppendPrintf(Target, "%02X%02X%02X", v->color_red, v->color_green, v->color_blue);
00392 }
00393 
00394 void tmpl_vcard_put_bgcolor(StrBuf *Target, WCTemplputParams *TP)
00395 {
00396        struct vnote *v = (struct vnote *) CTX;
00397        StrBufAppendPrintf(Target, "%02X%02X%02X", v->color_red/2, v->color_green/2, v->color_blue/2);
00398 }
00399 
00400 void tmpl_vcard_put_message(StrBuf *Target, WCTemplputParams *TP)
00401 {
00402        struct vnote *v = (struct vnote *) CTX;
00403        StrEscAppend(Target, NULL, v->body, 0, 0); /*TODO?*/
00404 }
00405 
00406 void tmpl_vcard_put_uid(StrBuf *Target, WCTemplputParams *TP)
00407 {
00408        struct vnote *v = (struct vnote *) CTX;
00409        StrBufAppendBufPlain(Target, v->uid, -1, 0);
00410 }
00411 
00412 
00413 
00414 
00415 int notes_GetParamsGetServerCall(SharedMessageStatus *Stat, 
00416                              void **ViewSpecific, 
00417                              long oper, 
00418                              char *cmd, 
00419                              long len,
00420                              char *filter,
00421                              long flen)
00422 {
00423        strcpy(cmd, "MSGS ALL");
00424        Stat->maxmsgs = 32767;
00425        wc_printf("<div id=\"new_notes_here\"></div>\n");
00426        return 200;
00427 
00428 }
00429 
00430 int notes_Cleanup(void **ViewSpecific)
00431 {
00432        wDumpContent(1);
00433        return 0;
00434 }
00435 
00436 
00437 void 
00438 InitModule_NOTES
00439 (void)
00440 {
00441        RegisterReadLoopHandlerset(
00442               VIEW_NOTES,
00443               notes_GetParamsGetServerCall,
00444               NULL,
00445               NULL,
00446               NULL,
00447               notes_LoadMsgFromServer,
00448               NULL,
00449               notes_Cleanup);
00450 
00451        WebcitAddUrlHandler(HKEY("add_new_note"), "", 0, add_new_note, 0);
00452        WebcitAddUrlHandler(HKEY("ajax_update_note"), "", 0, ajax_update_note, 0);
00453 
00454        RegisterNamespace("VNOTE:POS:LEFT", 0, 0, tmpl_vcard_put_posleft, NULL, CTX_VNOTE);
00455        RegisterNamespace("VNOTE:POS:TOP", 0, 0, tmpl_vcard_put_postop, NULL, CTX_VNOTE);
00456        RegisterNamespace("VNOTE:POS:WIDTH", 0, 0, tmpl_vcard_put_poswidth, NULL, CTX_VNOTE);
00457        RegisterNamespace("VNOTE:POS:HEIGHT", 0, 0, tmpl_vcard_put_posheight, NULL, CTX_VNOTE);
00458        RegisterNamespace("VNOTE:POS:HEIGHT2", 0, 0, tmpl_vcard_put_posheight2, NULL, CTX_VNOTE);
00459        RegisterNamespace("VNOTE:POS:WIDTH2", 0, 0, tmpl_vcard_put_width2, NULL, CTX_VNOTE);
00460        RegisterNamespace("VNOTE:COLOR", 0, 0, tmpl_vcard_put_color, NULL, CTX_VNOTE);
00461        RegisterNamespace("VNOTE:BGCOLOR", 0, 0,tmpl_vcard_put_bgcolor, NULL, CTX_VNOTE);
00462        RegisterNamespace("VNOTE:MSG", 0, 1, tmpl_vcard_put_message, NULL, CTX_VNOTE);
00463        RegisterNamespace("VNOTE:UID", 0, 0, tmpl_vcard_put_uid, NULL, CTX_VNOTE);
00464 }