/*
* asmail is the AfterStep mailbox monitor
* Copyright (c) 2002 Albert Dorofeev <albert@tigr.net>
* For the updates see http://www.tigr.net/
*
* This software is distributed under GPL. For details see LICENSE file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include "config.h"
#ifdef HAVE_OPENSSL_SSL_H
#include <openssl/md5.h>
#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; i<MD5_DIGEST_LENGTH; ++i) {
sprintf(str_target, "%02x",
(unsigned char)md5_digest[i]);
str_target += 2;
}
str_target[MD5_DIGEST_LENGTH*2] = '\0';
/* Login into the server with MD5 hash */
sprintf(output, "APOP %s %s\r\n", mb->user, 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);
}
}
syntax highlighted by Code2HTML, v. 0.9.1