/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006 Oswald Buddenhagen * * 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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #define _GNU_SOURCE #include #include #include #include #define as(ar) (sizeof(ar)/sizeof(ar[0])) #define __stringify(x) #x #define stringify(x) __stringify(x) #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) # define ATTR_UNUSED __attribute__((unused)) # define ATTR_NORETURN __attribute__((noreturn)) # define ATTR_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) #else # define ATTR_UNUSED # define ATTR_NORETURN # define ATTR_PRINTFLIKE(fmt,var) #endif #define EXE "mbsync" typedef struct { const char *file; FILE *fp; char *buf; int bufl; int line; char *cmd, *val, *rest; } conffile_t; #define OP_NEW (1<<0) #define OP_RENEW (1<<1) #define OP_DELETE (1<<2) #define OP_FLAGS (1<<3) #define OP_MASK_TYPE (OP_NEW|OP_RENEW|OP_DELETE|OP_FLAGS) /* asserted in the target ops */ #define OP_EXPUNGE (1<<4) #define OP_CREATE (1<<5) #define XOP_PUSH (1<<6) #define XOP_PULL (1<<7) #define XOP_MASK_DIR (XOP_PUSH|XOP_PULL) #define XOP_HAVE_TYPE (1<<8) #define XOP_HAVE_EXPUNGE (1<<9) #define XOP_HAVE_CREATE (1<<10) typedef struct driver driver_t; typedef struct store_conf { struct store_conf *next; char *name; driver_t *driver; const char *path; /* should this be here? its interpretation is driver-specific */ const char *map_inbox; const char *trash; unsigned max_size; /* off_t is overkill */ unsigned trash_remote_new:1, trash_only_new:1; } store_conf_t; typedef struct string_list { struct string_list *next; char string[1]; } string_list_t; #define M 0 /* master */ #define S 1 /* slave */ typedef struct channel_conf { struct channel_conf *next; const char *name; store_conf_t *stores[2]; const char *boxes[2]; char *sync_state; string_list_t *patterns; int ops[2]; unsigned max_messages; /* for slave only */ } channel_conf_t; typedef struct group_conf { struct group_conf *next; const char *name; string_list_t *channels; } group_conf_t; /* For message->flags */ /* Keep the mailbox driver flag definitions in sync! */ /* The order is according to alphabetical maildir flag sort */ #define F_DRAFT (1<<0) /* Draft */ #define F_FLAGGED (1<<1) /* Flagged */ #define F_ANSWERED (1<<2) /* Replied */ #define F_SEEN (1<<3) /* Seen */ #define F_DELETED (1<<4) /* Trashed */ #define NUM_FLAGS 5 /* For message->status */ #define M_RECENT (1<<0) /* unsyncable flag; maildir_* depend on this being 1<<0 */ #define M_DEAD (1<<1) /* expunged */ #define M_FLAGS (1<<2) /* flags fetched */ typedef struct message { struct message *next; struct sync_rec *srec; /* string_list_t *keywords; */ size_t size; /* zero implies "not fetched" */ int uid; unsigned char flags, status; } message_t; /* For opts, both in store and driver_t->select() */ #define OPEN_OLD (1<<0) #define OPEN_NEW (1<<1) #define OPEN_FLAGS (1<<2) #define OPEN_SIZE (1<<3) #define OPEN_CREATE (1<<4) #define OPEN_EXPUNGE (1<<5) #define OPEN_SETFLAGS (1<<6) #define OPEN_APPEND (1<<7) #define OPEN_FIND (1<<8) typedef struct store { struct store *next; store_conf_t *conf; /* foreign */ string_list_t *boxes; /* _list results - own */ unsigned listed:1; /* was _list already run? */ /* currently open mailbox */ const char *name; /* foreign! maybe preset? */ char *path; /* own */ message_t *msgs; /* own */ int uidvalidity; unsigned opts; /* maybe preset? */ /* note that the following do _not_ reflect stats from msgs, but mailbox totals */ int count; /* # of messages */ int recent; /* # of recent messages - don't trust this beyond the initial read */ } store_t; typedef struct { char *data; int len; unsigned char flags; } msg_data_t; #define DRV_OK 0 #define DRV_MSG_BAD 1 #define DRV_BOX_BAD 2 #define DRV_STORE_BAD 3 #define DRV_SERVER_BAD 4 #define DRV_CANCELED 5 /* All memory belongs to the driver's user. */ #define DRV_CRLF 1 #define TUIDL 12 struct driver { int flags; int (*parse_store)( conffile_t *cfg, store_conf_t **storep, int *err ); void (*cleanup)( void ); void (*open_store)( store_conf_t *conf, void (*cb)( store_t *ctx, void *aux ), void *aux ); void (*disown_store)( store_t *ctx ); store_t *(*own_store)( store_conf_t *conf ); void (*cancel_store)( store_t *ctx ); void (*list)( store_t *ctx, void (*cb)( int sts, void *aux ), void *aux ); void (*prepare_paths)( store_t *ctx ); void (*prepare_opts)( store_t *ctx, int opts ); int (*select)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs, int (*cb)( int sts, void *aux ), void *aux ); int (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data, int (*cb)( int sts, void *aux ), void *aux ); int (*store_msg)( store_t *ctx, msg_data_t *data, int to_trash, int (*cb)( int sts, int uid, void *aux ), void *aux ); int (*find_msg)( store_t *ctx, const char *tuid, int (*cb)( int sts, int uid, void *aux ), void *aux ); int (*set_flags)( store_t *ctx, message_t *msg, int uid, int add, int del, /* msg can be null, therefore uid as a fallback */ int (*cb)( int sts, void *aux ), void *aux ); int (*trash_msg)( store_t *ctx, message_t *msg, /* This may expunge the original message immediately, but it needn't to */ int (*cb)( int sts, void *aux ), void *aux ); int (*close)( store_t *ctx, /* IMAP-style: expunge inclusive */ int (*cb)( int sts, void *aux ), void *aux ); void (*cancel)( store_t *ctx, /* only not yet sent commands */ void (*cb)( int sts, void *aux ), void *aux ); void (*commit)( store_t *ctx ); }; /* main.c */ extern int Pid; extern char Hostname[256]; extern const char *Home; /* util.c */ #define DEBUG 1 #define VERBOSE 2 #define QUIET 4 #define VERYQUIET 8 #define KEEPJOURNAL 16 extern int DFlags, Ontty; void debug( const char *, ... ); void debugn( const char *, ... ); void info( const char *, ... ); void infon( const char *, ... ); void warn( const char *, ... ); void error( const char *, ... ); char *next_arg( char ** ); void add_string_list( string_list_t **list, const char *str ); void free_string_list( string_list_t *list ); void free_generic_messages( message_t * ); void *nfmalloc( size_t sz ); void *nfcalloc( size_t sz ); void *nfrealloc( void *mem, size_t sz ); char *nfstrdup( const char *str ); int nfvasprintf( char **str, const char *fmt, va_list va ); int nfasprintf( char **str, const char *fmt, ... ); int nfsnprintf( char *buf, int blen, const char *fmt, ... ); void ATTR_NORETURN oob( void ); char *expand_strdup( const char *s ); void sort_ints( int *arr, int len ); void arc4_init( void ); unsigned char arc4_getbyte( void ); /* sync.c */ extern const char *str_ms[2], *str_hl[2]; #define SYNC_OK 0 /* assumed to be 0 */ #define SYNC_FAIL 1 #define SYNC_BAD(ms) (2<<(ms)) #define SYNC_NOGOOD 8 /* internal */ #define SYNC_CANCELED 16 /* internal */ /* All passed pointers must stay alive until cb is called. */ void sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan, void (*cb)( int sts, void *aux ), void *aux ); /* config.c */ #define N_DRIVERS 2 extern driver_t *drivers[N_DRIVERS]; extern channel_conf_t *channels; extern group_conf_t *groups; extern int global_ops[2]; extern char *global_sync_state; int parse_bool( conffile_t *cfile ); int parse_int( conffile_t *cfile ); int parse_size( conffile_t *cfile ); int getcline( conffile_t *cfile ); int merge_ops( int cops, int ops[] ); int load_config( const char *filename, int pseudo ); void parse_generic_store( store_conf_t *store, conffile_t *cfg, int *err ); /* drv_*.c */ extern driver_t maildir_driver, imap_driver;