"Fossies" - the Fresh Open Source Software Archive

Member "netbiff-0.9.18/imap.c" (7 Feb 2005, 7378 Bytes) of package /linux/privat/old/netbiff-0.9.18.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 #include "imap.h"
    2 #include "util.h"
    3 
    4 #include <string.h>
    5 
    6 #include <openssl/err.h>
    7 #include <openssl/ssl.h>
    8 
    9 #define IMAP_DEFAULT_PORT 143
   10 #define IMAP_DEFAULT_SSL_PORT 993
   11 
   12 typedef void (*UntaggedCallback)(ImapContext *, char *, char *);
   13 
   14 void handle_ignore(ImapContext *c, char *resp, char *args) {
   15   return;
   16 }
   17 
   18 void handle_status(ImapContext *c, char *resp, char *args) {
   19   char *p;
   20 
   21   if(strcasecmp(resp, "STATUS"))
   22     return;
   23 
   24   if(!args)
   25     goto error;
   26 
   27   /* Kill the final close paren */
   28   p = args + strlen(args) - 1;
   29   *p = '\0';
   30 
   31   /* And then find the first one */
   32   p = strchr(args, '(');
   33   if(!p)
   34     goto error;
   35 
   36   p = strchr(p, ' ');
   37   if(!p)
   38     goto error;
   39 
   40   p++;
   41   c->recent = atoi(p);
   42   return;
   43 
   44 error:
   45   c->recent = 0;
   46 }
   47 
   48 static void imap_error(ImapContext *c, const char *fmt, ...) {
   49   va_list ap;
   50 
   51   c->error = 1;
   52 
   53   va_start(ap, fmt);
   54   vsnprintf(c->errstr, IMAP_BUFSIZE, fmt, ap);
   55   va_end(ap);
   56 }
   57 
   58 static void imap_serror(ImapContext *c, const char *fmt, ...) {
   59   va_list ap;
   60   char ssl_error[1024];
   61   char buf[IMAP_BUFSIZE];
   62 
   63   c->error =1;
   64 
   65   va_start(ap, fmt);
   66   vsnprintf(buf, IMAP_BUFSIZE, fmt, ap);
   67   va_end(ap);
   68 
   69   ERR_error_string(ERR_get_error(), ssl_error);
   70   snprintf(c->errstr, IMAP_BUFSIZE, "%s: %s", buf, ssl_error);
   71 }
   72 
   73 static void imap_close(ImapContext *c) {
   74   if(c->out) {
   75     BIO_puts(c->out, ". LOGOUT\r\n");
   76     BIO_free(c->out);
   77   }
   78   if(c->in)
   79     BIO_free(c->in);
   80   c->out = c->in = NULL;
   81 }
   82 
   83 static ImapContext *imap_new() {
   84   ImapContext *c;
   85 
   86   c = malloc(sizeof(ImapContext));
   87   if(!c)
   88     return NULL;
   89 
   90   c->in = c->out = NULL;
   91   c->error = 0;
   92   c->recent = 0;
   93   memset(c->buf, 0, IMAP_BUFSIZE);
   94   memset(c->errstr, 0, IMAP_BUFSIZE);
   95 
   96   return c;
   97 }
   98 
   99 static int imap_getline(ImapContext *c) {
  100   if(BIO_gets(c->in, c->buf, IMAP_BUFSIZE) < 0) {
  101     imap_serror(c, "read");
  102     imap_close(c);
  103     return -1;
  104   }
  105   return 0;
  106 }
  107 
  108 static int imap_command(ImapContext *c, UntaggedCallback ucb, 
  109     const char *fmt, ...) {
  110   va_list ap;
  111   BIO *b;
  112 
  113   va_start(ap, fmt);
  114 
  115   if(c->out)
  116     b = c->out;
  117   else
  118     b = c->in;
  119 
  120   BIO_puts(b, ". ");
  121   BIO_vprintf(b, fmt, ap);
  122   BIO_puts(b, "\r\n");
  123   BIO_flush(b);
  124 
  125   va_end(ap);
  126 
  127   while(1) {
  128     char *resp[3];
  129     int nresp;
  130 
  131     if(imap_getline(c) < 0)
  132       return -1;
  133 
  134     util_chomp(c->buf);
  135     nresp = util_split(" ", c->buf, resp, 3);
  136     if(nresp < 2) {
  137       imap_close(c);
  138       imap_error(c, "Confusing imap response: %s %s %s", nresp ? resp[0] : "",
  139           nresp > 1 ? resp[1] : "", nresp > 2 ? resp[2] : "");
  140       return -1;
  141     }
  142     if(!strcmp(resp[0], ".")) {
  143       if(!strcasecmp(resp[1], "OK"))
  144         return 1;
  145       else if(!strcasecmp(resp[1], "BAD"))
  146         return 0;
  147       else if(!strcasecmp(resp[1], "NO"))
  148         return 0;
  149       else {
  150         imap_close(c);
  151         imap_error(c, "Confusing imap response: %s %s %s", nresp ? resp[0] : "",
  152             nresp > 1 ? resp[1] : "", nresp > 2 ? resp[2] : "");
  153         return -1;
  154       }
  155     }
  156     else if(!strcmp(resp[0], "*")) 
  157       ucb(c, resp[1], resp[2]);
  158     else {
  159       imap_close(c);
  160       imap_error(c, "Confusing imap response: %s %s %s", nresp ? resp[0] : "",
  161           nresp > 1 ? resp[1] : "", nresp > 2 ? resp[2] : "");
  162       return -1;
  163     }
  164   }
  165 }
  166 
  167 static int imap_open_io(ImapContext *c, int use_ssl, int rfd, int wfd) {
  168   SSL_library_init();
  169   ERR_load_crypto_strings();
  170   ERR_load_SSL_strings();
  171 
  172   if(use_ssl) {
  173     SSL_CTX *ssl_ctx;
  174     BIO *bio;
  175 
  176     ssl_ctx = SSL_CTX_new(SSLv23_client_method());
  177     if(!ssl_ctx) {
  178       imap_serror(c, "Unable to initialize SSL context:");
  179       return -1;
  180     }
  181 
  182     c->in = BIO_new_socket(rfd, BIO_CLOSE);
  183     if(!c->in) {
  184       imap_serror(c, "BIO_new_socket");
  185       return -1;
  186     }
  187 
  188     bio = BIO_new_ssl(ssl_ctx, 1);
  189     if(!bio) {
  190       imap_serror(c, "BIO_new_ssl");
  191       return -1;
  192     }
  193     c->in = BIO_push(bio, c->in);
  194 
  195     bio = BIO_new(BIO_f_buffer());
  196     if(!bio) {
  197       imap_serror(c, "BIO_new_buffer");
  198       return -1;
  199     }
  200     c->in = BIO_push(bio, c->in);
  201   }
  202   else {
  203     c->in = BIO_new_socket(rfd, BIO_CLOSE);
  204     c->in = BIO_push(BIO_new(BIO_f_buffer()), c->in);
  205     if(wfd >= 0) {
  206       c->out = BIO_new_socket(wfd, BIO_CLOSE);
  207       c->out = BIO_push(BIO_new(BIO_f_buffer()), c->out);
  208     }
  209   }
  210 
  211   return 0;
  212 }
  213 
  214 ImapContext *imap_preauth(char * const cmd[]) {
  215   ImapContext *c;
  216   pid_t pid;
  217   int read, write;
  218   char *resp[3];
  219   int nresp;
  220 
  221   c = imap_new();
  222   if(!c)
  223     return NULL;
  224 
  225   pid = util_pipeto(cmd, &read, &write);
  226   if(!pid) {
  227     imap_error(c, "%s", strerror(errno));
  228     return c;
  229   }
  230 
  231   if(imap_open_io(c, 0, read, write) < 0)
  232     return c;
  233 
  234   if(imap_getline(c) < 0)
  235     return c;
  236   util_chomp(c->buf);
  237   nresp = util_split(" ", c->buf, resp, 3);
  238   if(nresp < 2 || strcmp(resp[0], "*") || strcasecmp(resp[1], "PREAUTH")) {
  239     imap_close(c);
  240     imap_error(c, "Unexpected preauth greeting: %s %s %s", 
  241         nresp ? resp[0] : "", nresp > 1 ? resp[1] : "", 
  242         nresp > 2 ? resp[2] : "");
  243     return c;
  244   }
  245 
  246   return c;
  247 }
  248 
  249 static int parse_host(const char *s, char **ret_host, int *use_ssl, 
  250     unsigned short *port) {
  251   char *port_string;
  252   char *ssl_string;
  253   char *host;
  254 
  255   *ret_host = host = strdup(s);
  256   if(!host)
  257     return -1;
  258   
  259   port_string = strchr(host, ':');
  260   if(port_string)
  261     *port_string++ = '\0';
  262 
  263   ssl_string = strchr(host, '/');
  264   if(ssl_string && !strcasecmp(ssl_string, "/ssl")) {
  265     *ssl_string = '\0';
  266     *use_ssl = 1;
  267   }
  268   else
  269     *use_ssl = 0;
  270 
  271   /* !! we should use one port and support STARTTLS */
  272   if(!port_string)
  273     *port = *use_ssl ? IMAP_DEFAULT_SSL_PORT : IMAP_DEFAULT_PORT;
  274   else
  275     *port = atoi(port_string);
  276 
  277   return 0;
  278 }
  279 
  280 ImapContext *imap_login(const char *host, const char *login, const char *pass) {
  281   ImapContext *c;
  282 
  283   int use_ssl;
  284   unsigned short port;
  285   char *hostname;
  286 
  287   int fd;
  288 
  289   char *resp[3];
  290   int nresp;
  291 
  292   c = imap_new();
  293   if(!c)
  294     return NULL;
  295 
  296   if(parse_host(host, &hostname, &use_ssl, &port) < 0) {
  297     imap_destroy(c);
  298     return NULL;
  299   }
  300 
  301   fd = util_iconnect(hostname, port);
  302   if(fd < 0) {
  303     if(fd < -1) {
  304 #ifdef HAVE_HSTRERROR
  305       imap_error(c, "Unable to resolve %s: %s", host, hstrerror(h_errno));
  306 #else
  307       imap_error(c, "Unable to resolve %s", host);
  308 #endif /* HAVE_STRERROR */
  309       return c;
  310     }
  311     else {
  312       imap_error(c, "Unable to connect to %s/%hu: %s", host, port, 
  313           strerror(errno));
  314       return c;
  315     }
  316   }
  317 
  318   if(imap_open_io(c, use_ssl, fd, -1) < 0)
  319     return c;
  320 
  321   if(imap_getline(c) < 0)
  322     return c;
  323   util_chomp(c->buf);
  324   nresp = util_split(" ", c->buf, resp, 3);
  325   if(nresp < 2 || strcmp(resp[0], "*") || strcasecmp(resp[1], "OK")) {
  326     imap_close(c);
  327     imap_error(c, "Unexpected IMAP greeting: %s %s %s", 
  328         nresp ? resp[0] : "", nresp > 1 ? resp[1] : "", 
  329         nresp > 2 ? resp[2] : "");
  330     return c;
  331   }
  332   
  333   switch(imap_command(c, handle_ignore, "LOGIN %s \"%s\"", login, pass)) {
  334     case -1:
  335       return c;
  336     case 0:
  337       imap_close(c);
  338       imap_error(c, "LOGIN command failed");
  339       return c;
  340     default:
  341       return c;
  342   }
  343 }
  344 
  345 void imap_destroy(ImapContext *c) {
  346   imap_close(c);
  347   free(c);
  348 }
  349 
  350 int imap_get_recent(ImapContext *c, const char *folder) {
  351   c->error = 0;
  352   switch(imap_command(c, handle_status, "STATUS %s (UNSEEN)", folder)) {
  353     case -1:
  354       return -1;
  355     case 0:
  356       return 0;
  357     default:
  358       return c->recent;
  359   }
  360 }
  361