[Goodies-commits] r5243 - xfce4-mailwatch-plugin/trunk/libmailwatch-core

Brian Tarricone kelnos at xfce.org
Sat Aug 16 10:49:43 CEST 2008


Author: kelnos
Date: 2008-08-16 08:49:43 +0000 (Sat, 16 Aug 2008)
New Revision: 5243

Modified:
   xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-imap.c
Log:
properly receive imap responses, rather than just parsing lines as they come in

this is a lot better, as we now properly handle possible negative response
tokens, and we always wait for some kind of response token to indicate
the end of a command

Modified: xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-imap.c
===================================================================
--- xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-imap.c	2008-08-16 08:49:32 UTC (rev 5242)
+++ xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-mailbox-imap.c	2008-08-16 08:49:43 UTC (rev 5243)
@@ -187,6 +187,67 @@
     return recvd;
 }
 
+static inline gboolean
+imap_response_fatal(const gchar *msg)
+{
+    gchar *p;
+
+    /* here we assume that our tags are always 5 digits long,
+     * plus a space. */
+
+    /* if NO is untagged, the command can still complete */
+    p = strstr(msg, "NO");
+    if(p && p - msg == 6)
+        return TRUE;
+
+    /* BAD can be tagged or untagged, but is always a failure */
+    p = strstr(msg, "BAD");
+    if(p && p - msg <= 6)
+        return TRUE;
+
+    /* BYE as a reasponse to LOGOUT will wait, otherwise will
+     * disconnect at once */
+    p = strstr(msg, "BYE");
+    if(p && p - msg <= 6)
+        return TRUE;
+
+    return FALSE;
+}
+
+static gssize
+imap_recv_command(XfceMailwatchIMAPMailbox *imailbox,
+                  XfceMailwatchNetConn *net_conn,
+                  gchar *buf,
+                  gsize len)
+{
+    gssize bin, tot = 0;
+    gchar *p;
+
+    while(len - tot > 0) {
+        DBG("trying to get line");
+        bin = imap_recv(imailbox, net_conn, buf+tot, len-tot);
+        DBG("got line: %s", bin > 0 ? buf+tot : "(nada)");
+        if(bin <= 0)
+            return -1;
+        if(imap_response_fatal(buf+tot))
+            return -1;
+
+        *(buf+tot+bin) = '\n';
+        ++bin;
+        *(buf+tot+bin) = 0;
+
+        p = strstr(buf+tot, "OK");
+        if(p && p - (buf+tot) <= 6)
+            return tot + bin;
+
+        tot += bin;
+    }
+
+    g_critical("imap_recv_command(): buffer full!");
+
+    return -1;
+}
+
 static gboolean
 imap_send_login_info(XfceMailwatchIMAPMailbox *imailbox,
                      XfceMailwatchNetConn *net_conn,
@@ -205,14 +266,16 @@
     DBG("sent CAPABILITY (%d)", bout);
     if(bout != strlen(buf))
         goto cleanuperr;
-    bin = imap_recv(imailbox, net_conn, buf, BUFSIZE);
+    bin = imap_recv_command(imailbox, net_conn, buf, BUFSIZE);
     DBG("response from CAPABILITY (%d): %s", bin, bin>0?buf:"(nada)");
     if(bin <= 0)
         goto cleanuperr;
     
-    if(strstr(buf, " LOGINDISABLED")) {
-        xfce_textdomain(GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
-        g_warning(_("Secure IMAP is not available, and the IMAP server does not support plaintext logins."));
+    if(strstr(buf, "LOGINDISABLED")) {
+        xfce_mailwatch_log_message(imailbox->mailwatch,
+                                   XFCE_MAILWATCH_MAILBOX(imailbox),
+                                   XFCE_MAILWATCH_LOG_ERROR,
+                                   _("Secure IMAP is not available, and the IMAP server does not support plaintext logins."));
         goto cleanuperr;
     }
     
@@ -254,12 +317,10 @@
             if(bout != strlen(buf))
                 goto cleanuperr;
 
-            bin = imap_recv(imailbox, net_conn, buf, BUFSIZE);
+            bin = imap_recv_command(imailbox, net_conn, buf, BUFSIZE);
             DBG("reponse from cram-md5 resp (%d): %s\n", bin, bin>0?buf:"(nada)");
             if(bin <= 0)
                 goto cleanuperr;
-            if(!strstr(buf, "OK"))
-                goto cleanuperr;
 
             /* auth successful */
             TRACE("leaving (success)");
@@ -268,7 +329,7 @@
     }
 #endif
 
-    /* send the creds */
+    /* no cram-md5 support, send the normal creds */
     g_snprintf(buf, BUFSIZE, "%05d LOGIN \"%s\" \"%s\"\r\n",
                ++imailbox->imap_tag, username, password);
     bout = imap_send(imailbox, net_conn, buf);
@@ -277,13 +338,10 @@
         goto cleanuperr;
     
     /* and see if we actually got auth-ed */
-    bin = imap_recv(imailbox, net_conn, buf, BUFSIZE);
+    bin = imap_recv_command(imailbox, net_conn, buf, BUFSIZE);
     DBG("response from login (%d): %s", bin, bin>0?buf:"(nada)");
     if(bin <= 0)
         goto cleanuperr;
-    DBG("strstr() returns %p", strstr(buf, "OK"));
-    if(!strstr(buf, "OK"))
-        goto cleanuperr;
     
     TRACE("leaving (success)");
     
@@ -304,7 +362,6 @@
     GError *error = NULL;
     
     ret = xfce_mailwatch_net_conn_make_secure(net_conn, &error);
-    
     if(!ret) {
         xfce_mailwatch_log_message(imailbox->mailwatch,
                                    XFCE_MAILWATCH_MAILBOX(imailbox),
@@ -327,7 +384,6 @@
 #define BUFSIZE 8191
     gint bin;
     gchar buf[BUFSIZE+1];
-    gboolean starttls_ok = FALSE;
     
     TRACE("entering");
     
@@ -335,18 +391,12 @@
     if(imap_send(imailbox, net_conn, buf) != strlen(buf))
         return FALSE;
 
-    do {
-        bin = imap_recv(imailbox, net_conn, buf, BUFSIZE);
-        DBG("checking for STARTTLS caps (%d): %s", bin, bin>0?buf:"(nada)");
-        if(bin <= 0)
-            return FALSE;
-        if(bin > 6 && (!strncmp(buf+6, "NO", 2) || !strncmp(buf+6, "BAD", 3)))
-            return FALSE;
-        if(strstr(buf, " STARTTLS"))
-            starttls_ok = TRUE;
-    } while(strncmp(buf+6, "OK", 2));
+    bin = imap_recv_command(imailbox, net_conn, buf, BUFSIZE);
+    DBG("checking for STARTTLS caps (%d): %s", bin, bin>0?buf:"(nada)");
+    if(bin <= 0)
+        return FALSE;
 
-    if(!starttls_ok) {
+    if(!strstr(buf, "STARTTLS")) {
         xfce_mailwatch_log_message(imailbox->mailwatch,
                                    XFCE_MAILWATCH_MAILBOX(imailbox),
                                    XFCE_MAILWATCH_LOG_WARNING,
@@ -358,11 +408,9 @@
     if(imap_send(imailbox, net_conn, buf) != strlen(buf))
         return FALSE;
     
-    if(imap_recv(imailbox, net_conn, buf, BUFSIZE) < 0)
+    if(imap_recv_command(imailbox, net_conn, buf, BUFSIZE) < 0)
         return FALSE;
     DBG("got STARTLS response: %s", bin>0?buf:"(nada)");
-    if(!strstr(buf, " OK"))
-        return FALSE;
     
     return TRUE;
 #undef BUFSIZE
@@ -404,11 +452,10 @@
     gchar buf[2048];
     gint bin;
     
-    bin = imap_recv(imailbox, net_conn, buf, sizeof(buf)-1);
+    bin = imap_recv_command(imailbox, net_conn, buf, sizeof(buf));
     if(bin < 0) {
         DBG("failed to get banner");
     } else {
-        buf[bin] = 0;
         DBG("got banner, discarding: %s\n", buf);
     }
     
@@ -484,32 +531,23 @@
         return 0;
     DBG("  successfully sent cmd '%s'", buf);
     
-    do {
-        /* grab the response */
-        bin = imap_recv(imailbox, net_conn, buf, sizeof(buf)-1);
-        if(bin <= 0) {
-            xfce_mailwatch_log_message(imailbox->mailwatch,
-                                       XFCE_MAILWATCH_MAILBOX(imailbox),
-                                       XFCE_MAILWATCH_LOG_WARNING,
-                                       _("The IMAP server returned a response we weren't quite expecting.  This might be OK, or this plugin might need to be modified to support your mail server if the new message counts are incorrect."));
-            g_warning("Mailwatch: Odd response to STATUS UNSEEN");
-            return 0;
-        }
-        DBG("response to STATUS UNSEEN: %s", buf);
+    /* grab the response */
+    bin = imap_recv_command(imailbox, net_conn, buf, sizeof(buf));
+    if(bin <= 0) {
+        g_warning("Mailwatch: Bad response to STATUS UNSEEN; possibly just a folder that doesn't exist");
+        return 0;
+    }
+    DBG("response to STATUS UNSEEN: %s", buf);
 
-        if(bin > 6 && (!strncmp(buf+6, "NO", 2) || !strncmp(buf+6, "BAD", 3)))
-            return 0;
-
-        p = strstr(buf, "(UNSEEN ");
-        if(p) {
-            q = strchr(p, ')');
-            if(q) {
-                *q = 0;
-                new_messages = atoi(p+8);
-                *q = ')';
-            }
+    p = strstr(buf, "(UNSEEN ");
+    if(p) {
+        q = strchr(p, ')');
+        if(q) {
+            *q = 0;
+            new_messages = atoi(p+8);
+            *q = ')';
         }
-    } while(bin < 6 || strncmp(buf+6, "OK", 2));
+    }
     
     DBG("new message count in mailbox '%s' is %d", mailbox_name, new_messages);
     
@@ -834,7 +872,7 @@
     gboolean ret = TRUE;
     gchar buf[BUFSIZE+1], fullpath[(BUFSIZE+1)/8] = "", separator[2] = { 0, 0 };
     gchar *p, *q, **resp_lines;
-    gint bin_tot = 0, bin, i;
+    gint bin, i;
     gboolean holds_messages = TRUE, has_children = TRUE;
     IMAPFolderData *fdata;
     GNode *node;
@@ -849,34 +887,22 @@
         return FALSE;
     DBG("sent LIST: '%s'", buf);
     
-    *buf = 0;
-    while(!strstr(buf, " OK") && bin_tot < BUFSIZE) {
-        /* this is probably a bad idea... */
-    
-        bin = imap_recv(imailbox, net_conn, buf+bin_tot, BUFSIZE);
-        if(bin < 0) {
-            DBG("imap_recv() failed");
-            return FALSE;
-        }
-        bin_tot += bin;
-        
-        DBG("got LIST response (%d): '%s'", bin, buf+bin_tot-bin);
-        
-        if(strstr(buf, " NO ") || strstr(buf, " BAD "))
-            return FALSE;
+    bin = imap_recv_command(imailbox, net_conn, buf, BUFSIZE);
+    if(bin <= 0) {
+        DBG("LIST failed");
+        return FALSE;
     }
     
-    if(!strstr(buf, " OK"))
-        return FALSE;
-    
     if(strstr(buf, "\r"))
         resp_lines = g_strsplit(buf, "\r\n", -1);
     else
         resp_lines = g_strsplit(buf, "\n", -1);
     
     for(i = 0; resp_lines[i]; i++) {
-        if(!imap_folder_tree_should_continue(net_conn, imailbox))
-            return FALSE;
+        if(!imap_folder_tree_should_continue(net_conn, imailbox)) {
+            ret = FALSE;
+            break;
+        }
 
         if(*resp_lines[i] != '*')
             continue;
@@ -979,8 +1005,10 @@
         
         if(has_children) {
             g_strlcat(fullpath, separator, (BUFSIZE+1)/8);
-            if(!imap_populate_folder_tree(imailbox, net_conn, fullpath, node))
-                return FALSE;
+            if(!imap_populate_folder_tree(imailbox, net_conn, fullpath, node)) {
+                ret = FALSE;
+                break;
+            }
         }
     }
     




More information about the Goodies-commits mailing list