Define a built-in attribute macro "binary".
[gitweb.git] / imap-send.c
index fddaac00c0adea7347934b008da9b33e72fe5b5f..84df2fabb7f91d30f7617dd07202ed916c5f8eb1 100644 (file)
 
 #include "cache.h"
 
-#include <assert.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
 typedef struct store_conf {
        char *name;
        const char *path; /* should this be here? its interpretation is driver-specific */
@@ -92,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
@@ -102,14 +96,13 @@ 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, ... );
 
 
@@ -231,7 +224,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 );
+       int n = xread( sock->fd, buf, len );
        if (n <= 0) {
                socket_perror( "read", sock, n );
                close( sock->fd );
@@ -241,9 +234,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 );
@@ -272,7 +265,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;
@@ -304,7 +297,7 @@ buffer_gets( buffer_t * b, char **s )
 }
 
 static void
-info( const char *msg, ... )
+imap_info( const char *msg, ... )
 {
        va_list va;
 
@@ -317,7 +310,7 @@ info( const char *msg, ... )
 }
 
 static void
-warn( const char *msg, ... )
+imap_warn( const char *msg, ... )
 {
        va_list va;
 
@@ -334,12 +327,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;
@@ -354,7 +347,7 @@ next_arg( char **s )
                if (**s)
                        *(*s)++ = 0;
                if (!**s)
-                       *s = 0;
+                       *s = NULL;
        }
        return ret;
 }
@@ -370,21 +363,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, ... )
 {
@@ -398,15 +376,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;
@@ -421,7 +390,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 );
        }
@@ -474,7 +443,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",
@@ -505,12 +474,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++;
@@ -606,7 +575,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++;
@@ -679,11 +648,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;
 }
 
@@ -701,7 +670,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
@@ -788,7 +757,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 );
@@ -812,7 +781,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) {
@@ -848,7 +817,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;
                                                }
@@ -897,7 +866,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 );
@@ -923,6 +892,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 );
 
@@ -933,19 +903,22 @@ 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] );
                        close( a[1] );
-                       execl( "/bin/sh", "sh", "-c", srvc->tunnel, 0 );
+                       execl( "/bin/sh", "sh", "-c", srvc->tunnel, NULL );
                        _exit( 127 );
                }
 
@@ -953,31 +926,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;
 
@@ -1000,13 +973,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;
@@ -1027,14 +1000,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;
                }
@@ -1046,7 +1019,7 @@ imap_open_store( imap_server_conf_t *srvc )
 
   bail:
        imap_close_store( &ctx->gen );
-       return 0;
+       return NULL;
 }
 
 static int
@@ -1201,6 +1174,7 @@ read_message( FILE *f, msg_data_t *msg )
                        p = xrealloc(msg->data, len+1);
                        if (!p)
                                break;
+                       msg->data = p;
                }
                r = fread( &msg->data[msg->len], 1, len - msg->len, f );
                if (r <= 0)
@@ -1218,7 +1192,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;
                }
@@ -1242,9 +1216,17 @@ 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;
@@ -1282,26 +1264,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;
 }
 
@@ -1309,7 +1291,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;
@@ -1331,6 +1313,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) {
@@ -1338,7 +1326,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) {