/*
* Heirloom mailx - a mail user agent derived from Berkeley Mail.
*
* Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
*/
/*
* Copyright (c) 2004
* Gunnar Ritter. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Gunnar Ritter
* and his contributors.
* 4. Neither the name of Gunnar Ritter nor the names of his contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
#ifdef DOSCCS
static char sccsid[] = "@(#)imap.c 1.222 (gritter) 3/13/09";
#endif
#endif /* not lint */
#include "config.h"
/*
* Mail -- a mail program
*
* IMAP v4r1 client following RFC 2060.
*/
#include "rcv.h"
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#ifdef HAVE_SOCKETS
#include "md5.h"
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif /* HAVE_ARPA_INET_H */
#include "extern.h"
static int verbose;
#define IMAP_ANSWER() { \
if (mp->mb_type != MB_CACHE) { \
enum okay ok = OKAY; \
while (mp->mb_active & MB_COMD) \
ok = imap_answer(mp, 1); \
if (ok == STOP) \
return STOP; \
} \
}
#define IMAP_OUT(x, y, action) \
{ \
if (mp->mb_type != MB_CACHE) { \
if (imap_finish(mp) == STOP) \
return STOP; \
if (verbose) \
fprintf(stderr, ">>> %s", x); \
mp->mb_active |= (y); \
if (swrite(&mp->mb_sock, x) == STOP) \
action; \
} else { \
if (queuefp != NULL) \
fputs(x, queuefp); \
} \
}
static struct record {
struct record *rec_next;
unsigned long rec_count;
enum rec_type {
REC_EXISTS,
REC_EXPUNGE
} rec_type;
} *record, *recend;
static enum {
RESPONSE_TAGGED,
RESPONSE_DATA,
RESPONSE_FATAL,
RESPONSE_CONT,
RESPONSE_ILLEGAL
} response_type;
static enum {
RESPONSE_OK,
RESPONSE_NO,
RESPONSE_BAD,
RESPONSE_PREAUTH,
RESPONSE_BYE,
RESPONSE_OTHER,
RESPONSE_UNKNOWN
} response_status;
static char *responded_tag;
static char *responded_text;
static char *responded_other_text;
static long responded_other_number;
static enum {
MAILBOX_DATA_FLAGS,
MAILBOX_DATA_LIST,
MAILBOX_DATA_LSUB,
MAILBOX_DATA_MAILBOX,
MAILBOX_DATA_SEARCH,
MAILBOX_DATA_STATUS,
MAILBOX_DATA_EXISTS,
MAILBOX_DATA_RECENT,
MESSAGE_DATA_EXPUNGE,
MESSAGE_DATA_FETCH,
CAPABILITY_DATA,
RESPONSE_OTHER_UNKNOWN
} response_other;
static enum list_attributes {
LIST_NONE = 000,
LIST_NOINFERIORS = 001,
LIST_NOSELECT = 002,
LIST_MARKED = 004,
LIST_UNMARKED = 010
} list_attributes;
static int list_hierarchy_delimiter;
static char *list_name;
struct list_item {
struct list_item *l_next;
char *l_name;
char *l_base;
enum list_attributes l_attr;
int l_delim;
int l_level;
int l_has_children;
};
static char *imapbuf;
static size_t imapbufsize;
static sigjmp_buf imapjmp;
static sighandler_type savealrm;
static int reset_tio;
static struct termios otio;
static int imapkeepalive;
static long had_exists = -1;
static long had_expunge = -1;
static long expunged_messages;
static volatile int imaplock;
static int same_imap_account;
static void imap_other_get(char *pp);
static void imap_response_get(const char **cp);
static void imap_response_parse(void);
static enum okay imap_answer(struct mailbox *mp, int errprnt);
static enum okay imap_parse_list(void);
static enum okay imap_finish(struct mailbox *mp);
static void imap_timer_off(void);
static void imapcatch(int s);
static void maincatch(int s);
static enum okay imap_noop1(struct mailbox *mp);
static void rec_queue(enum rec_type type, unsigned long count);
static enum okay rec_dequeue(void);
static void rec_rmqueue(void);
static void imapalarm(int s);
static int imap_use_starttls(const char *uhp);
static enum okay imap_preauth(struct mailbox *mp, const char *xserver,
const char *uhp);
static enum okay imap_capability(struct mailbox *mp);
static enum okay imap_auth(struct mailbox *mp, const char *uhp,
char *xuser, const char *pass);
static enum okay imap_cram_md5(struct mailbox *mp,
char *xuser, const char *xpass);
static enum okay imap_login(struct mailbox *mp, char *xuser, const char *xpass);
#ifdef USE_GSSAPI
static enum okay imap_gss(struct mailbox *mp, char *user);
#endif /* USE_GSSAPI */
static enum okay imap_flags(struct mailbox *mp, unsigned X, unsigned Y);
static void imap_init(struct mailbox *mp, int n);
static void imap_setptr(struct mailbox *mp, int newmail, int transparent,
int *prevcount);
static char *imap_have_password(const char *server);
static void imap_split(char **server, const char **sp, int *use_ssl,
const char **cp, char **uhp, char **mbx,
const char **pass, char **user);
static int imap_setfile1(const char *xserver, int newmail, int isedit,
int transparent);
static int imap_fetchdata(struct mailbox *mp, struct message *m,
size_t expected, int need,
const char *head, size_t headsize, long headlines);
static void imap_putstr(struct mailbox *mp, struct message *m,
const char *str,
const char *head, size_t headsize, long headlines);
static enum okay imap_get(struct mailbox *mp, struct message *m,
enum needspec need);
static void commitmsg(struct mailbox *mp, struct message *to,
struct message from, enum havespec have);
static enum okay imap_fetchheaders(struct mailbox *mp, struct message *m,
int bot, int top);
static enum okay imap_exit(struct mailbox *mp);
static enum okay imap_delete(struct mailbox *mp, int n, struct message *m, int
needstat);
static enum okay imap_close(struct mailbox *mp);
static enum okay imap_update(struct mailbox *mp);
static enum okay imap_store(struct mailbox *mp, struct message *m,
int n, int c, const char *sp, int needstat);
static enum okay imap_unstore(struct message *m, int n, const char *flag);
static const char *tag(int new);
static char *imap_putflags(int f);
static void imap_getflags(const char *cp, char **xp, enum mflag *f);
static enum okay imap_append1(struct mailbox *mp, const char *name, FILE *fp,
off_t off1, long xsize, enum mflag flag, time_t t);
static enum okay imap_append0(struct mailbox *mp, const char *name, FILE *fp);
static enum okay imap_list1(struct mailbox *mp, const char *base,
struct list_item **list, struct list_item **lend, int level);
static enum okay imap_list(struct mailbox *mp, const char *base,
int strip, FILE *fp);
static void dopr(FILE *fp);
static enum okay imap_copy1(struct mailbox *mp, struct message *m, int n,
const char *name);
static enum okay imap_copyuid_parse(const char *cp, unsigned lon