/* * 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 "config.h" #ifdef HAVE_OPENSSL_SSL_H #include #else #include "md5.h" #define MD5_DIGEST_LENGTH 16 #endif #include "globals.h" #include "pop3.h" #include "socklib.h" #define ACK_MSG "+OK" #define BYE(RET_STATUS) { \ Sclose(s); \ return(RET_STATUS); \ } #define WAITOK { \ switch (Sread(s->sd, input, MAX_INPUT_LENGTH, mb->timeout)) { \ case -1: /* Error */ \ BYE(STAT_CONN); \ case 0: /* Timeout */ \ BYE(STAT_TIMEOUT); \ } \ sscanf(input, "%5s", key); \ } #define SENDOK { \ if ( Swrite(s->sd, output) == -1 ) { \ BYE(STAT_CONN); \ } \ } int pop3_mailcheck( struct mbox_struct * mb ) { SOCKET * s; char input[MAX_INPUT_LENGTH+1]; char output[MAX_INPUT_LENGTH+1]; char key[MAX_INPUT_LENGTH+1]; int ctotal; char md5_digest[MD5_DIGEST_LENGTH]; char * str_ptr; char * str_end; char * str_target; int i; #ifndef HAVE_OPENSSL_SSL_H MD5_CTX mdc; #endif if ( !( s = Sopen() ) ) { return STAT_FAIL; } if ( Sclient(s, mb->server, mb->port) == -1 ) { BYE(STAT_CONN); } /* Once we connect, we should receive the greeting */ WAITOK; if ( strcmp(key, ACK_MSG) ) { BYE(STAT_CONN); } /* Check if the server supports MD5 */ if ( (mb->auth & AUTH_MD5) && (str_ptr = strchr(input, '<')) && strchr(input, '@') && (str_end = strchr(input, '>')) && (str_ptr < str_end) ) { str_target = key; while ( str_ptr <= str_end ) { *str_target++ = *str_ptr++; } *str_target = '\0'; strcat(key, mb->pass); pthread_mutex_lock(&md5_lock); #ifdef HAVE_OPENSSL_SSL_H MD5((unsigned char *)key, strlen(key), (unsigned char *)md5_digest); #else MD5Init(&mdc); MD5Update(&mdc, key, strlen(key)); MD5Final(md5_digest, &mdc); #endif pthread_mutex_unlock(&md5_lock); /* basically sprintf(key, "%x", md5_digest); */ str_target = key; for ( i=0; iuser, key); SENDOK; WAITOK; if ( strcmp(key, ACK_MSG) ) { sprintf(output, "QUIT\r\n"); SENDOK; BYE(STAT_LOGIN); } } else if ( mb->auth & AUTH_PLAIN) { /* Login into the server with password in clear */ sprintf(output, "USER %s\r\n", mb->user); SENDOK; WAITOK; if ( strcmp(key, ACK_MSG) ) { sprintf(output, "QUIT\r\n"); SENDOK; BYE(STAT_LOGIN); } sprintf(output, "PASS %s\r\n", mb->pass); SENDOK; WAITOK; if ( strcmp(key, ACK_MSG) ) { sprintf(output, "QUIT\r\n"); SENDOK; BYE(STAT_LOGIN); } } else { /* requested login method unsupported */ printf("asmail: pop3_mailcheck: specified login method is unsupported by POP server.\n"); sprintf(output, "QUIT\r\n"); SENDOK; BYE(STAT_LOGIN); } /* seems we are logged in, get statistics */ sprintf(output, "STAT\r\n"); SENDOK; WAITOK; if ( strcmp(key, ACK_MSG) ) { BYE(STAT_CONN); } sprintf(output, "%s %s", ACK_MSG, "%d"); sscanf(input, output, &ctotal); /* and good-bye */ sprintf(output, "QUIT\r\n"); SENDOK; WAITOK; if ( strcmp(key, ACK_MSG) ) { BYE(STAT_CONN); } Sclose(s); /* Ok, now some tricks to figure out of we have new * messages. Basically, we have only the total number * of messages but, what the heck, we can do some * dirty tricks, right? */ if ( ctotal == mb->ctotal ) { /* Ok, assume nothing has changed, although * it is quite possible that some mail was * deleted and some has arrived in exactly * the same quantities. Well, too bad. */ return(STAT_IDLE); } if ( ctotal > mb->ctotal ) { /* we probably got more new mail */ mb->cnew += ctotal - mb->ctotal; mb->ctotal = ctotal; pthread_mutex_lock(&mb->mutex); mb->flags |= FLAG_ARRIVED; pthread_mutex_unlock(&mb->mutex); } else { /* right, you may have read and deleted * some messages and, maybe, there are * new ones but I would not know... */ mb->cnew = 0; mb->ctotal = ctotal; } return(STAT_IDLE); } void pop3_handle( struct mbox_struct * mb ) { /* Sanity check */ if ( mb->type != MBOX_POP3 ) { printf("asmail: pop3_handle: Cowardly refusing to work with a non-POP3 server.\n"); mb->status = STAT_FAIL; pthread_exit(NULL); } if ( ! strlen(mb->server) ) { printf("asmail: pop3_handle: no server name specified!\n"); mb->status = STAT_FAIL; pthread_exit(NULL); } if ( ! strlen(mb->user) ) { printf("asmail: pop3_handle: no user name specified!\n"); mb->status = STAT_FAIL; pthread_exit(NULL); } if ( mb->port == 0 ) mb->port = PORT_POP3; while (1) { mb->status |= STAT_RUN; signal_update(); if ( ! ( mb->status = pop3_mailcheck(mb) ) ) { 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); } }