Back to index

citadel  8.12
Functions | Variables
serv_pop3.c File Reference
#include "sysdep.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <pwd.h>
#include <errno.h>
#include <sys/types.h>
#include <time.h>
#include <sys/wait.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#include <libcitadel.h>
#include "citadel.h"
#include "server.h"
#include "citserver.h"
#include "support.h"
#include "config.h"
#include "user_ops.h"
#include "database.h"
#include "msgbase.h"
#include "internet_addressing.h"
#include "serv_pop3.h"
#include "md5.h"
#include "ctdl_module.h"

Go to the source code of this file.

Functions

void pop3_cleanup_function (void)
void pop3_greeting (void)
void pop3s_greeting (void)
void pop3_user (char *argbuf)
void pop3_add_message (long msgnum, void *userdata)
int pop3_grab_mailbox (void)
void pop3_login (void)
void pop3_pass (char *argbuf)
void pop3_list (char *argbuf)
void pop3_stat (char *argbuf)
void pop3_retr (char *argbuf)
void pop3_top (char *argbuf)
void pop3_dele (char *argbuf)
void pop3_update (void)
void pop3_rset (char *argbuf)
void pop3_last (char *argbuf)
void pop3_capa (void)
void pop3_uidl (char *argbuf)
void pop3_stls (void)
void pop3_command_loop (void)
 CTDL_MODULE_INIT (pop3)

Variables

const char * CitadelServicePop3 = "POP3"
const char * CitadelServicePop3S = "POP3S"

Function Documentation

CTDL_MODULE_INIT ( pop3  )

Definition at line 664 of file serv_pop3.c.

{
       if(!threading)
       {
              CtdlRegisterServiceHook(config.c_pop3_port,
                                   NULL,
                                   pop3_greeting,
                                   pop3_command_loop,
                                   NULL,
                                   CitadelServicePop3);
#ifdef HAVE_OPENSSL
              CtdlRegisterServiceHook(config.c_pop3s_port,
                                   NULL,
                                   pop3s_greeting,
                                   pop3_command_loop,
                                   NULL,
                                   CitadelServicePop3S);
#endif
              CtdlRegisterSessionHook(pop3_cleanup_function, EVT_STOP, PRIO_STOP + 30);
       }
       
       /* return our module name for the log */
       return "pop3";
}

Here is the call graph for this function:

void pop3_add_message ( long  msgnum,
void *  userdata 
)

Definition at line 151 of file serv_pop3.c.

                                                   {
       struct MetaData smi;

       ++POP3->num_msgs;
       if (POP3->num_msgs < 2) POP3->msgs = malloc(sizeof(struct pop3msg));
       else POP3->msgs = realloc(POP3->msgs, 
              (POP3->num_msgs * sizeof(struct pop3msg)) ) ;
       POP3->msgs[POP3->num_msgs-1].msgnum = msgnum;
       POP3->msgs[POP3->num_msgs-1].deleted = 0;

       /* We need to know the length of this message when it is printed in
        * RFC822 format.  Perhaps we have cached this length in the message's
        * metadata record.  If so, great; if not, measure it and then cache
        * it for next time.
        */
       GetMetaData(&smi, msgnum);
       if (smi.meta_rfc822_length <= 0L) {
              CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
              CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 1, NULL, SUPPRESS_ENV_TO);
              smi.meta_rfc822_length = StrLength(CC->redirect_buffer);
              FreeStrBuf(&CC->redirect_buffer); /* TODO: WHEW, all this for just knowing the length???? */
              PutMetaData(&smi);
       }
       POP3->msgs[POP3->num_msgs-1].rfc822_length = smi.meta_rfc822_length;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_capa ( void  )

Definition at line 480 of file serv_pop3.c.

                     {
       cprintf("+OK Capability list follows\r\n"
              "TOP\r\n"
              "USER\r\n"
              "UIDL\r\n"
              "IMPLEMENTATION %s\r\n"
              ".\r\n"
              ,
              CITADEL
       );
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_cleanup_function ( void  )

Definition at line 79 of file serv_pop3.c.

                                 {

       /* Don't do this stuff if this is not a POP3 session! */
       if (CC->h_command_function != pop3_command_loop) return;

       syslog(LOG_DEBUG, "Performing POP3 cleanup hook");
       if (POP3->msgs != NULL) free(POP3->msgs);

       free(POP3);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_command_loop ( void  )

Definition at line 566 of file serv_pop3.c.

                             {
       char cmdbuf[SIZ];

       time(&CC->lastcmd);
       memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
       if (client_getln(cmdbuf, sizeof cmdbuf) < 1) {
              syslog(LOG_ERR, "POP3 client disconnected: ending session.");
              CC->kill_me = KILLME_CLIENT_DISCONNECTED;
              return;
       }
       if (!strncasecmp(cmdbuf, "PASS", 4)) {
              syslog(LOG_INFO, "POP3: PASS...");
       }
       else {
              syslog(LOG_INFO, "POP3: %s", cmdbuf);
       }
       while (strlen(cmdbuf) < 5) strcat(cmdbuf, " ");

       if (!strncasecmp(cmdbuf, "NOOP", 4)) {
              cprintf("+OK No operation.\r\n");
       }

       else if (!strncasecmp(cmdbuf, "CAPA", 4)) {
              pop3_capa();
       }

       else if (!strncasecmp(cmdbuf, "QUIT", 4)) {
              cprintf("+OK Goodbye...\r\n");
              pop3_update();
              CC->kill_me = KILLME_CLIENT_LOGGED_OUT;
              return;
       }

       else if (!strncasecmp(cmdbuf, "USER", 4)) {
              pop3_user(&cmdbuf[5]);
       }

       else if (!strncasecmp(cmdbuf, "PASS", 4)) {
              pop3_pass(&cmdbuf[5]);
       }

#ifdef HAVE_OPENSSL
       else if (!strncasecmp(cmdbuf, "STLS", 4)) {
              pop3_stls();
       }
#endif

       else if (!CC->logged_in) {
              cprintf("-ERR Not logged in.\r\n");
       }
       
       else if (CC->nologin) {
              cprintf("-ERR System busy, try later.\r\n");
              CC->kill_me = KILLME_NOLOGIN;
       }

       else if (!strncasecmp(cmdbuf, "LIST", 4)) {
              pop3_list(&cmdbuf[5]);
       }

       else if (!strncasecmp(cmdbuf, "STAT", 4)) {
              pop3_stat(&cmdbuf[5]);
       }

       else if (!strncasecmp(cmdbuf, "RETR", 4)) {
              pop3_retr(&cmdbuf[5]);
       }

       else if (!strncasecmp(cmdbuf, "DELE", 4)) {
              pop3_dele(&cmdbuf[5]);
       }

       else if (!strncasecmp(cmdbuf, "RSET", 4)) {
              pop3_rset(&cmdbuf[5]);
       }

       else if (!strncasecmp(cmdbuf, "UIDL", 4)) {
              pop3_uidl(&cmdbuf[5]);
       }

       else if (!strncasecmp(cmdbuf, "TOP", 3)) {
              pop3_top(&cmdbuf[4]);
       }

       else if (!strncasecmp(cmdbuf, "LAST", 4)) {
              pop3_last(&cmdbuf[4]);
       }

       else {
              cprintf("-ERR I'm afraid I can't do that.\r\n");
       }

}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_dele ( char *  argbuf)

Definition at line 393 of file serv_pop3.c.

                             {
       int which_one;

       which_one = atoi(argbuf);
       if ( (which_one < 1) || (which_one > POP3->num_msgs) ) {
              cprintf("-ERR No such message.\r\n");
              return;
       }

       if (POP3->msgs[which_one - 1].deleted) {
              cprintf("-ERR You already deleted that message.\r\n");
              return;
       }

       /* Flag the message as deleted.  Will expunge during QUIT command. */
       POP3->msgs[which_one - 1].deleted = 1;
       cprintf("+OK Message %d deleted.\r\n",
              which_one);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int pop3_grab_mailbox ( void  )

Definition at line 184 of file serv_pop3.c.

                            {
        visit vbuf;
       int i;

       if (CtdlGetRoom(&CC->room, MAILROOM) != 0) return(-1);

       /* Load up the messages */
       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
              pop3_add_message, NULL);

       /* Figure out which are old and which are new */
        CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
       POP3->lastseen = (-1);
       if (POP3->num_msgs) for (i=0; i<POP3->num_msgs; ++i) {
              if (is_msg_in_sequence_set(vbuf.v_seen,
                 (POP3->msgs[POP3->num_msgs-1].msgnum) )) {
                     POP3->lastseen = i;
              }
       }

       return(POP3->num_msgs);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_greeting ( void  )

Definition at line 95 of file serv_pop3.c.

                         {
       strcpy(CC->cs_clientname, "POP3 session");
       CC->internal_pgm = 1;
       CC->session_specific_data = malloc(sizeof(struct citpop3));
       memset(POP3, 0, sizeof(struct citpop3));

       cprintf("+OK Citadel POP3 server ready.\r\n");
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_last ( char *  argbuf)

Definition at line 471 of file serv_pop3.c.

                             {
       cprintf("+OK %d\r\n", POP3->lastseen + 1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_list ( char *  argbuf)

Definition at line 247 of file serv_pop3.c.

                             {
       int i;
       int which_one;

       which_one = atoi(argbuf);

       /* "list one" mode */
       if (which_one > 0) {
              if (which_one > POP3->num_msgs) {
                     cprintf("-ERR no such message, only %d are here\r\n",
                            POP3->num_msgs);
                     return;
              }
              else if (POP3->msgs[which_one-1].deleted) {
                     cprintf("-ERR Sorry, you deleted that message.\r\n");
                     return;
              }
              else {
                     cprintf("+OK %d %ld\r\n",
                            which_one,
                            (long)POP3->msgs[which_one-1].rfc822_length
                            );
                     return;
              }
       }

       /* "list all" (scan listing) mode */
       else {
              cprintf("+OK Here's your mail:\r\n");
              if (POP3->num_msgs > 0) for (i=0; i<POP3->num_msgs; ++i) {
                     if (! POP3->msgs[i].deleted) {
                            cprintf("%d %ld\r\n",
                                   i+1,
                                   (long)POP3->msgs[i].rfc822_length);
                     }
              }
              cprintf(".\r\n");
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_login ( void  )

Definition at line 207 of file serv_pop3.c.

{
       int msgs;
       
       msgs = pop3_grab_mailbox();
       if (msgs >= 0) {
              cprintf("+OK %s is logged in (%d messages)\r\n",
                     CC->user.fullname, msgs);
              syslog(LOG_NOTICE, "POP3 authenticated %s", CC->user.fullname);
       }
       else {
              cprintf("-ERR Can't open your mailbox\r\n");
       }
       
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_pass ( char *  argbuf)

Definition at line 227 of file serv_pop3.c.

                             {
       char password[SIZ];

       safestrncpy(password, argbuf, sizeof password);
       striplt(password);

       /* syslog(LOG_DEBUG, "Trying <%s>", password); */
       if (CtdlTryPassword(password, strlen(password)) == pass_ok) {
              pop3_login();
       }
       else {
              cprintf("-ERR That is NOT the password.\r\n");
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_retr ( char *  argbuf)

Definition at line 311 of file serv_pop3.c.

                             {
       int which_one;

       which_one = atoi(argbuf);
       if ( (which_one < 1) || (which_one > POP3->num_msgs) ) {
              cprintf("-ERR No such message.\r\n");
              return;
       }

       if (POP3->msgs[which_one - 1].deleted) {
              cprintf("-ERR Sorry, you deleted that message.\r\n");
              return;
       }

       cprintf("+OK Message %d:\r\n", which_one);
       CtdlOutputMsg(POP3->msgs[which_one - 1].msgnum,
              MT_RFC822, HEADERS_ALL, 0, 1, NULL,
              (ESC_DOT|SUPPRESS_ENV_TO)
       );
       cprintf(".\r\n");
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_rset ( char *  argbuf)

Definition at line 455 of file serv_pop3.c.

                             {
       int i;

       if (POP3->num_msgs > 0) for (i=0; i<POP3->num_msgs; ++i) {
              if (POP3->msgs[i].deleted) {
                     POP3->msgs[i].deleted = 0;
              }
       }
       cprintf("+OK Reset completed.\r\n");
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_stat ( char *  argbuf)

Definition at line 291 of file serv_pop3.c.

                             {
       int total_msgs = 0;
       size_t total_octets = 0;
       int i;
       
       if (POP3->num_msgs > 0) for (i=0; i<POP3->num_msgs; ++i) {
              if (! POP3->msgs[i].deleted) {
                     ++total_msgs;
                     total_octets += POP3->msgs[i].rfc822_length;
              }
       }

       cprintf("+OK %d %ld\r\n", total_msgs, (long)total_octets);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_stls ( void  )

Definition at line 542 of file serv_pop3.c.

{
       char ok_response[SIZ];
       char nosup_response[SIZ];
       char error_response[SIZ];

       sprintf(ok_response,
              "+OK Begin TLS negotiation now\r\n");
       sprintf(nosup_response,
              "-ERR TLS not supported here\r\n");
       sprintf(error_response,
              "-ERR Internal error\r\n");
       CtdlModuleStartCryptoMsgs(ok_response, nosup_response, error_response);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_top ( char *  argbuf)

Definition at line 337 of file serv_pop3.c.

                            {
       int which_one;
       int lines_requested = 0;
       int lines_dumped = 0;
       char buf[1024];
       StrBuf *msgtext;
       const char *ptr;
       int in_body = 0;
       int done = 0;

       sscanf(argbuf, "%d %d", &which_one, &lines_requested);
       if ( (which_one < 1) || (which_one > POP3->num_msgs) ) {
              cprintf("-ERR No such message.\r\n");
              return;
       }

       if (POP3->msgs[which_one - 1].deleted) {
              cprintf("-ERR Sorry, you deleted that message.\r\n");
              return;
       }

       CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
       CtdlOutputMsg(POP3->msgs[which_one - 1].msgnum, MT_RFC822, HEADERS_ALL, 0, 1, NULL, SUPPRESS_ENV_TO);
       msgtext = CC->redirect_buffer;
       CC->redirect_buffer = NULL;

       cprintf("+OK Message %d:\r\n", which_one);
       
       ptr = ChrPtr(msgtext);
       while (ptr = cmemreadline(ptr, buf, (sizeof buf - 2)),
             ( (*ptr != 0) && (done == 0))) {
              strcat(buf, "\r\n");
              if (in_body == 1) {
                     if (lines_dumped >= lines_requested) {
                            done = 1;
                     }
              }
              if ((in_body == 0) || (done == 0)) {
                     client_write(buf, strlen(buf));
              }
              if (in_body) {
                     ++lines_dumped;
              }
              if ((buf[0]==13)||(buf[0]==10)) in_body = 1;
       }

       if (buf[strlen(buf)-1] != 10) cprintf("\n");
       FreeStrBuf(&msgtext);

       cprintf(".\r\n");
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_uidl ( char *  argbuf)

Definition at line 498 of file serv_pop3.c.

                             {
       int i;
       int which_one;

       which_one = atoi(argbuf);

       /* "list one" mode */
       if (which_one > 0) {
              if (which_one > POP3->num_msgs) {
                     cprintf("-ERR no such message, only %d are here\r\n",
                            POP3->num_msgs);
                     return;
              }
              else if (POP3->msgs[which_one-1].deleted) {
                     cprintf("-ERR Sorry, you deleted that message.\r\n");
                     return;
              }
              else {
                     cprintf("+OK %d %ld\r\n",
                            which_one,
                            POP3->msgs[which_one-1].msgnum
                            );
                     return;
              }
       }

       /* "list all" (scan listing) mode */
       else {
              cprintf("+OK Here's your mail:\r\n");
              if (POP3->num_msgs > 0) for (i=0; i<POP3->num_msgs; ++i) {
                     if (! POP3->msgs[i].deleted) {
                            cprintf("%d %ld\r\n",
                                   i+1,
                                   POP3->msgs[i].msgnum);
                     }
              }
              cprintf(".\r\n");
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_update ( void  )

Definition at line 416 of file serv_pop3.c.

                       {
       int i;
        visit vbuf;

       long *deletemsgs = NULL;
       int num_deletemsgs = 0;

       /* Remove messages marked for deletion */
       if (POP3->num_msgs > 0) {
              deletemsgs = malloc(POP3->num_msgs * sizeof(long));
              for (i=0; i<POP3->num_msgs; ++i) {
                     if (POP3->msgs[i].deleted) {
                            deletemsgs[num_deletemsgs++] = POP3->msgs[i].msgnum;
                     }
              }
              if (num_deletemsgs > 0) {
                     CtdlDeleteMessages(MAILROOM, deletemsgs, num_deletemsgs, "");
              }
              free(deletemsgs);
       }

       /* Set last read pointer */
       if (POP3->num_msgs > 0) {
              CtdlGetUserLock(&CC->user, CC->curr_user);

              CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
              snprintf(vbuf.v_seen, sizeof vbuf.v_seen, "*:%ld",
                     POP3->msgs[POP3->num_msgs-1].msgnum);
              CtdlSetRelationship(&vbuf, &CC->user, &CC->room);

              CtdlPutUserLock(&CC->user);
       }

}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3_user ( char *  argbuf)

Definition at line 126 of file serv_pop3.c.

                             {
       char username[SIZ];

       if (CC->logged_in) {
              cprintf("-ERR You are already logged in.\r\n");
              return;
       }

       strcpy(username, argbuf);
       striplt(username);

       /* syslog(LOG_DEBUG, "Trying <%s>", username); */
       if (CtdlLoginExistingUser(NULL, username) == login_ok) {
              cprintf("+OK Password required for %s\r\n", username);
       }
       else {
              cprintf("-ERR No such user.\r\n");
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pop3s_greeting ( void  )

Definition at line 108 of file serv_pop3.c.

                          {
       CtdlModuleStartCryptoMsgs(NULL, NULL, NULL);

/* kill session if no crypto */
#ifdef HAVE_OPENSSL
       if (!CC->redirect_ssl) CC->kill_me = KILLME_NO_CRYPTO;
#else
       CC->kill_me = KILLME_NO_CRYPTO;
#endif

       pop3_greeting();
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

const char* CitadelServicePop3 = "POP3"

Definition at line 660 of file serv_pop3.c.

const char* CitadelServicePop3S = "POP3S"

Definition at line 661 of file serv_pop3.c.