/* * asmail is the AfterStep mailbox monitor * Copyright (c) 2002 Albert Dorofeev * For the updates see http://www.tigr.net/ * * This software is distributed under GPL. For details see LICENSE file. */ #include #include #include #include #include #include "globals.h" #include "imap.h" #include "socklib.h" #define CREATE_OPEN_SOCK { \ if ( !( *sock = Sopen() ) ) { \ return STAT_FAIL; \ } \ s = *sock; \ \ if ( Sclient(s, mb->server, mb->port) == -1) { \ BYE(STAT_CONN); \ } \ } #define CHECK_GREETING { \ WAITOK; \ if ( strncmp(input, "* OK", 4) ) { \ BYE(STAT_CONN); \ } \ } #define BYE(RET_STATUS) { \ Sclose(s); \ *sock = NULL; \ return(RET_STATUS); \ } #ifdef HAVE_OPENSSL_SSL_H #define WRITE_OUTPUT { \ ret = (mb->flags & FLAG_SSL) && (s->ssl) ? \ Sslwrite(s, output) : Swrite(s->sd, output); \ if ( ret == -1 ) { \ BYE(STAT_CONN); \ } \ } #define WAITOK { \ ret = (mb->flags & FLAG_SSL) && (s->ssl) ? \ Sslread(s, input, MAX_INPUT_LENGTH, mb->timeout) : \ Sread(s->sd, input, MAX_INPUT_LENGTH, mb->timeout); \ \ switch (ret) { \ case -1: /* Error */ \ BYE(STAT_CONN); \ break; \ case 0: /* Timeout */ \ BYE(STAT_TIMEOUT); \ break; \ } \ } #else #define WRITE_OUTPUT { \ ret = Swrite(s->sd, output); \ if ( ret == -1 ) { \ BYE(STAT_CONN); \ } \ } #define WAITOK { \ ret = Sread(s->sd, input, MAX_INPUT_LENGTH, mb->timeout); \ switch (ret) { \ case -1: /* Error */ \ BYE(STAT_CONN); \ break; \ case 0: /* Timeout */ \ BYE(STAT_TIMEOUT); \ break; \ } \ } #endif int imap_login( struct mbox_struct * mb, SOCKET ** sock ) { int ret; char input[MAX_INPUT_LENGTH+1]; char output[MAX_INPUT_LENGTH+1]; SOCKET * s; CREATE_OPEN_SOCK; #ifdef HAVE_OPENSSL_SSL_H if ( (mb->flags & FLAG_SSL) && (Sslclient(s, mb->trustedCaDir) == -1) ) { /* no imaps server: * close the connection, try to re-connect and negotiate tls */ Sclose(s); s = NULL; CREATE_OPEN_SOCK; CHECK_GREETING; sprintf(output, "A000 STARTTLS\r\n"); WRITE_OUTPUT; WAITOK; if ( strncmp(input, "A000 OK", 7) ) { BYE(STAT_CONN); } if ( Sslclient(s, mb->trustedCaDir) == -1) { BYE(STAT_CONN); } } else { CHECK_GREETING; } #else CHECK_GREETING; #endif /* connection is open, let's log in */ sprintf(output, "A000 LOGIN %s %s\r\n", mb->user, mb->pass); WRITE_OUTPUT; WAITOK; if ( strncmp(input, "A000 OK", 7) ) { BYE(STAT_LOGIN); } return(STAT_IDLE); } int imap_checkmbox ( struct mbox_struct * mb, SOCKET ** sock ) { int ret; int ctotal = 0; int cnew = 0; char input[MAX_INPUT_LENGTH+1]; char output[MAX_INPUT_LENGTH+1]; char * tmp_str; SOCKET * s; s = *sock; if (mb->status != (STAT_IDLE | STAT_RUN)) return(mb->status); /* seems we are logged in, get statistics */ sprintf(output, "A001 STATUS %s (MESSAGES)\r\n", mb->mbox); WRITE_OUTPUT; WAITOK; if ( strncmp(input, "* STATUS", 8) ) { /* Notes 6 sends a different (non-standard?) response */ /* According to Jason Day : * * OK Domino IMAP4 Server Release 6.0.1 ready * A000 LOGIN xxx xxx * A000 OK LOGIN completed * A001 STATUS INBOX (MESSAGES) * * 10 EXISTS * * 0 RECENT * * STATUS INBOX (MESSAGES 10) * A001 OK STATUS completed */ if (strncmp (input, "* ", 2)) { BYE(STAT_CONN); } WAITOK; if (strncmp (input, "* ", 2)) { BYE(STAT_CONN); } WAITOK; if ( strncmp(input, "* STATUS", 8) ) { BYE(STAT_CONN); } } if ( (tmp_str = strstr(input, "MESSAGES")) ) { sscanf(tmp_str, "MESSAGES %d", &ctotal); } else { printf("asmail: imap_mailcheck: did not get MESSAGES in response to the STATUS.\n"); BYE(STAT_FAIL); } WAITOK; if ( strncmp(input, "A001 OK", 7) ) { BYE(STAT_CONN); } sprintf(output, "A002 STATUS %s (UNSEEN)\r\n", mb->mbox); WRITE_OUTPUT; WAITOK; if ( strncmp(input, "* STATUS", 8) ) { BYE(STAT_CONN); } if ( (tmp_str = strstr(input, "UNSEEN")) ) { sscanf(tmp_str, "UNSEEN %d", &cnew); } else { printf("asmail: imap_mailcheck: did not get UNSEEN in response to the STATUS.\n"); BYE(STAT_FAIL); } WAITOK; if ( strncmp(input, "A002 OK", 7) ) { BYE(STAT_CONN); } if ( (mb->cnew != cnew) && (cnew != 0) ) { pthread_mutex_lock(&mb->mutex); mb->flags |= FLAG_ARRIVED; pthread_mutex_unlock(&mb->mutex); } mb->cnew = cnew; mb->ctotal = ctotal; return(STAT_IDLE); } int imap_goodbye ( struct mbox_struct * mb, SOCKET ** sock ) { int ret; char input[MAX_INPUT_LENGTH+1]; char output[MAX_INPUT_LENGTH+1]; SOCKET * s; s = *sock; if (!s) return(mb->status); /* and good-bye */ sprintf(output, "A004 LOGOUT\r\n"); WRITE_OUTPUT; WAITOK; if ( strncmp(input, "* BYE", 5) ) { BYE(STAT_CONN); } Sclose(*sock); *sock = NULL; return(STAT_IDLE); } void imap_handle( struct mbox_struct * mb ) { SOCKET * s; /* Sanity check */ if ( mb->type != MBOX_IMAP ) { printf("asmail: imap_handle: Cowardly refusing to work with a non-IMAP server.\n"); mb->status = STAT_FAIL; pthread_exit(NULL); } if ( ! strlen(mb->server) ) { printf("asmail: imap_handle: no server name specified!\n"); mb->status = STAT_FAIL; pthread_exit(NULL); } if ( ! strlen(mb->user) ) { printf("asmail: imap_handle: no user name specified!\n"); mb->status = STAT_FAIL; pthread_exit(NULL); } if ( mb->port == 0 ) { mb->port = (mb->flags & FLAG_SSL) ? PORT_IMAPS : PORT_IMAP; } if ( ! strlen(mb->mbox) ) strcpy(mb->mbox, IMAP_MAILBOX_DEFAULT); if ( mb->flags & FLAG_PERSISTENT_CONN ) mb->status = imap_login(mb, &s); while (1) { mb->status |= STAT_RUN; signal_update(); if ( mb->flags & FLAG_PERSISTENT_CONN ) { if ( (mb->status = imap_checkmbox(mb, &s)) ) { /* something failed - retry once */ mb->status = imap_goodbye(mb, &s); mb->status = imap_login(mb, &s) | imap_checkmbox(mb, &s); } } else { mb->status |= imap_login(mb, &s); mb->status |= imap_checkmbox(mb, &s); mb->status |= imap_goodbye(mb, &s); } mb->status &= ~STAT_RUN; if ( ! mb->status ) { mb->status = STAT_IDLE; if ( mb->cnew > 0) mb->mail = MAIL_NEW; else if ( mb->ctotal > 0 ) mb->mail = MAIL_OLD; else mb->mail = MAIL_NONE; } signal_update(); sleep_check(mb->update); } }