help: remove extra blank line after "See 'git --help'" message
[gitweb.git] / imap-send.c
index 1b38b3af676a2867c09d7eabe36956b87fa9478d..a429a76a6385bb7d7935cfaddec9cfc8508c77e5 100644 (file)
 
 #include "cache.h"
 
-#include <assert.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
 typedef struct store_conf {
        char *name;
        const char *path; /* should this be here? its interpretation is driver-specific */
@@ -93,7 +86,7 @@ typedef struct {
        char *data;
        int len;
        unsigned char flags;
-       unsigned char crlf:1;
+       unsigned int crlf:1;
 } msg_data_t;
 
 #define DRV_OK          0
@@ -103,16 +96,28 @@ typedef struct {
 
 static int Verbose, Quiet;
 
-static void info( const char *, ... );
-static void warn( const char *, ... );
+static void imap_info( const char *, ... );
+static void imap_warn( const char *, ... );
 
 static char *next_arg( char ** );
 
 static void free_generic_messages( message_t * );
 
-static int nfvasprintf( char **str, const char *fmt, va_list va );
 static int nfsnprintf( char *buf, int blen, const char *fmt, ... );
 
+static int nfvasprintf(char **strp, const char *fmt, va_list ap)
+{
+       int len;
+       char tmp[8192];
+
+       len = vsnprintf(tmp, sizeof(tmp), fmt, ap);
+       if (len < 0)
+               die("Fatal: Out of memory\n");
+       if (len >= sizeof(tmp))
+               die("imap command overflow !\n");
+       *strp = xmemdupz(tmp, len);
+       return len;
+}
 
 static void arc4_init( void );
 static unsigned char arc4_getbyte( void );
@@ -232,7 +237,7 @@ socket_perror( const char *func, Socket_t *sock, int ret )
 static int
 socket_read( Socket_t *sock, char *buf, int len )
 {
-       int n = read( sock->fd, buf, len );
+       ssize_t n = xread( sock->fd, buf, len );
        if (n <= 0) {
                socket_perror( "read", sock, n );
                close( sock->fd );
@@ -242,9 +247,9 @@ socket_read( Socket_t *sock, char *buf, int len )
 }
 
 static int
-socket_write( Socket_t *sock, char *buf, int len )
+socket_write( Socket_t *sock, const char *buf, int len )
 {
-       int n = write( sock->fd, buf, len );
+       int n = write_in_full( sock->fd, buf, len );
        if (n != len) {
                socket_perror( "write", sock, n );
                close( sock->fd );
@@ -273,7 +278,7 @@ buffer_gets( buffer_t * b, char **s )
                                n = b->bytes - start;
 
                                if (n)
-                                       memcpy( b->buf, b->buf + start, n );
+                                       memmove(b->buf, b->buf + start, n);
                                b->offset -= start;
                                b->bytes = n;
                                start = 0;
@@ -305,7 +310,7 @@ buffer_gets( buffer_t * b, char **s )
 }
 
 static void
-info( const char *msg, ... )
+imap_info( const char *msg, ... )
 {
        va_list va;
 
@@ -318,7 +323,7 @@ info( const char *msg, ... )
 }
 
 static void
-warn( const char *msg, ... )
+imap_warn( const char *msg, ... )
 {
        va_list va;
 
@@ -335,12 +340,12 @@ next_arg( char **s )
        char *ret;
 
        if (!s || !*s)
-               return 0;
+               return NULL;
        while (isspace( (unsigned char) **s ))
                (*s)++;
        if (!**s) {
-               *s = 0;
-               return 0;
+               *s = NULL;
+               return NULL;
        }
        if (**s == '"') {
                ++*s;
@@ -355,7 +360,7 @@ next_arg( char **s )
                if (**s)
                        *(*s)++ = 0;
                if (!**s)
-                       *s = 0;
+                       *s = NULL;
        }
        return ret;
 }
@@ -371,21 +376,6 @@ free_generic_messages( message_t *msgs )
        }
 }
 
-static int
-vasprintf( char **strp, const char *fmt, va_list ap )
-{
-       int len;
-       char tmp[1024];
-
-       if ((len = vsnprintf( tmp, sizeof(tmp), fmt, ap )) < 0 || !(*strp = xmalloc( len + 1 )))
-               return -1;
-       if (len >= (int)sizeof(tmp))
-               vsprintf( *strp, fmt, ap );
-       else
-               memcpy( *strp, tmp, len + 1 );
-       return len;
-}
-
 static int
 nfsnprintf( char *buf, int blen, const char *fmt, ... )
 {
@@ -399,15 +389,6 @@ nfsnprintf( char *buf, int blen, const char *fmt, ... )
        return ret;
 }
 
-static int
-nfvasprintf( char **str, const char *fmt, va_list va )
-{
-       int ret = vasprintf( str, fmt, va );
-       if (ret < 0)
-               die( "Fatal: Out of memory\n");
-       return ret;
-}
-
 static struct {
        unsigned char i, j, s[256];
 } rs;
@@ -422,7 +403,7 @@ arc4_init( void )
                fprintf( stderr, "Fatal: no random number source available.\n" );
                exit( 3 );
        }
-       if (read( fd, dat, 128 ) != 128) {
+       if (read_in_full( fd, dat, 128 ) != 128) {
                fprintf( stderr, "Fatal: cannot read random number source.\n" );
                exit( 3 );
        }
@@ -475,7 +456,7 @@ v_issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb,
                memset( &cmd->cb, 0, sizeof(cmd->cb) );
 
        while (imap->literal_pending)
-               get_cmd_result( ctx, 0 );
+               get_cmd_result( ctx, NULL );
 
        bufl = nfsnprintf( buf, sizeof(buf), cmd->cb.data ? CAP(LITERALPLUS) ?
                           "%d %s{%d+}\r\n" : "%d %s{%d}\r\n" : "%d %s\r\n",
@@ -506,12 +487,12 @@ v_issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb,
                                free( cmd );
                                return NULL;
                        }
-                       cmd->cb.data = 0;
+                       cmd->cb.data = NULL;
                } else
                        imap->literal_pending = 1;
        } else if (cmd->cb.cont)
                imap->literal_pending = 1;
-       cmd->next = 0;
+       cmd->next = NULL;
        *imap->in_progress_append = cmd;
        imap->in_progress_append = &cmd->next;
        imap->num_in_progress++;
@@ -607,7 +588,7 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level )
                }
                *curp = cur = xmalloc( sizeof(*cur) );
                curp = &cur->next;
-               cur->val = 0; /* for clean bail */
+               cur->val = NULL; /* for clean bail */
                if (*s == '(') {
                        /* sublist */
                        s++;
@@ -655,9 +636,7 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level )
                                        goto bail;
                        cur->len = s - p;
                        s++;
-                       cur->val = xmalloc( cur->len + 1 );
-                       memcpy( cur->val, p, cur->len );
-                       cur->val[cur->len] = 0;
+                       cur->val = xmemdupz(p, cur->len);
                } else {
                        /* atom */
                        p = s;
@@ -665,12 +644,10 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level )
                                if (level && *s == ')')
                                        break;
                        cur->len = s - p;
-                       if (cur->len == 3 && !memcmp ("NIL", p, 3))
+                       if (cur->len == 3 && !memcmp ("NIL", p, 3)) {
                                cur->val = NIL;
-                       else {
-                               cur->val = xmalloc( cur->len + 1 );
-                               memcpy( cur->val, p, cur->len );
-                               cur->val[cur->len] = 0;
+                       } else {
+                               cur->val = xmemdupz(p, cur->len);
                        }
                }
 
@@ -680,11 +657,11 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level )
                        goto bail;
        }
        *sp = s;
-       *curp = 0;
+       *curp = NULL;
        return 0;
 
   bail:
-       *curp = 0;
+       *curp = NULL;
        return -1;
 }
 
@@ -702,7 +679,7 @@ parse_imap_list( imap_t *imap, char **sp )
 static list_t *
 parse_list( char **sp )
 {
-       return parse_imap_list( 0, sp );
+       return parse_imap_list( NULL, sp );
 }
 
 static void
@@ -789,7 +766,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
                                imap->ns_shared = parse_list( &cmd );
                        } else if (!strcmp( "OK", arg ) || !strcmp( "BAD", arg ) ||
                                   !strcmp( "NO", arg ) || !strcmp( "BYE", arg )) {
-                               if ((resp = parse_response_code( ctx, 0, cmd )) != RESP_OK)
+                               if ((resp = parse_response_code( ctx, NULL, cmd )) != RESP_OK)
                                        return resp;
                        } else if (!strcmp( "CAPABILITY", arg ))
                                parse_capability( imap, cmd );
@@ -813,7 +790,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
                        if (cmdp->cb.data) {
                                n = socket_write( &imap->buf.sock, cmdp->cb.data, cmdp->cb.dlen );
                                free( cmdp->cb.data );
-                               cmdp->cb.data = 0;
+                               cmdp->cb.data = NULL;
                                if (n != (int)cmdp->cb.dlen)
                                        return RESP_BAD;
                        } else if (cmdp->cb.cont) {
@@ -849,7 +826,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
                                if (!strcmp( "NO", arg )) {
                                        if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp( cmd, "[TRYCREATE]", 11 ))) { /* SELECT, APPEND or UID COPY */
                                                p = strchr( cmdp->cmd, '"' );
-                                               if (!issue_imap_cmd( ctx, 0, "CREATE \"%.*s\"", strchr( p + 1, '"' ) - p + 1, p )) {
+                                               if (!issue_imap_cmd( ctx, NULL, "CREATE \"%.*s\"", strchr( p + 1, '"' ) - p + 1, p )) {
                                                        resp = RESP_BAD;
                                                        goto normal;
                                                }
@@ -898,7 +875,7 @@ imap_close_server( imap_store_t *ictx )
        imap_t *imap = ictx->imap;
 
        if (imap->buf.sock.fd != -1) {
-               imap_exec( ictx, 0, "LOGOUT" );
+               imap_exec( ictx, NULL, "LOGOUT" );
                close( imap->buf.sock.fd );
        }
        free_list( imap->ns_personal );
@@ -924,6 +901,7 @@ imap_open_store( imap_server_conf_t *srvc )
        struct hostent *he;
        struct sockaddr_in addr;
        int s, a[2], preauth;
+       pid_t pid;
 
        ctx = xcalloc( sizeof(*ctx), 1 );
 
@@ -934,14 +912,17 @@ imap_open_store( imap_server_conf_t *srvc )
        /* open connection to IMAP server */
 
        if (srvc->tunnel) {
-               info( "Starting tunnel '%s'... ", srvc->tunnel );
+               imap_info( "Starting tunnel '%s'... ", srvc->tunnel );
 
                if (socketpair( PF_UNIX, SOCK_STREAM, 0, a )) {
                        perror( "socketpair" );
                        exit( 1 );
                }
 
-               if (fork() == 0) {
+               pid = fork();
+               if (pid < 0)
+                       _exit( 127 );
+               if (!pid) {
                        if (dup2( a[0], 0 ) == -1 || dup2( a[0], 1 ) == -1)
                                _exit( 127 );
                        close( a[0] );
@@ -954,31 +935,31 @@ imap_open_store( imap_server_conf_t *srvc )
 
                imap->buf.sock.fd = a[1];
 
-               info( "ok\n" );
+               imap_info( "ok\n" );
        } else {
                memset( &addr, 0, sizeof(addr) );
                addr.sin_port = htons( srvc->port );
                addr.sin_family = AF_INET;
 
-               info( "Resolving %s... ", srvc->host );
+               imap_info( "Resolving %s... ", srvc->host );
                he = gethostbyname( srvc->host );
                if (!he) {
                        perror( "gethostbyname" );
                        goto bail;
                }
-               info( "ok\n" );
+               imap_info( "ok\n" );
 
                addr.sin_addr.s_addr = *((int *) he->h_addr_list[0]);
 
                s = socket( PF_INET, SOCK_STREAM, 0 );
 
-               info( "Connecting to %s:%hu... ", inet_ntoa( addr.sin_addr ), ntohs( addr.sin_port ) );
+               imap_info( "Connecting to %s:%hu... ", inet_ntoa( addr.sin_addr ), ntohs( addr.sin_port ) );
                if (connect( s, (struct sockaddr *)&addr, sizeof(addr) )) {
                        close( s );
                        perror( "connect" );
                        goto bail;
                }
-               info( "ok\n" );
+               imap_info( "ok\n" );
 
                imap->buf.sock.fd = s;
 
@@ -1001,13 +982,13 @@ imap_open_store( imap_server_conf_t *srvc )
                fprintf( stderr, "IMAP error: unknown greeting response\n" );
                goto bail;
        }
-       parse_response_code( ctx, 0, rsp );
-       if (!imap->caps && imap_exec( ctx, 0, "CAPABILITY" ) != RESP_OK)
+       parse_response_code( ctx, NULL, rsp );
+       if (!imap->caps && imap_exec( ctx, NULL, "CAPABILITY" ) != RESP_OK)
                goto bail;
 
        if (!preauth) {
 
-               info ("Logging in...\n");
+               imap_info ("Logging in...\n");
                if (!srvc->user) {
                        fprintf( stderr, "Skipping server %s, no user\n", srvc->host );
                        goto bail;
@@ -1028,14 +1009,14 @@ imap_open_store( imap_server_conf_t *srvc )
                         * getpass() returns a pointer to a static buffer.  make a copy
                         * for long term storage.
                         */
-                       srvc->pass = strdup( arg );
+                       srvc->pass = xstrdup( arg );
                }
                if (CAP(NOLOGIN)) {
                        fprintf( stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host );
                        goto bail;
                }
-               warn( "*** IMAP Warning *** Password is being sent in the clear\n" );
-               if (imap_exec( ctx, 0, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass ) != RESP_OK) {
+               imap_warn( "*** IMAP Warning *** Password is being sent in the clear\n" );
+               if (imap_exec( ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass ) != RESP_OK) {
                        fprintf( stderr, "IMAP error: LOGIN failed\n" );
                        goto bail;
                }
@@ -1047,7 +1028,7 @@ imap_open_store( imap_server_conf_t *srvc )
 
   bail:
        imap_close_store( &ctx->gen );
-       return 0;
+       return NULL;
 }
 
 static int
@@ -1188,27 +1169,18 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid )
 static int
 read_message( FILE *f, msg_data_t *msg )
 {
-       int len, r;
+       struct strbuf buf;
 
-       memset( msg, 0, sizeof *msg );
-       len = CHUNKSIZE;
-       msg->data = xmalloc( len+1 );
-       msg->data[0] = 0;
-
-       while(!feof( f )) {
-               if (msg->len >= len) {
-                       void *p;
-                       len += CHUNKSIZE;
-                       p = xrealloc(msg->data, len+1);
-                       if (!p)
-                               break;
-               }
-               r = fread( &msg->data[msg->len], 1, len - msg->len, f );
-               if (r <= 0)
+       memset(msg, 0, sizeof(*msg));
+       strbuf_init(&buf, 0);
+
+       do {
+               if (strbuf_fread(&buf, CHUNKSIZE, f) <= 0)
                        break;
-               msg->len += r;
-       }
-       msg->data[msg->len] = 0;
+       } while (!feof(f));
+
+       msg->len  = buf.len;
+       msg->data = strbuf_detach(&buf, NULL);
        return msg->len;
 }
 
@@ -1219,7 +1191,7 @@ count_messages( msg_data_t *msg )
        char *p = msg->data;
 
        while (1) {
-               if (!strncmp( "From ", p, 5 )) {
+               if (!prefixcmp(p, "From ")) {
                        count++;
                        p += 5;
                }
@@ -1243,22 +1215,24 @@ split_msg( msg_data_t *all_msgs, msg_data_t *msg, int *ofs )
        data = &all_msgs->data[ *ofs ];
        msg->len = all_msgs->len - *ofs;
 
-       if (msg->len < 5 || strncmp( data, "From ", 5 ))
+       if (msg->len < 5 || prefixcmp(data, "From "))
                return 0;
 
+       p = strchr( data, '\n' );
+       if (p) {
+               p = &p[1];
+               msg->len -= p-data;
+               *ofs += p-data;
+               data = p;
+       }
+
        p = strstr( data, "\nFrom " );
        if (p)
                msg->len = &p[1] - data;
 
-       msg->data = xmalloc( msg->len + 1 );
-       if (!msg->data)
-               return 0;
-
-       memcpy( msg->data, data, msg->len );
-       msg->data[ msg->len ] = 0;
-
+       msg->data = xmemdupz(data, msg->len);
        *ofs += msg->len;
-       return 1;
+       return 1;
 }
 
 static imap_server_conf_t server =
@@ -1283,26 +1257,26 @@ git_imap_config(const char *key, const char *val)
        key += sizeof imap_key - 1;
 
        if (!strcmp( "folder", key )) {
-               imap_folder = strdup( val );
+               imap_folder = xstrdup( val );
        } else if (!strcmp( "host", key )) {
                {
-                       if (!strncmp( "imap:", val, 5 ))
+                       if (!prefixcmp(val, "imap:"))
                                val += 5;
                        if (!server.port)
                                server.port = 143;
                }
-               if (!strncmp( "//", val, 2 ))
+               if (!prefixcmp(val, "//"))
                        val += 2;
-               server.host = strdup( val );
+               server.host = xstrdup( val );
        }
        else if (!strcmp( "user", key ))
-               server.user = strdup( val );
+               server.user = xstrdup( val );
        else if (!strcmp( "pass", key ))
-               server.pass = strdup( val );
+               server.pass = xstrdup( val );
        else if (!strcmp( "port", key ))
                server.port = git_config_int( key, val );
        else if (!strcmp( "tunnel", key ))
-               server.tunnel = strdup( val );
+               server.tunnel = xstrdup( val );
        return 0;
 }
 
@@ -1310,7 +1284,7 @@ int
 main(int argc, char **argv)
 {
        msg_data_t all_msgs, msg;
-       store_t *ctx = 0;
+       store_t *ctx = NULL;
        int uid = 0;
        int ofs = 0;
        int r;
@@ -1332,6 +1306,12 @@ main(int argc, char **argv)
                return 1;
        }
 
+       total = count_messages( &all_msgs );
+       if (!total) {
+               fprintf(stderr,"no messages to send\n");
+               return 1;
+       }
+
        /* write it to the imap server */
        ctx = imap_open_store( &server );
        if (!ctx) {
@@ -1339,7 +1319,6 @@ main(int argc, char **argv)
                return 1;
        }
 
-       total = count_messages( &all_msgs );
        fprintf( stderr, "sending %d message%s\n", total, (total!=1)?"s":"" );
        ctx->name = imap_folder;
        while (1) {