/*
* 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 "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 <jasonday@worldnet.att.net> :
* * 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);
}
}
syntax highlighted by Code2HTML, v. 0.9.1