* New parameter to CtdlSaveMsgPointersInRoom() to suppress the reference count adjust...
[citadel.git] / citadel / modules / imap / imap_misc.c
index 9b15e4208af09f8f4f80752149fc6ff5919073c5..dbd224ff705a73d125616ed6621660ee19fe1ed8 100644 (file)
@@ -1,7 +1,21 @@
 /*
  * $Id$
  *
+ * Copyright (c) 1987-2010 by the citadel.org team
  *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 
 #include "citserver.h"
 #include "support.h"
 #include "config.h"
-#include "room_ops.h"
 #include "user_ops.h"
 #include "policy.h"
 #include "database.h"
 #include "msgbase.h"
 #include "internet_addressing.h"
-#include "serv_imap.h"
 #include "imap_tools.h"
+#include "serv_imap.h"
 #include "imap_fetch.h"
 #include "imap_misc.h"
 #include "genstamp.h"
@@ -58,7 +71,7 @@
  * imap_copy() calls imap_do_copy() to do its actual work, once it's
  * validated and boiled down the request a bit.  (returns 0 on success)
  */
-int imap_do_copy(char *destination_folder) {
+int imap_do_copy(const char *destination_folder) {
        int i;
        char roomname[ROOMNAMELEN];
        struct ctdlroom qrbuf;
@@ -69,7 +82,7 @@ int imap_do_copy(char *destination_folder) {
                return(0);
        }
 
-       i = imap_grabroom(roomname, destination_folder, 0);
+       i = imap_grabroom(roomname, destination_folder, 1);
        if (i != 0) return(i);
 
        /*
@@ -85,7 +98,7 @@ int imap_do_copy(char *destination_folder) {
        }
 
        if (num_selected > 0) {
-               CtdlCopyMsgsToRoom(selected_msgs, num_selected, roomname);
+               CtdlSaveMsgPointersInRoom(roomname, selected_msgs, num_selected, 1, NULL, 0);
        }
        free(selected_msgs);
 
@@ -127,7 +140,7 @@ int imap_do_copy(char *destination_folder) {
        }
 
        /* Set the flags... */
-       i = getroom(&qrbuf, roomname);
+       i = CtdlGetRoom(&qrbuf, roomname);
        if (i == 0) {
                CtdlSetSeen(seen_yes, num_seen_yes, 1, ctdlsetseen_seen, NULL, &qrbuf);
                CtdlSetSeen(seen_no, num_seen_no, 0, ctdlsetseen_seen, NULL, &qrbuf);
@@ -177,130 +190,59 @@ void imap_output_copyuid_response(void) {
 /*
  * This function is called by the main command loop.
  */
-void imap_copy(int num_parms, char *parms[]) {
+void imap_copy(int num_parms, ConstStr *Params) {
        int ret;
 
        if (num_parms != 4) {
-               cprintf("%s BAD invalid parameters\r\n", parms[0]);
+               cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
                return;
        }
 
-       if (imap_is_message_set(parms[2])) {
-               imap_pick_range(parms[2], 0);
+       if (imap_is_message_set(Params[2].Key)) {
+               imap_pick_range(Params[2].Key, 0);
        }
        else {
-               cprintf("%s BAD invalid parameters\r\n", parms[0]);
+               cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
                return;
        }
 
-       ret = imap_do_copy(parms[3]);
+       ret = imap_do_copy(Params[3].Key);
        if (!ret) {
-               cprintf("%s OK ", parms[0]);
+               cprintf("%s OK ", Params[0].Key);
                imap_output_copyuid_response();
                cprintf("COPY completed\r\n");
        }
        else {
-               cprintf("%s NO COPY failed (error %d)\r\n", parms[0], ret);
+               cprintf("%s NO COPY failed (error %d)\r\n", Params[0].Key, ret);
        }
 }
 
 /*
  * This function is called by the main command loop.
  */
-void imap_uidcopy(int num_parms, char *parms[]) {
+void imap_uidcopy(int num_parms, ConstStr *Params) {
 
        if (num_parms != 5) {
-               cprintf("%s BAD invalid parameters\r\n", parms[0]);
+               cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
                return;
        }
 
-       if (imap_is_message_set(parms[3])) {
-               imap_pick_range(parms[3], 1);
+       if (imap_is_message_set(Params[3].Key)) {
+               imap_pick_range(Params[3].Key, 1);
        }
        else {
-               cprintf("%s BAD invalid parameters\r\n", parms[0]);
+               cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
                return;
        }
 
-       if (imap_do_copy(parms[4]) == 0) {
-               cprintf("%s OK ", parms[0]);
+       if (imap_do_copy(Params[4].Key) == 0) {
+               cprintf("%s OK ", Params[0].Key);
                imap_output_copyuid_response();
                cprintf("UID COPY completed\r\n");
        }
        else {
-               cprintf("%s NO UID COPY failed\r\n", parms[0]);
-       }
-}
-
-
-/*
- * Poll for instant messages (yeah, we can do this in IMAP ... I think)
- */
-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;
-
-       if (CC->FirstExpressMessage == NULL) {
-               return;
-       }
-       begin_critical_section(S_SESSION_TABLE);
-       ptr = CC->FirstExpressMessage;
-       CC->FirstExpressMessage = NULL;
-       end_critical_section(S_SESSION_TABLE);
-
-       while (ptr != NULL) {
-               localtime_r(&(ptr->timestamp), &stamp);
-               size = strlen(ptr->text) + SIZ;
-               dumpomatic = malloc(size);
-               strcpy(dumpomatic, "");
-               if (ptr->flags && EM_BROADCAST)
-                       strcat(dumpomatic, "Broadcast message ");
-               else if (ptr->flags && EM_CHAT)
-                       strcat(dumpomatic, "Chat request ");
-               else if (ptr->flags && EM_GO_AWAY)
-                       strcat(dumpomatic, "Please logoff now, as requested ");
-               else
-                       strcat(dumpomatic, "Message ");
-
-               /* Timestamp.  Can this be improved? */
-               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 */
-                       sprintf(tmp, "at %d:%02dpm",
-                               stamp.tm_hour - 12,
-                               stamp.tm_min);
-               else                                    /* am */
-                       sprintf(tmp, "at %d:%02dam",
-                               stamp.tm_hour, stamp.tm_min);
-               strcat(dumpomatic, tmp);
-
-               size2 = strlen(dumpomatic);
-               snprintf(&dumpomatic[size2], size - size2,
-                       " from %s:\n", ptr->sender);
-               if (ptr->text != NULL)
-                       strcat(dumpomatic, ptr->text);
-
-               holdptr = ptr->next;
-               if (ptr->text != NULL) free(ptr->text);
-               free(ptr);
-               ptr = holdptr;
-
-               for (i=0; dumpomatic[i]; ++i) {
-                       if (!isprint(dumpomatic[i])) dumpomatic[i] = ' ';
-                       if (dumpomatic[i]=='\\') dumpomatic[i]='/';
-                       if (dumpomatic[i]=='\"') dumpomatic[i]='\'';
-               }
-
-               cprintf("* OK [ALERT] %s\r\n", dumpomatic);
-               free(dumpomatic);
+               cprintf("%s NO UID COPY failed\r\n", Params[0].Key);
        }
-       cprintf("000\n");
 }
 
 
@@ -338,10 +280,9 @@ void imap_do_append_flags(long new_msgnum, char *new_message_flags) {
 /*
  * This function is called by the main command loop.
  */
-void imap_append(int num_parms, char *parms[]) {
+void imap_append(int num_parms, ConstStr *Params) {
        long literal_length;
        long bytes_transferred;
-       long stripped_length = 0;
        struct CtdlMessage *msg = NULL;
        long new_msgnum = (-1L);
        int ret = 0;
@@ -351,23 +292,23 @@ void imap_append(int num_parms, char *parms[]) {
        int msgs, new;
        int i;
        char new_message_flags[SIZ];
-       struct citimap *Imap;
+       citimap *Imap;
 
        if (num_parms < 4) {
-               cprintf("%s BAD usage error\r\n", parms[0]);
+               cprintf("%s BAD usage error\r\n", Params[0].Key);
                return;
        }
 
-       if ( (parms[num_parms-1][0] != '{')
-          || (parms[num_parms-1][strlen(parms[num_parms-1])-1] != '}') )  {
-               cprintf("%s BAD no message literal supplied\r\n", parms[0]);
+       if ( (Params[num_parms-1].Key[0] != '{')
+          || (Params[num_parms-1].Key[Params[num_parms-1].len-1] != '}') )  {
+               cprintf("%s BAD no message literal supplied\r\n", Params[0].Key);
                return;
        }
 
        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, Params[i].Key);
                        strcat(new_message_flags, " ");
                }
                stripallbut(new_message_flags, '(', ')');
@@ -379,31 +320,30 @@ void imap_append(int num_parms, char *parms[]) {
         * }
         */
 
-       literal_length = atol(&parms[num_parms-1][1]);
+       literal_length = atol(&Params[num_parms-1].Key[1]);
        if (literal_length < 1) {
                cprintf("%s BAD Message length must be at least 1.\r\n",
-                       parms[0]);
+                       Params[0].Key);
                return;
        }
 
        Imap = IMAP;
        imap_free_transmitted_message();        /* just in case. */
-       Imap->transmitted_message = malloc(literal_length + 1);
-       if (Imap->transmitted_message == NULL) {
-               cprintf("%s NO Cannot allocate memory.\r\n", parms[0]);
+
+       Imap->TransmittedMessage = NewStrBufPlain(NULL, literal_length);
+
+       if (Imap->TransmittedMessage == NULL) {
+               cprintf("%s NO Cannot allocate memory.\r\n", Params[0].Key);
                return;
        }
-       Imap->transmitted_length = literal_length;
-
+       
        cprintf("+ Transmit message now.\r\n");
 
        bytes_transferred = 0;
+       client_read_blob(Imap->TransmittedMessage, literal_length, config.c_sleeping);
 
-       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]);
+       if ((ret < 0) || (StrLength(Imap->TransmittedMessage) < literal_length)) {
+               cprintf("%s NO Read failed.\r\n", Params[0].Key);
                return;
        }
 
@@ -415,36 +355,26 @@ void imap_append(int num_parms, char *parms[]) {
 
        /* Convert RFC822 newlines (CRLF) to Unix newlines (LF) */
        CtdlLogPrintf(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)) {
-                       Imap->transmitted_message[stripped_length++] =
-                               Imap->transmitted_message[i];
-               }
-       }
-       literal_length = stripped_length;
-       Imap->transmitted_message[literal_length] = 0;  /* reterminate it */
+       StrBufToUnixLF(Imap->TransmittedMessage);
 
        CtdlLogPrintf(CTDL_DEBUG, "Converting message format\n");
-       msg = convert_internet_message(Imap->transmitted_message);
-       Imap->transmitted_message = NULL;
-       Imap->transmitted_length = 0;
+       msg = convert_internet_message_buf(&Imap->TransmittedMessage);
 
-       ret = imap_grabroom(roomname, parms[2], 0);
+       ret = imap_grabroom(roomname, Params[2].Key, 1);
        if (ret != 0) {
                cprintf("%s NO Invalid mailbox name or access denied\r\n",
-                       parms[0]);
+                       Params[0].Key);
                return;
        }
 
        /*
-        * usergoto() formally takes us to the desired room.  (If another
+        * CtdlUserGoto() formally takes us to the desired room.  (If another
         * folder is selected, save its name so we can return there!!!!!)
         */
        if (Imap->selected) {
                strcpy(savedroom, CC->room.QRname);
        }
-       usergoto(roomname, 0, 0, &msgs, &new);
+       CtdlUserGoto(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?
@@ -471,21 +401,21 @@ void imap_append(int num_parms, char *parms[]) {
 
        if (ret) {
                /* Nope ... print an error message */
-               cprintf("%s NO %s\r\n", parms[0], buf);
+               cprintf("%s NO %s\r\n", Params[0].Key, buf);
        }
 
        else {
                /* Yes ... go ahead and post! */
                if (msg != NULL) {
-                       new_msgnum = CtdlSubmitMsg(msg, NULL, "");
+                       new_msgnum = CtdlSubmitMsg(msg, NULL, "", 0);
                }
                if (new_msgnum >= 0L) {
                        cprintf("%s OK [APPENDUID %ld %ld] APPEND completed\r\n",
-                               parms[0], GLOBAL_UIDVALIDITY_VALUE, new_msgnum);
+                               Params[0].Key, GLOBAL_UIDVALIDITY_VALUE, new_msgnum);
                }
                else {
                        cprintf("%s BAD Error %ld saving message to disk.\r\n",
-                               parms[0], new_msgnum);
+                               Params[0].Key, new_msgnum);
                }
        }
 
@@ -496,7 +426,7 @@ void imap_append(int num_parms, char *parms[]) {
         * our happy day without violent explosions.
         */
        if (Imap->selected) {
-               usergoto(savedroom, 0, 0, &msgs, &new);
+               CtdlUserGoto(savedroom, 0, 0, &msgs, &new);
        }
 
        /* We don't need this buffer anymore */