"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. For more information about "imap.c" see the Fossies "Dox" file reference documentation.

    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