]> code.citadel.org Git - citadel.git/blobdiff - citadel/imap_misc.c
* Cc: and Bcc: support. Not finished yet.
[citadel.git] / citadel / imap_misc.c
index ab03090b1a068f7d119ef56db28412c87cb4fffd..192f9c833878c9f5d2c596891297a4a74b6c8ea9 100644 (file)
 int imap_do_copy(char *destination_folder) {
        int i;
        char roomname[ROOMNAMELEN];
+       struct ctdlroom qrbuf;
 
-       i = imap_grabroom(roomname, destination_folder);
+       if (IMAP->num_msgs < 1) {
+               return(0);
+       }
+
+       i = imap_grabroom(roomname, destination_folder, 0);
+       if (i != 0) return(i);
+
+       for (i = 0; i < IMAP->num_msgs; ++i) {
+               if (IMAP->flags[i] & IMAP_SELECTED) {
+                       CtdlCopyMsgToRoom(IMAP->msgids[i], roomname);
+               }
+       }
+
+       /* Set the flags... */
+       i = getroom(&qrbuf, roomname);
        if (i != 0) return(i);
 
-       if (IMAP->num_msgs > 0) {
-               for (i = 0; i < IMAP->num_msgs; ++i) {
-                       if (IMAP->flags[i] && IMAP_SELECTED) {
-                               CtdlCopyMsgToRoom(
-                                       IMAP->msgids[i], roomname);
-                       }
+       for (i = 0; i < IMAP->num_msgs; ++i) {
+               if (IMAP->flags[i] & IMAP_SELECTED) {
+                       CtdlSetSeen(IMAP->msgids[i],
+                               ((IMAP->flags[i] & IMAP_SEEN) ? 1 : 0),
+                               ctdlsetseen_seen,
+                               NULL, &qrbuf
+                       );
+                       CtdlSetSeen(IMAP->msgids[i],
+                               ((IMAP->flags[i] & IMAP_ANSWERED) ? 1 : 0),
+                               ctdlsetseen_answered,
+                               NULL, &qrbuf
+                       );
                }
        }
 
@@ -79,6 +100,7 @@ int imap_do_copy(char *destination_folder) {
 }
 
 
+
 /*
  * This function is called by the main command loop.
  */
@@ -135,15 +157,15 @@ void imap_uidcopy(int num_parms, char *parms[]) {
 
 
 /*
- * Poll for express messages (yeah, we can do this in IMAP ... I think)
+ * Poll for instant messages (yeah, we can do this in IMAP ... I think)
  */
-void imap_print_express_messages(void) {
+void imap_print_instant_messages(void) {
        struct ExpressMessage *ptr, *holdptr;
        char *dumpomatic = NULL;
        char tmp[SIZ];
        int i;
        size_t size, size2;
-       struct tm *stamp;
+       struct tm stamp;
 
        if (CC->FirstExpressMessage == NULL) {
                return;
@@ -154,9 +176,9 @@ void imap_print_express_messages(void) {
        end_critical_section(S_SESSION_TABLE);
 
        while (ptr != NULL) {
-               stamp = localtime(&(ptr->timestamp));
+               localtime_r(&(ptr->timestamp), &stamp);
                size = strlen(ptr->text) + SIZ;
-               dumpomatic = mallok(size);
+               dumpomatic = malloc(size);
                strcpy(dumpomatic, "");
                if (ptr->flags && EM_BROADCAST)
                        strcat(dumpomatic, "Broadcast message ");
@@ -168,17 +190,17 @@ void imap_print_express_messages(void) {
                        strcat(dumpomatic, "Message ");
 
                /* Timestamp.  Can this be improved? */
-               if (stamp->tm_hour == 0 || stamp->tm_hour == 12)
+               if (stamp.tm_hour == 0 || stamp.tm_hour == 12)
                        sprintf(tmp, "at 12:%02d%cm",
-                               stamp->tm_min, 
-                               stamp->tm_hour ? 'p' : 'a');
-               else if (stamp->tm_hour > 12)           /* pm */
+                               stamp.tm_min, 
+                               stamp.tm_hour ? 'p' : 'a');
+               else if (stamp.tm_hour > 12)            /* pm */
                        sprintf(tmp, "at %d:%02dpm",
-                               stamp->tm_hour - 12,
-                               stamp->tm_min);
+                               stamp.tm_hour - 12,
+                               stamp.tm_min);
                else                                    /* am */
                        sprintf(tmp, "at %d:%02dam",
-                               stamp->tm_hour, stamp->tm_min);
+                               stamp.tm_hour, stamp.tm_min);
                strcat(dumpomatic, tmp);
 
                size2 = strlen(dumpomatic);
@@ -188,8 +210,8 @@ void imap_print_express_messages(void) {
                        strcat(dumpomatic, ptr->text);
 
                holdptr = ptr->next;
-               if (ptr->text != NULL) phree(ptr->text);
-               phree(ptr);
+               if (ptr->text != NULL) free(ptr->text);
+               free(ptr);
                ptr = holdptr;
 
                for (i=0; i<strlen(dumpomatic); ++i) {
@@ -199,26 +221,59 @@ void imap_print_express_messages(void) {
                }
 
                cprintf("* OK [ALERT] %s\r\n", dumpomatic);
-               phree(dumpomatic);
+               free(dumpomatic);
        }
        cprintf("000\n");
 }
 
 
+/*
+ * imap_do_append_flags() is called by imap_append() to set any flags that
+ * the client specified at append time.
+ *
+ * FIXME find a way to do these in bulk so we don't max out our db journal
+ */
+void imap_do_append_flags(long new_msgnum, char *new_message_flags) {
+       char flags[32];
+       char this_flag[sizeof flags];
+       int i;
+
+       if (new_message_flags == NULL) return;
+       if (strlen(new_message_flags) == 0) return;
+
+       safestrncpy(flags, new_message_flags, sizeof flags);
+
+       for (i=0; i<num_tokens(flags, ' '); ++i) {
+               extract_token(this_flag, flags, i, ' ', sizeof this_flag);
+               if (this_flag[0] == '\\') strcpy(this_flag, &this_flag[1]);
+               if (!strcasecmp(this_flag, "Seen")) {
+                       CtdlSetSeen(new_msgnum, 1, ctdlsetseen_seen,
+                               NULL, NULL);
+               }
+               if (!strcasecmp(this_flag, "Answered")) {
+                       CtdlSetSeen(new_msgnum, 1, ctdlsetseen_answered,
+                               NULL, NULL);
+               }
+       }
+}
+
 
 /*
  * This function is called by the main command loop.
  */
 void imap_append(int num_parms, char *parms[]) {
-       size_t literal_length;
+       long literal_length;
+       long bytes_transferred;
+       long stripped_length = 0;
        struct CtdlMessage *msg;
-       int ret;
+       long new_msgnum = (-1L);
+       int ret = 0;
        char roomname[ROOMNAMELEN];
        char buf[SIZ];
        char savedroom[ROOMNAMELEN];
        int msgs, new;
        int i;
-
+       char new_message_flags[SIZ];
 
        if (num_parms < 4) {
                cprintf("%s BAD usage error\r\n", parms[0]);
@@ -231,7 +286,22 @@ void imap_append(int num_parms, char *parms[]) {
                return;
        }
 
-       literal_length = (size_t) atol(&parms[num_parms-1][1]);
+       strcpy(new_message_flags, "");
+       if (num_parms >= 5) {
+               for (i=3; i<num_parms; ++i) {
+                       strcat(new_message_flags, parms[i]);
+                       strcat(new_message_flags, " ");
+               }
+               stripallbut(new_message_flags, '(', ')');
+       }
+
+       /* This is how we'd do this if it were relevant in our data store.
+        * if (num_parms >= 6) {
+        *  new_message_internaldate = parms[4];
+        * }
+        */
+
+       literal_length = atol(&parms[num_parms-1][1]);
        if (literal_length < 1) {
                cprintf("%s BAD Message length must be at least 1.\r\n",
                        parms[0]);
@@ -239,7 +309,7 @@ void imap_append(int num_parms, char *parms[]) {
        }
 
        imap_free_transmitted_message();        /* just in case. */
-       IMAP->transmitted_message = mallok(literal_length + 1);
+       IMAP->transmitted_message = malloc(literal_length + 1);
        if (IMAP->transmitted_message == NULL) {
                cprintf("%s NO Cannot allocate memory.\r\n", parms[0]);
                return;
@@ -247,31 +317,43 @@ void imap_append(int num_parms, char *parms[]) {
        IMAP->transmitted_length = literal_length;
 
        cprintf("+ Transmit message now.\r\n");
+
+       bytes_transferred = 0;
+
        ret = client_read(IMAP->transmitted_message, literal_length);
        IMAP->transmitted_message[literal_length] = 0;
+
        if (ret != 1) {
                cprintf("%s NO Read failed.\r\n", parms[0]);
                return;
        }
 
+       /* Client will transmit a trailing CRLF after the literal (the message
+        * text) is received.  This call to client_getln() absorbs it.
+        */
+       flush_output();
+       client_getln(buf, sizeof buf);
+
        /* Convert RFC822 newlines (CRLF) to Unix newlines (LF) */
-       lprintf(9, "Converting newline format\n");
+       lprintf(CTDL_DEBUG, "Converting CRLF to LF\n");
+       stripped_length = 0;
        for (i=0; i<literal_length; ++i) {
-               if (!strncmp(&IMAP->transmitted_message[i], "\r\n", 2)) {
-                       strcpy(&IMAP->transmitted_message[i],
-                               &IMAP->transmitted_message[i+1]);
-                       --literal_length;
+               if (strncmp(&IMAP->transmitted_message[i], "\r\n", 2)) {
+                       IMAP->transmitted_message[stripped_length++] =
+                               IMAP->transmitted_message[i];
                }
        }
+       literal_length = stripped_length;
+       IMAP->transmitted_message[literal_length] = 0;  /* reterminate it */
 
-       lprintf(9, "Converting message format\n");
-        msg = convert_internet_message(IMAP->transmitted_message);
+       lprintf(CTDL_DEBUG, "Converting message format\n");
+       msg = convert_internet_message(IMAP->transmitted_message);
        IMAP->transmitted_message = NULL;
        IMAP->transmitted_length = 0;
 
-       ret = imap_grabroom(roomname, parms[2]);
+       ret = imap_grabroom(roomname, parms[2], 0);
        if (ret != 0) {
-               cprintf("%s NO Invalid mailbox name or location, or access denied\r\n",
+               cprintf("%s NO Invalid mailbox name or access denied\r\n",
                        parms[0]);
                return;
        }
@@ -281,27 +363,27 @@ void imap_append(int num_parms, char *parms[]) {
         * folder is selected, save its name so we can return there!!!!!)
         */
        if (IMAP->selected) {
-               strcpy(savedroom, CC->quickroom.QRname);
+               strcpy(savedroom, CC->room.QRname);
        }
        usergoto(roomname, 0, 0, &msgs, &new);
 
-        /* If the user is locally authenticated, FORCE the From: header to
-         * show up as the real sender.  FIXME do we really want to do this?
+       /* If the user is locally authenticated, FORCE the From: header to
+        * show up as the real sender.  FIXME do we really want to do this?
         * Probably should make it site-definable or even room-definable.
         *
         * For now, we allow "forgeries" if the room is one of the user's
         * private mailboxes.
-         */
-        if (CC->logged_in) {
-          if ( (CC->quickroom.QRflags & QR_MAILBOX) == 0) {
-                if (msg->cm_fields['A'] != NULL) phree(msg->cm_fields['A']);
-                if (msg->cm_fields['N'] != NULL) phree(msg->cm_fields['N']);
-                if (msg->cm_fields['H'] != NULL) phree(msg->cm_fields['H']);
-                msg->cm_fields['A'] = strdoop(CC->usersupp.fullname);
-                msg->cm_fields['N'] = strdoop(config.c_nodename);
-                msg->cm_fields['H'] = strdoop(config.c_humannode);
+        */
+       if (CC->logged_in) {
+          if ( (CC->room.QRflags & QR_MAILBOX) == 0) {
+               if (msg->cm_fields['A'] != NULL) free(msg->cm_fields['A']);
+               if (msg->cm_fields['N'] != NULL) free(msg->cm_fields['N']);
+               if (msg->cm_fields['H'] != NULL) free(msg->cm_fields['H']);
+               msg->cm_fields['A'] = strdup(CC->user.fullname);
+               msg->cm_fields['N'] = strdup(config.c_nodename);
+               msg->cm_fields['H'] = strdup(config.c_humannode);
            }
-        }
+       }
 
        /* 
         * Can we post here?
@@ -316,9 +398,15 @@ void imap_append(int num_parms, char *parms[]) {
        else {
                /* Yes ... go ahead and post! */
                if (msg != NULL) {
-                       CtdlSubmitMsg(msg, NULL, "");
+                       new_msgnum = CtdlSubmitMsg(msg, NULL, NULL, NULL, "");
+               }
+               if (new_msgnum >= 0L) {
+                       cprintf("%s OK APPEND completed\r\n", parms[0]);
+               }
+               else {
+                       cprintf("%s BAD Error %ld saving message to disk.\r\n",
+                               parms[0], new_msgnum);
                }
-               cprintf("%s OK APPEND completed\r\n", parms[0]);
        }
 
        /*
@@ -333,4 +421,8 @@ void imap_append(int num_parms, char *parms[]) {
 
        /* We don't need this buffer anymore */
        CtdlFreeMessage(msg);
+
+       if (new_message_flags != NULL) {
+               imap_do_append_flags(new_msgnum, new_message_flags);
+       }
 }