From: Thomas Roessler Date: Mon, 15 Jun 1998 15:19:45 +0000 (+0000) Subject: Brandon's IMAP patch. X-Git-Tag: mutt-0-92-10i~4 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a07d9f79f6a533ec83d64dda1c824e3a81c2d493;p=mutt Brandon's IMAP patch. --- diff --git a/commands.c b/commands.c index da508df9..0144238f 100644 --- a/commands.c +++ b/commands.c @@ -511,10 +511,13 @@ static int save_confirm_func (const char *s, struct stat *st) { char tmp[_POSIX_PATH_MAX]; int ret = 1; + int magic = 0; + + magic = mx_get_magic (s); if (stat (s, st) != -1) { - if (mx_get_magic (s) == -1) + if (magic == -1) { mutt_error ("%s is not a mailbox!", s); return 0; @@ -529,22 +532,25 @@ static int save_confirm_func (const char *s, struct stat *st) } else { - st->st_mtime = 0; - st->st_atime = 0; - - if (errno == ENOENT) + if (magic != M_IMAP) { - if (option (OPTCONFIRMCREATE)) + st->st_mtime = 0; + st->st_atime = 0; + + if (errno == ENOENT) { - snprintf (tmp, sizeof (tmp), "Create %s?", s); - if (mutt_yesorno (tmp, 1) < 1) - ret = 0; + if (option (OPTCONFIRMCREATE)) + { + snprintf (tmp, sizeof (tmp), "Create %s?", s); + if (mutt_yesorno (tmp, 1) < 1) + ret = 0; + } + } + else + { + mutt_perror (s); + return 0; } - } - else - { - mutt_perror (s); - return 0; } } diff --git a/imap.c b/imap.c index 619482c7..872e019b 100644 --- a/imap.c +++ b/imap.c @@ -30,6 +30,7 @@ #include #include #include +#include /* Minimal support for IMAP 4rev1 */ @@ -45,9 +46,21 @@ enum IMAP_FATAL = 1, IMAP_NEW_MAIL, IMAP_EXPUNGE, - IMAP_BYE + IMAP_BYE, + IMAP_OK_FAIL, + IMAP_OPEN_NEW }; +typedef struct +{ + char *server; + int uses; + int fd; + char inbuf[LONG_STRING]; + int bufpos; + int available; +} CONNECTION; + typedef struct { int index; @@ -59,36 +72,40 @@ typedef struct short status; unsigned short sequence; unsigned short newMailCount; + char *mailbox; short xxx; IMAP_CACHE cache[IMAP_CACHE_LEN]; + CONNECTION *conn; } IMAP_DATA; +#define CTX_DATA ((IMAP_DATA *) ctx->data) + +static CONNECTION *Connections = NULL; +static int NumConnections = 0; + /* simple read buffering to speed things up. */ -static int imap_readchar (int fd, char *c) +static int imap_readchar (CONNECTION *conn, char *c) { - static char inbuf[LONG_STRING]; - static int bufpos=0, available=0; - - if (bufpos>=available) - { - available = read (fd, inbuf, sizeof(inbuf)); - bufpos = 0; - if (available <= 0) - return available; /* returns 0 for EOF or -1 for other error */ - } - *c = inbuf[bufpos]; - bufpos++; + if (conn->bufpos >= conn->available) + { + conn->available = read (conn->fd, conn->inbuf, sizeof(LONG_STRING)); + conn->bufpos = 0; + if (conn->available <= 0) + return conn->available; /* returns 0 for EOF or -1 for other error */ + } + *c = conn->inbuf[conn->bufpos]; + conn->bufpos++; return 1; } -static int imap_read_line (char *buf, size_t buflen, int fd) +static int imap_read_line (char *buf, size_t buflen, CONNECTION *conn) { char ch; int i; for (i = 0; i < buflen; i++) { - if (imap_readchar (fd, &ch) != 1) + if (imap_readchar (conn, &ch) != 1) return (-1); if (ch == '\n') break; @@ -98,22 +115,22 @@ static int imap_read_line (char *buf, size_t buflen, int fd) return (i + 1); } -static int imap_read_line_d (char *buf, size_t buflen, int fd) +static int imap_read_line_d (char *buf, size_t buflen, CONNECTION *conn) { - int r = imap_read_line (buf, buflen, fd); + int r = imap_read_line (buf, buflen, conn); dprint (1,(debugfile,"imap_read_line_d():%s\n", buf)); return r; } static void imap_make_sequence (char *buf, size_t buflen, CONTEXT *ctx) { - snprintf (buf, buflen, "a%04d", ((IMAP_DATA *) ctx->data)->sequence++); + snprintf (buf, buflen, "a%04d", CTX_DATA->sequence++); } -static int imap_write (int fd, const char *buf) +static int imap_write (CONNECTION *conn, const char *buf) { dprint (1,(debugfile,"imap_write():%s", buf)); - return (write (fd, buf, strlen (buf))); + return (write (conn->fd, buf, strlen (buf))); } static void imap_error (const char *where, const char *msg) @@ -121,13 +138,43 @@ static void imap_error (const char *where, const char *msg) dprint (1, (debugfile, "imap_error(): unexpected response in %s: %s\n", where, msg)); } +static CONNECTION *imap_select_connection (char *host, int flags) +{ + int x; + + if (flags != IMAP_OPEN_NEW) + { + for (x = 0; x < NumConnections; x++) + { + if (!strcmp (host, Connections[x].server)) + return &Connections[x]; + } + } + if (NumConnections == 0) + { + NumConnections = 1; + Connections = (CONNECTION *) safe_malloc (sizeof (CONNECTION)); + } + else + { + NumConnections++; + safe_realloc ((void *)Connections, sizeof (CONNECTION) * NumConnections); + } + Connections[NumConnections - 1].bufpos = 0; + Connections[NumConnections - 1].available = 0; + Connections[NumConnections - 1].uses = 0; + Connections[NumConnections - 1].server = safe_strdup (host); + + return &Connections[NumConnections - 1]; +} + /* date is of the form: DD-MMM-YYYY HH:MM:SS +ZZzz */ static time_t imap_parse_date (char *s) { struct tm t; time_t tz; - t.tm_mday = (s[0] - '0') * 10 + (s[1] - '0'); + t.tm_mday = (s[0] == ' '? s[1] - '0' : (s[0] - '0') * 10 + (s[1] - '0')); s += 2; if (*s != '-') return 0; @@ -200,6 +247,7 @@ static int imap_parse_fetch (HEADER *h, char *s) /* we're about to get a new set of headers, so clear the old ones. */ h->deleted=0; h->flagged=0; h->replied=0; h->read=0; + h->changed=0; s++; state = 1; } @@ -230,7 +278,7 @@ static int imap_parse_fetch (HEADER *h, char *s) while (isdigit (*s)) *ptmp++ = *s++; *ptmp = 0; - h->content->length = atoi (tmp); + h->content->length += atoi (tmp); } else if (*s == ')') s++; /* end of request */ @@ -278,7 +326,7 @@ static int imap_parse_fetch (HEADER *h, char *s) return 0; } -static int imap_read_bytes (FILE *fp, int fd, long bytes) +static int imap_read_bytes (FILE *fp, CONNECTION *conn, long bytes) { long pos; long len; @@ -286,7 +334,7 @@ static int imap_read_bytes (FILE *fp, int fd, long bytes) for (pos = 0; pos < bytes; ) { - len = imap_read_line (buf, sizeof (buf), fd); + len = imap_read_line (buf, sizeof (buf), conn); if (len < 0) return (-1); pos += len; @@ -331,29 +379,28 @@ static int imap_handle_untagged (CONTEXT *ctx, char *s) /* new mail arrived */ count = atoi (pn); - if (((IMAP_DATA *) ctx->data)->status != IMAP_EXPUNGE) { - if (count <= ctx->msgcount) - { - /* something is wrong because the server reported fewer messages - * than we previously saw - */ - mutt_error ("Fatal error. Message count is out of sync!"); - ((IMAP_DATA *) ctx->data)->status = IMAP_FATAL; - mx_fastclose_mailbox (ctx); - return (-1); - } - else - { - ((IMAP_DATA *) ctx->data)->status = IMAP_NEW_MAIL; - ((IMAP_DATA *) ctx->data)->newMailCount = count; - } - } + if ( (CTX_DATA->status != IMAP_EXPUNGE) && + count <= ctx->msgcount) + { + /* something is wrong because the server reported fewer messages + * than we previously saw + */ + mutt_error ("Fatal error. Message count is out of sync!"); + CTX_DATA->status = IMAP_FATAL; + mx_fastclose_mailbox (ctx); + return (-1); + } + else + { + CTX_DATA->status = IMAP_NEW_MAIL; + CTX_DATA->newMailCount = count; + } } else if (strncasecmp ("EXPUNGE", s, 7) == 0) { /* a message was removed; reindex remaining messages */ /* (which amounts to decrementing indices of messages */ - /* with an index greater than the deleted one. */ + /* with an index greater than the deleted one.) */ ind = atoi (pn) - 1; for (n = 0; n < ctx->msgcount; n++) if (ctx->hdrs[n]->index > ind) @@ -366,7 +413,7 @@ static int imap_handle_untagged (CONTEXT *ctx, char *s) s += 3; SKIPWS (s); mutt_error (s); - ((IMAP_DATA *) ctx->data)->status = IMAP_BYE; + CTX_DATA->status = IMAP_BYE; mx_fastclose_mailbox (ctx); return (-1); } @@ -387,7 +434,7 @@ static int imap_read_header (CONTEXT *ctx, int msgno) char seq[8]; char *pc; char *pn; - long bytes; + long bytes = 0; ctx->hdrs[ctx->msgcount]->index = ctx->msgcount; @@ -399,11 +446,11 @@ static int imap_read_header (CONTEXT *ctx, int msgno) imap_make_sequence (seq, sizeof (seq), ctx); snprintf (buf, sizeof (buf), "%s FETCH %d RFC822.HEADER\r\n", seq, msgno + 1); - imap_write (ctx->fd, buf); + imap_write (CTX_DATA->conn, buf); do { - if (imap_read_line (buf, sizeof (buf), ctx->fd) < 0) + if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0) { return (-1); } @@ -427,7 +474,7 @@ static int imap_read_header (CONTEXT *ctx, int msgno) *pc = 0; bytes = atoi (pn); - imap_read_bytes (fp, ctx->fd, bytes); + imap_read_bytes (fp, CTX_DATA->conn, bytes); } else if (imap_handle_untagged (ctx, buf) != 0) return (-1); @@ -438,16 +485,19 @@ static int imap_read_header (CONTEXT *ctx, int msgno) rewind (fp); ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno]); +/* subtract the header length; the total message size will be added to this */ + ctx->hdrs[msgno]->content->length = -bytes; + fclose (fp); unlink (tempfile); /* get the status of this message */ imap_make_sequence (seq, sizeof (seq), ctx); snprintf (buf, sizeof (buf), "%s FETCH %d FAST\r\n", seq, msgno + 1); - imap_write (ctx->fd, buf); + imap_write (CTX_DATA->conn, buf); do { - if (imap_read_line_d (buf, sizeof (buf), ctx->fd) < 0) + if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0) break; if (buf[0] == '*') { @@ -475,15 +525,15 @@ static int imap_read_header (CONTEXT *ctx, int msgno) } static int imap_exec (char *buf, size_t buflen, - CONTEXT *ctx, const char *seq, const char *cmd) + CONTEXT *ctx, const char *seq, const char *cmd, int flags) { int count; - imap_write (ctx->fd, cmd); + imap_write (CTX_DATA->conn, cmd); do { - if (imap_read_line_d (buf, buflen, ctx->fd) < 0) + if (imap_read_line_d (buf, buflen, CTX_DATA->conn) < 0) return (-1); if (buf[0] == '*' && imap_handle_untagged (ctx, buf) != 0) @@ -491,16 +541,16 @@ static int imap_exec (char *buf, size_t buflen, } while (strncmp (buf, seq, SEQLEN) != 0); - if (((IMAP_DATA *) ctx->data)->status == IMAP_NEW_MAIL) + if (CTX_DATA->status == IMAP_NEW_MAIL) { /* read new mail messages */ dprint (1, (debugfile, "imap_exec(): new mail detected\n")); mutt_message ("Fetching headers for new mail..."); - ((IMAP_DATA *) ctx->data)->status = 0; + CTX_DATA->status = 0; - count = ((IMAP_DATA *) ctx->data)->newMailCount; + count = CTX_DATA->newMailCount; while (count > ctx->hdrmax) mx_alloc_memory (ctx); @@ -513,12 +563,12 @@ static int imap_exec (char *buf, size_t buflen, /* check to make sure that new mail hasn't arrived in the middle of * checking for new mail (sigh) */ - if (((IMAP_DATA *) ctx->data)->status == IMAP_NEW_MAIL) + if (CTX_DATA->status == IMAP_NEW_MAIL) { - count = ((IMAP_DATA *) ctx->data)->newMailCount; + count = CTX_DATA->newMailCount; while (count > ctx->hdrmax) mx_alloc_memory (ctx); - ((IMAP_DATA *) ctx->data)->status = 0; + CTX_DATA->status = 0; } } @@ -529,6 +579,8 @@ static int imap_exec (char *buf, size_t buflen, { char *pc; + if (flags == IMAP_OK_FAIL) + return (-1); dprint (1, (debugfile, "imap_exec(): command failed: %s\n", buf)); pc = buf + SEQLEN; SKIPWS (pc); @@ -541,31 +593,14 @@ static int imap_exec (char *buf, size_t buflen, return 0; } -int imap_open_mailbox (CONTEXT *ctx) +static int imap_open_connection (CONTEXT *ctx, CONNECTION *conn) { struct sockaddr_in sin; struct hostent *he; char buf[LONG_STRING]; - char bufout[LONG_STRING]; - char host[SHORT_STRING]; char user[SHORT_STRING]; char pass[SHORT_STRING]; - char mailbox[_POSIX_PATH_MAX]; char seq[16]; - int count = 0; - int n; - char *pc; - - if (ctx->path[0] != '{') - return (-1); - for(n = 0, pc = ctx->path + 1; *pc && *pc != '}' && n < sizeof(host) - 1; - n++, pc++) - host[n++] = *pc++; - if(*pc != '}') - return -1; - host[n] = 0; - pc++; - strfcpy (mailbox, pc, sizeof (mailbox)); if (!ImapUser) { @@ -583,7 +618,7 @@ int imap_open_mailbox (CONTEXT *ctx) if (!ImapPass) { pass[0]=0; - snprintf (buf, sizeof (buf), "Password for %s@%s: ", user, host); + snprintf (buf, sizeof (buf), "Password for %s@%s: ", user, conn->server); if (mutt_get_field (buf, pass, sizeof (pass), M_PASS) != 0 || !pass[0]) { @@ -596,53 +631,48 @@ int imap_open_mailbox (CONTEXT *ctx) memset (&sin, 0, sizeof (sin)); sin.sin_port = htons (IMAP_PORT); sin.sin_family = AF_INET; - if ((he = gethostbyname (host)) == NULL) + if ((he = gethostbyname (conn->server)) == NULL) { - mutt_perror (host); + mutt_perror (conn->server); return (-1); } memcpy (&sin.sin_addr, he->h_addr_list[0], he->h_length); - if ((ctx->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) + if ((conn->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) { mutt_perror ("socket"); return (-1); } - mutt_message ("Connecting to %s...", host); + mutt_message ("Connecting to %s...", conn->server); - if (connect (ctx->fd, (struct sockaddr *) &sin, sizeof (sin)) < 0) + if (connect (conn->fd, (struct sockaddr *) &sin, sizeof (sin)) < 0) { mutt_perror ("connect"); - close (ctx->fd); + close (conn->fd); } - if (imap_read_line_d (buf, sizeof (buf), ctx->fd) < 0) + if (imap_read_line_d (buf, sizeof (buf), conn) < 0) { - close (ctx->fd); + close (conn->fd); return (-1); } if (strncmp ("* OK", buf, 4) != 0) { - imap_error ("imap_open_mailbox()", buf); - close (ctx->fd); + imap_error ("imap_open_connection()", buf); + close (conn->fd); return (-1); } - /* create IMAP-specific state struct */ - ctx->data = safe_malloc (sizeof (IMAP_DATA)); - memset (ctx->data, 0, sizeof (IMAP_DATA)); - mutt_message ("Logging in..."); - imap_make_sequence (seq, sizeof (seq), ctx); + /* sequence numbers are currently context dependent, so just make one + * up for this first access to the server */ + strcpy (seq, "l0000"); snprintf (buf, sizeof (buf), "%s LOGIN %s %s\r\n", seq, user, pass); - if (imap_exec (buf, sizeof (buf), ctx, seq, buf) != 0) + if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0) { - /* Most likely an invalid login; clear username and password for re-entry. */ - FREE (&ImapUser); - FREE (&ImapPass); - imap_error ("imap_open_mailbox()", buf); + imap_error ("imap_open_connection()", buf); return (-1); } /* If they have a successful login, we may as well cache the user/password. */ @@ -651,14 +681,54 @@ int imap_open_mailbox (CONTEXT *ctx) if (!ImapPass) ImapPass = safe_strdup (pass); - mutt_message ("Selecting %s...", mailbox); + return 0; +} + +int imap_open_mailbox (CONTEXT *ctx) +{ + CONNECTION *conn; + char buf[LONG_STRING]; + char bufout[LONG_STRING]; + char host[SHORT_STRING]; + char seq[16]; + int count = 0; + int n; + char *pc; + + /* create IMAP-specific state struct */ + ctx->data = safe_malloc (sizeof (IMAP_DATA)); + memset (ctx->data, 0, sizeof (IMAP_DATA)); + + pc = ctx->path; + if (*pc != '{') + return (-1); + pc++; + n = 0; + while (*pc && *pc != '}') + host[n++] = *pc++; + host[n] = 0; + if (!*pc) + return (-1); + pc++; + + CTX_DATA->mailbox = safe_strdup (pc); + + conn = imap_select_connection (host, IMAP_OPEN_NEW); + CTX_DATA->conn = conn; + + if (conn->uses == 0) + if (imap_open_connection (ctx, conn)) + return (-1); + conn->uses++; + + mutt_message ("Selecting %s...", CTX_DATA->mailbox); imap_make_sequence (seq, sizeof (seq), ctx); - snprintf (bufout, sizeof (bufout), "%s SELECT %s\r\n", seq, mailbox); - imap_write (ctx->fd, bufout); + snprintf (bufout, sizeof (bufout), "%s SELECT %s\r\n", seq, CTX_DATA->mailbox); + imap_write (CTX_DATA->conn, bufout); do { - if (imap_read_line_d (buf, sizeof (buf), ctx->fd) < 0) + if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0) break; if (buf[0] == '*') @@ -704,18 +774,89 @@ int imap_open_mailbox (CONTEXT *ctx) mx_update_context (ctx); /* increments ->msgcount */ /* in case we get new mail while fetching the headers */ - if (((IMAP_DATA *) ctx->data)->status == IMAP_NEW_MAIL) + if (CTX_DATA->status == IMAP_NEW_MAIL) { - count = ((IMAP_DATA *) ctx->data)->newMailCount; + count = CTX_DATA->newMailCount; while (count > ctx->hdrmax) mx_alloc_memory (ctx); - ((IMAP_DATA *) ctx->data)->status = 0; + CTX_DATA->status = 0; } } return 0; } +static int imap_create_mailbox (CONTEXT *ctx) +{ + char seq[8]; + char buf[LONG_STRING]; + + imap_make_sequence (seq, sizeof (seq), ctx); + snprintf (buf, sizeof (buf), "%s CREATE %s\r\n", seq, CTX_DATA->mailbox); + + if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0) + { + imap_error ("imap_sync_mailbox()", buf); + return (-1); + } + return 0; +} + +int imap_open_mailbox_append (CONTEXT *ctx) +{ + CONNECTION *conn; + char host[SHORT_STRING]; + char buf[LONG_STRING]; + char seq[16]; + int n; + char *pc; + + /* create IMAP-specific state struct */ + ctx->data = safe_malloc (sizeof (IMAP_DATA)); + memset (ctx->data, 0, sizeof (IMAP_DATA)); + + pc = ctx->path; + if (*pc != '{') + return (-1); + pc++; + n = 0; + while (*pc && *pc != '}') + host[n++] = *pc++; + host[n] = 0; + if (!*pc) + return (-1); + pc++; + + CTX_DATA->mailbox = pc; + + conn = imap_select_connection (host, 0); + CTX_DATA->conn = conn; + + if (conn->uses == 0) + if (imap_open_connection (ctx, conn)) + return (-1); + conn->uses++; + + /* check mailbox existance */ + + imap_make_sequence (seq, sizeof (seq), ctx); + snprintf (buf, sizeof (buf), "%s STATUS %s (UIDVALIDITY)\r\n", seq, + CTX_DATA->mailbox); + + if (imap_exec (buf, sizeof (buf), ctx, seq, buf, IMAP_OK_FAIL) != 0) + { + if (option (OPTCONFIRMCREATE)) + { + snprintf (buf, sizeof (buf), "Create %s?", CTX_DATA->mailbox); + if (mutt_yesorno (buf, 1) < 1) + return (-1); + if (imap_create_mailbox (ctx) < 0) + return (-1); + } + } + return 0; +} + int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) { char seq[8]; @@ -727,7 +868,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) IMAP_CACHE *cache; /* see if we already have the message in our cache */ - cache = &((IMAP_DATA *) ctx->data)->cache[ctx->hdrs[msgno]->index % IMAP_CACHE_LEN]; + cache = &CTX_DATA->cache[ctx->hdrs[msgno]->index % IMAP_CACHE_LEN]; if (cache->path) { @@ -763,10 +904,10 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) imap_make_sequence (seq, sizeof (seq), ctx); snprintf (buf, sizeof (buf), "%s FETCH %d RFC822\r\n", seq, ctx->hdrs[msgno]->index + 1); - imap_write (ctx->fd, buf); + imap_write (CTX_DATA->conn, buf); do { - if (imap_read_line (buf, sizeof (buf), ctx->fd) < 0) + if (imap_read_line (buf, sizeof (buf), CTX_DATA->conn) < 0) { return (-1); } @@ -789,7 +930,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) pc++; *pc = 0; bytes = atoi (pn); - imap_read_bytes (msg->fp, ctx->fd, bytes); + imap_read_bytes (msg->fp, CTX_DATA->conn, bytes); } else if (imap_handle_untagged (ctx, buf) != 0) return (-1); @@ -806,27 +947,119 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) return 0; } +int imap_append_message (CONTEXT *ctx, MESSAGE *msg) +{ + FILE *fp; + struct stat s; + char seq[8]; + char buf[LONG_STRING]; + + if (stat (msg->path, &s) == -1) + { + mutt_perror (msg->path); + return (-1); + } + + if ((fp = safe_fopen (msg->path, "r")) == NULL) + { + mutt_perror (msg->path); + return (-1); + } + + mutt_message ("Sending APPEND command ..."); + imap_make_sequence (seq, sizeof (seq), ctx); + snprintf (buf, sizeof (buf), "%s APPEND %s {%d}\r\n", seq, + CTX_DATA->mailbox, s.st_size); + + imap_write (CTX_DATA->conn, buf); + + do + { + if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0) + { + fclose (fp); + return (-1); + } + + if (buf[0] == '*' && imap_handle_untagged (ctx, buf) != 0) + { + return (-1); + fclose (fp); + } + } + while ((strncmp (buf, seq, SEQLEN) != 0) && (buf[0] != '+')); + + if (buf[0] != '+') + { + char *pc; + + dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", buf)); + + pc = buf + SEQLEN; + SKIPWS (pc); + pc = imap_next_word (pc); + mutt_error (pc); + sleep (1); + fclose (fp); + return (-1); + } + + mutt_message ("Uploading message ..."); + while (fgets (buf, sizeof (buf), fp) != NULL) + { + imap_write (CTX_DATA->conn, buf); + } + imap_write (CTX_DATA->conn, "\r\n"); + fclose (fp); + + do + { + if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0) + return (-1); + + if (buf[0] == '*' && imap_handle_untagged (ctx, buf) != 0) + return (-1); + } + while (strncmp (buf, seq, SEQLEN) != 0); + + if (!imap_code (buf)) + { + char *pc; + + dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", buf)); + pc = buf + SEQLEN; + SKIPWS (pc); + pc = imap_next_word (pc); + mutt_error (pc); + sleep (1); + return (-1); + } + + return 0; +} + int imap_close_connection (CONTEXT *ctx) { char buf[LONG_STRING]; char seq[8]; /* if the server didn't shut down on us, close the connection gracefully */ - if (((IMAP_DATA *) ctx->data)->status != IMAP_BYE) + if (CTX_DATA->status != IMAP_BYE) { mutt_message ("Closing connection to IMAP server..."); imap_make_sequence (seq, sizeof (seq), ctx); snprintf (buf, sizeof (buf), "%s LOGOUT\r\n", seq); - imap_write (ctx->fd, buf); + imap_write (CTX_DATA->conn, buf); do { - if (imap_read_line_d (buf, sizeof (buf), ctx->fd) < 0) + if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0) break; } while (strncmp (seq, buf, SEQLEN) != 0); mutt_clear_error (); } - close (ctx->fd); + close (CTX_DATA->conn->fd); + CTX_DATA->conn->uses--; return 0; } @@ -840,11 +1073,11 @@ int imap_sync_mailbox (CONTEXT *ctx) /* save status changes */ for (n = 0; n < ctx->msgcount; n++) { - snprintf (tmp, sizeof (tmp), "Saving message status flags... [%d/%d]", n+1, - ctx->msgcount); - mutt_message (tmp); if (ctx->hdrs[n]->deleted || ctx->hdrs[n]->changed) { + snprintf (tmp, sizeof (tmp), "Saving message status flags... [%d/%d]", n+1, + ctx->msgcount); + mutt_message (tmp); *tmp = 0; if (ctx->hdrs[n]->read) strcat (tmp, "\\Seen "); @@ -860,7 +1093,7 @@ int imap_sync_mailbox (CONTEXT *ctx) imap_make_sequence (seq, sizeof (seq), ctx); snprintf (buf, sizeof (buf), "%s STORE %d FLAGS.SILENT (%s)\r\n", seq, ctx->hdrs[n]->index + 1, tmp); - if (imap_exec (buf, sizeof (buf), ctx, seq, buf) != 0) + if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0) { imap_error ("imap_sync_mailbox()", buf); return (-1); @@ -869,17 +1102,25 @@ int imap_sync_mailbox (CONTEXT *ctx) } mutt_message ("Expunging messages from server..."); - ((IMAP_DATA *) ctx->data)->status = IMAP_EXPUNGE; + CTX_DATA->status = IMAP_EXPUNGE; imap_make_sequence (seq, sizeof (seq), ctx); snprintf (buf, sizeof (buf), "%s EXPUNGE\r\n", seq); - if (imap_exec (buf, sizeof (buf), ctx, seq, buf) != 0) + if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0) { imap_error ("imap_sync_mailbox()", buf); return (-1); } - ((IMAP_DATA *) ctx->data)->status = 0; - /* WARNING: Messages need to be reindexed at this point after the expunge, or */ - /* mutt will become -very- confused unless it's quitting. */ + CTX_DATA->status = 0; + + for (n = 0; n < IMAP_CACHE_LEN; n++) + { + if (CTX_DATA->cache[n].path) + { + unlink (CTX_DATA->cache[n].path); + safe_free ((void **) &CTX_DATA->cache[n].path); + } + } + return 0; } @@ -887,13 +1128,16 @@ void imap_fastclose_mailbox (CONTEXT *ctx) { int i; + /* Check to see if the mailbox is actually open */ + if (!ctx->data) + return; imap_close_connection (ctx); for (i = 0; i < IMAP_CACHE_LEN; i++) { - if (((IMAP_DATA *) ctx->data)->cache[i].path) + if (CTX_DATA->cache[i].path) { - unlink (((IMAP_DATA *) ctx->data)->cache[i].path); - safe_free ((void **) &((IMAP_DATA *) ctx->data)->cache[i].path); + unlink (CTX_DATA->cache[i].path); + safe_free ((void **) &CTX_DATA->cache[i].path); } } safe_free ((void **) &ctx->data); @@ -909,7 +1153,7 @@ int imap_close_mailbox (CONTEXT *ctx) mutt_message ("Closing mailbox..."); imap_make_sequence (seq, sizeof (seq), ctx); snprintf (buf, sizeof (buf), "%s CLOSE\r\n", seq); - if (imap_exec (buf, sizeof (buf), ctx, seq, buf) != 0) + if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0) { imap_error ("imap_close_mailbox()", buf); return (-1); @@ -934,7 +1178,7 @@ int imap_check_mailbox (CONTEXT *ctx, int *index_hint) imap_make_sequence (seq, sizeof (seq), ctx); snprintf (buf, sizeof (buf), "%s NOOP\r\n", seq); - if (imap_exec (buf, sizeof (buf), ctx, seq, buf) != 0) + if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0) { imap_error ("imap_check_mailbox()", buf); return (-1); diff --git a/mailbox.h b/mailbox.h index ad9d8417..44b227ce 100644 --- a/mailbox.h +++ b/mailbox.h @@ -37,6 +37,7 @@ typedef struct { FILE *fp; /* pointer to the message data */ #ifdef USE_IMAP + CONTEXT *ctx; /* context (mailbox) for this message */ char *path; /* path to temp file */ #endif /* USE_IMAP */ short magic; /* type of mailbox this message belongs to */ diff --git a/main.c b/main.c index 2bea7ce7..4d1cce3c 100644 --- a/main.c +++ b/main.c @@ -210,9 +210,9 @@ static void show_version (void) #ifdef BUFFY_SIZE - "+BUFFY_SIZE" + "+BUFFY_SIZE " #else - "-BUFFY_SIZE" + "-BUFFY_SIZE " #endif ); puts ( diff --git a/mx.c b/mx.c index a1b93c53..b9964044 100644 --- a/mx.c +++ b/mx.c @@ -468,9 +468,18 @@ int mx_set_magic (const char *s) static int mx_open_mailbox_append (CONTEXT *ctx) { ctx->append = 1; + ctx->magic = mx_get_magic (ctx->path); + +#ifdef USE_IMAP + if (ctx->magic == M_IMAP) + { + return imap_open_mailbox_append (ctx); + } + else +#endif if (access (ctx->path, W_OK) == 0) { - switch (ctx->magic = mx_get_magic (ctx->path)) + switch (ctx->magic) { case 0: mutt_error ("%s is not a mailbox.", ctx->path); @@ -1082,6 +1091,20 @@ int mbox_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr) return 0; } +#ifdef USE_IMAP +int imap_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr) +{ + char tmp[_POSIX_PATH_MAX]; + + mutt_mktemp(tmp); + if ((msg->fp = safe_fopen (tmp, "w")) == NULL) + return (-1); + msg->path = safe_strdup(tmp); + msg->ctx = dest; + return 0; +} +#endif + /* args: * dest destintation mailbox * hdr message being copied (required for maildir support, because @@ -1106,6 +1129,11 @@ MESSAGE *mx_open_new_message (CONTEXT *dest, HEADER *hdr, int flags) case M_MH: func = mh_open_new_message; break; +#ifdef USE_IMAP + case M_IMAP: + func = imap_open_new_message; + break; +#endif default: dprint (1, (debugfile, "mx_open_new_message(): function unimplemented for mailbox type %d.\n", dest->magic)); @@ -1121,7 +1149,8 @@ MESSAGE *mx_open_new_message (CONTEXT *dest, HEADER *hdr, int flags) if (dest->magic == M_MMDF) fputs (MMDF_SEP, msg->fp); - if (msg->magic != M_MAILDIR && (flags & M_ADD_FROM)) + if ((msg->magic != M_MAILDIR) && (msg->magic != M_IMAP) && + (flags & M_ADD_FROM)) { if (hdr) { @@ -1420,8 +1449,26 @@ int mx_close_message (MESSAGE **msg) } } - if ((*msg)->magic == M_MH || (*msg)->magic == M_MAILDIR || (*msg)->magic == M_IMAP) - r = fclose ((*msg)->fp); + switch ((*msg)->magic) + { + case M_MH: + case M_MAILDIR: + r = fclose ((*msg)->fp); + break; + +#ifdef USE_IMAP + case M_IMAP: + r = fclose ((*msg)->fp); + if ((*msg)->write && (*msg)->ctx->append) + { + r = imap_append_message ((*msg)->ctx, *msg); + unlink ((*msg)->path); + } +#endif + + default: + break; + } free (*msg); *msg = NULL; @@ -1456,8 +1503,9 @@ void mx_update_context (CONTEXT *ctx) { HEADER *h = ctx->hdrs[ctx->msgcount]; - - +#ifdef USE_IMAP +#include "imap.h" +#endif