Back to index

citadel  8.12
Classes | Defines | Typedefs | Enumerations | Functions | Variables
serv_imap.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  _imap_handler_hook
struct  __citimap_command
struct  __citimap

Defines

#define GLOBAL_UIDVALIDITY_VALUE   1L
#define IMAP_ANSWERED   1 /* reportable and setable */
#define IMAP_FLAGGED   2 /* reportable and setable */
#define IMAP_DELETED   4 /* reportable and setable */
#define IMAP_DRAFT   8 /* reportable and setable */
#define IMAP_SEEN   16 /* reportable and setable */
#define IMAP_MASK_SETABLE   0x1f
#define IMAP_MASK_SYSTEM   0xe0
#define IMAP_SELECTED   32 /* neither reportable nor setable */
#define IMAP_RECENT   64 /* reportable but not setable */
#define IR_MAILBOX   0x0100 /* Mailbox */
#define IR_EXISTS   0x0200 /* Room exists (not implemented) */
#define IR_BABOON   0x0000 /* Just had to put this here :) */
#define FDELIM   '\\'
#define IMAP   ((citimap *)CC->session_specific_data)
#define CCCIMAP   ((citimap *)CCC->session_specific_data)
#define IMAPDBGLOG(LEVEL)   if ((LEVEL != LOG_DEBUG) || (IMAPDebugEnabled != 0))
#define CCCID   CCC->cs_pid
#define IMAP_syslog(LEVEL, FORMAT,...)
#define IMAPM_syslog(LEVEL, FORMAT)
#define I_FLAG_NONE   (0)
#define I_FLAG_LOGGED_IN   (1<<0)
#define I_FLAG_SELECT   (1<<1)
#define I_FLAG_UNTAGGED   (1<<2)
#define REALLOC_INCREMENT   100
#define RegisterImapCMD(First, Second, H, Flags)   registerImapCMD(HKEY(First), HKEY(Second), H, Flags)

Typedefs

typedef void(* imap_handler )(int num_parms, ConstStr *Params)
typedef struct _imap_handler_hook imap_handler_hook
typedef struct __citimap_command citimap_command
typedef struct __citimap citimap

Enumerations

enum  {
  imap_as_normal, imap_as_expecting_username, imap_as_expecting_password, imap_as_expecting_plainauth,
  imap_as_expecting_multilineusername, imap_as_expecting_multilinepassword
}

Functions

void imap_cleanup_function (void)
void imap_greeting (void)
void imap_command_loop (void)
int imap_grabroom (char *returned_roomname, const char *foldername, int zapped_ok)
void imap_free_transmitted_message (void)
int imap_do_expunge (void)
void imap_rescan_msgids (void)
void registerImapCMD (const char *First, long FLen, const char *Second, long SLen, imap_handler H, int Flags)

Variables

int IMAPDebugEnabled

Class Documentation

struct _imap_handler_hook

Definition at line 23 of file serv_imap.h.

Class Members
int Flags
imap_handler h
struct __citimap_command

Definition at line 28 of file serv_imap.h.

Collaboration diagram for __citimap_command:
Class Members
int avail_parms
StrBuf * CmdBuf
const imap_handler_hook * hh
int num_parms
ConstStr * Params
struct __citimap

Definition at line 37 of file serv_imap.h.

Collaboration diagram for __citimap:
Class Members
char authseq
int authstate
char * cached_body
size_t cached_body_len
char cached_body_withbody
long cached_bodymsgnum
char cached_bodypart
StrBuf * cached_rfc822
long cached_rfc822_msgnum
char cached_rfc822_withbody
citimap_command Cmd
unsigned int * flags
time_t last_mtime
long * msgids
int num_alloc
int num_msgs
int readonly
StrBuf * Reply
int selected
StrBuf * TransmittedMessage

Define Documentation

#define CCCID   CCC->cs_pid

Definition at line 110 of file serv_imap.h.

#define CCCIMAP   ((citimap *)CCC->session_specific_data)

Definition at line 107 of file serv_imap.h.

#define FDELIM   '\\'

Definition at line 102 of file serv_imap.h.

#define GLOBAL_UIDVALIDITY_VALUE   1L

Definition at line 1 of file serv_imap.h.

#define I_FLAG_LOGGED_IN   (1<<0)

Definition at line 122 of file serv_imap.h.

#define I_FLAG_NONE   (0)

Definition at line 121 of file serv_imap.h.

#define I_FLAG_SELECT   (1<<1)

Definition at line 123 of file serv_imap.h.

#define I_FLAG_UNTAGGED   (1<<2)

Definition at line 125 of file serv_imap.h.

#define IMAP   ((citimap *)CC->session_specific_data)

Definition at line 106 of file serv_imap.h.

#define IMAP_ANSWERED   1 /* reportable and setable */

Definition at line 81 of file serv_imap.h.

#define IMAP_DELETED   4 /* reportable and setable */

Definition at line 83 of file serv_imap.h.

#define IMAP_DRAFT   8 /* reportable and setable */

Definition at line 84 of file serv_imap.h.

#define IMAP_FLAGGED   2 /* reportable and setable */

Definition at line 82 of file serv_imap.h.

#define IMAP_MASK_SETABLE   0x1f

Definition at line 87 of file serv_imap.h.

#define IMAP_MASK_SYSTEM   0xe0

Definition at line 88 of file serv_imap.h.

#define IMAP_RECENT   64 /* reportable but not setable */

Definition at line 91 of file serv_imap.h.

#define IMAP_SEEN   16 /* reportable and setable */

Definition at line 85 of file serv_imap.h.

#define IMAP_SELECTED   32 /* neither reportable nor setable */

Definition at line 90 of file serv_imap.h.

#define IMAP_syslog (   LEVEL,
  FORMAT,
  ... 
)
Value:
IMAPDBGLOG(LEVEL) syslog(LEVEL,                  \
                             "IMAPCC[%d] " FORMAT,      \
                             CCCID, __VA_ARGS__)

Definition at line 111 of file serv_imap.h.

#define IMAPDBGLOG (   LEVEL)    if ((LEVEL != LOG_DEBUG) || (IMAPDebugEnabled != 0))

Definition at line 109 of file serv_imap.h.

#define IMAPM_syslog (   LEVEL,
  FORMAT 
)
Value:
IMAPDBGLOG(LEVEL) syslog(LEVEL,                  \
                             "IMAPCC[%d] " FORMAT,      \
                             CCCID)

Definition at line 116 of file serv_imap.h.

#define IR_BABOON   0x0000 /* Just had to put this here :) */

Definition at line 100 of file serv_imap.h.

#define IR_EXISTS   0x0200 /* Room exists (not implemented) */

Definition at line 99 of file serv_imap.h.

#define IR_MAILBOX   0x0100 /* Mailbox */

Definition at line 98 of file serv_imap.h.

#define REALLOC_INCREMENT   100

Definition at line 131 of file serv_imap.h.

#define RegisterImapCMD (   First,
  Second,
  H,
  Flags 
)    registerImapCMD(HKEY(First), HKEY(Second), H, Flags)

Definition at line 139 of file serv_imap.h.


Typedef Documentation

typedef struct __citimap citimap
typedef void(* imap_handler)(int num_parms, ConstStr *Params)

Definition at line 21 of file serv_imap.h.


Enumeration Type Documentation

anonymous enum
Enumerator:
imap_as_normal 
imap_as_expecting_username 
imap_as_expecting_password 
imap_as_expecting_plainauth 
imap_as_expecting_multilineusername 
imap_as_expecting_multilinepassword 

Definition at line 69 of file serv_imap.h.


Function Documentation

void imap_cleanup_function ( void  )

Definition at line 479 of file serv_imap.c.

{
       struct CitContext *CCC = CC;
       citimap *Imap = CCCIMAP;

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

       /* If there is a mailbox selected, auto-expunge it. */
       if (Imap->selected) {
              imap_do_expunge();
       }

       IMAPM_syslog(LOG_DEBUG, "Performing IMAP cleanup hook");
       imap_free_msgids();
       imap_free_transmitted_message();

       if (Imap->cached_rfc822 != NULL) {
              FreeStrBuf(&Imap->cached_rfc822);
              Imap->cached_rfc822_msgnum = (-1);
              Imap->cached_rfc822_withbody = 0;
       }

       if (Imap->cached_body != NULL) {
              free(Imap->cached_body);
              Imap->cached_body = NULL;
              Imap->cached_body_len = 0;
              Imap->cached_bodymsgnum = (-1);
       }
       FreeStrBuf(&Imap->Cmd.CmdBuf);
       FreeStrBuf(&Imap->Reply);
       if (Imap->Cmd.Params != NULL) free(Imap->Cmd.Params);
       free(Imap);
       IMAPM_syslog(LOG_DEBUG, "Finished IMAP cleanup hook");
}

Here is the call graph for this function:

Here is the caller graph for this function:

void imap_command_loop ( void  )

Definition at line 1483 of file serv_imap.c.

{
       struct CitContext *CCC = CC;
       struct timeval tv1, tv2;
       suseconds_t total_time = 0;
       citimap *Imap;
       const char *pchs, *pche;
       const imap_handler_hook *h;

       gettimeofday(&tv1, NULL);
       CCC->lastcmd = time(NULL);
       Imap = CCCIMAP;

       flush_output();
       if (Imap->Cmd.CmdBuf == NULL)
              Imap->Cmd.CmdBuf = NewStrBufPlain(NULL, SIZ);
       else
              FlushStrBuf(Imap->Cmd.CmdBuf);

       if (CtdlClientGetLine(Imap->Cmd.CmdBuf) < 1) {
              IMAPM_syslog(LOG_ERR, "client disconnected: ending session.");
              CC->kill_me = KILLME_CLIENT_DISCONNECTED;
              return;
       }

       if (Imap->authstate == imap_as_expecting_password) {
              IMAPM_syslog(LOG_INFO, "<password>");
       }
       else if (Imap->authstate == imap_as_expecting_plainauth) {
              IMAPM_syslog(LOG_INFO, "<plain_auth>");
       }
       else if ((Imap->authstate == imap_as_expecting_multilineusername) || 
               cbmstrcasestr(ChrPtr(Imap->Cmd.CmdBuf), " LOGIN ")) {
              IMAPM_syslog(LOG_INFO, "LOGIN...");
       }
       else {
              IMAP_syslog(LOG_DEBUG, "%s", ChrPtr(Imap->Cmd.CmdBuf));
       }

       pchs = ChrPtr(Imap->Cmd.CmdBuf);
       pche = pchs + StrLength(Imap->Cmd.CmdBuf);

       while ((pche > pchs) &&
              ((*pche == '\n') ||
              (*pche == '\r')))
       {
              pche --;
              StrBufCutRight(Imap->Cmd.CmdBuf, 1);
       }
       StrBufTrim(Imap->Cmd.CmdBuf);

       /* If we're in the middle of a multi-line command, handle that */
       switch (Imap->authstate){
       case imap_as_expecting_username:
              imap_auth_login_user(imap_as_expecting_username);
              IUnbuffer();
              return;
       case imap_as_expecting_multilineusername:
              imap_auth_login_user(imap_as_expecting_multilineusername);
              IUnbuffer();
              return;
       case imap_as_expecting_plainauth:
              imap_auth_plain();
              IUnbuffer();
              return;
       case imap_as_expecting_password:
              imap_auth_login_pass(imap_as_expecting_password);
              IUnbuffer();
              return;
       case imap_as_expecting_multilinepassword:
              imap_auth_login_pass(imap_as_expecting_multilinepassword);
              IUnbuffer();
              return;
       default:
              break;
       }

       /* Ok, at this point we're in normal command mode.
        * If the command just submitted does not contain a literal, we
        * might think about delivering some untagged stuff...
        */

       /* Grab the tag, command, and parameters. */
       imap_parameterize(&Imap->Cmd);
#if 0 
/* debug output the parsed vector */
       {
              int i;
              IMAP_syslog(LOG_DEBUG, "----- %ld params", Imap->Cmd.num_parms);

       for (i=0; i < Imap->Cmd.num_parms; i++) {
              if (Imap->Cmd.Params[i].len != strlen(Imap->Cmd.Params[i].Key))
                     IMAP_syslog(LOG_DEBUG, "*********** %ld != %ld : %s",
                                Imap->Cmd.Params[i].len, 
                                strlen(Imap->Cmd.Params[i].Key),
                                  Imap->Cmd.Params[i].Key);
              else
                     IMAP_syslog(LOG_DEBUG, "%ld : %s",
                                Imap->Cmd.Params[i].len, 
                                Imap->Cmd.Params[i].Key);
       }}
#endif

       /* Now for the command set. */
       h = imap_lookup(Imap->Cmd.num_parms, Imap->Cmd.Params);

       if (h == NULL)
       {
              IReply("BAD command unrecognized");
              goto BAIL;
       }

       /* RFC3501 says that we cannot output untagged data during these commands */
       if ((h->Flags & I_FLAG_UNTAGGED) == 0) {

              /* we can put any additional untagged stuff right here in the future */

              /*
               * Before processing the command that was just entered... if we happen
               * to have a folder selected, we'd like to rescan that folder for new
               * messages, and for deletions/changes of existing messages.  This
               * could probably be optimized better with some deep thought...
               */
              if (Imap->selected) {
                     imap_rescan_msgids();
              }
       }

       /* does our command require a logged-in state */
       if ((!CC->logged_in) && ((h->Flags & I_FLAG_LOGGED_IN) != 0)) {
              IReply("BAD Not logged in.");
              goto BAIL;
       }

       /* does our command require the SELECT state on a mailbox */
       if ((Imap->selected == 0) && ((h->Flags & I_FLAG_SELECT) != 0)){
              IReply("BAD no folder selected");
              goto BAIL;
       }
       h->h(Imap->Cmd.num_parms, Imap->Cmd.Params);

       /* If the client transmitted a message we can free it now */

BAIL:
       IUnbuffer();

       imap_free_transmitted_message();

       gettimeofday(&tv2, NULL);
       total_time = (tv2.tv_usec + (tv2.tv_sec * 1000000)) - (tv1.tv_usec + (tv1.tv_sec * 1000000));
       IMAP_syslog(LOG_DEBUG, "IMAP command completed in %ld.%ld seconds",
                  (total_time / 1000000),
                  (total_time % 1000000)
              );
}

Here is the call graph for this function:

Here is the caller graph for this function:

int imap_do_expunge ( void  )

Definition at line 916 of file serv_imap.c.

{
       struct CitContext *CCC = CC;
       citimap *Imap = CCCIMAP;
       int i;
       int num_expunged = 0;
       long *delmsgs = NULL;
       int num_delmsgs = 0;

       IMAPM_syslog(LOG_DEBUG, "imap_do_expunge() called");
       if (Imap->selected == 0) {
              return (0);
       }

       if (Imap->num_msgs > 0) {
              delmsgs = malloc(Imap->num_msgs * sizeof(long));
              for (i = 0; i < Imap->num_msgs; ++i) {
                     if (Imap->flags[i] & IMAP_DELETED) {
                            delmsgs[num_delmsgs++] = Imap->msgids[i];
                     }
              }
              if (num_delmsgs > 0) {
                     CtdlDeleteMessages(CC->room.QRname, delmsgs, num_delmsgs, "");
              }
              num_expunged += num_delmsgs;
              free(delmsgs);
       }

       if (num_expunged > 0) {
              imap_rescan_msgids();
       }

       IMAP_syslog(LOG_DEBUG, "Expunged %d messages from <%s>", num_expunged, CC->room.QRname);
       return (num_expunged);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 188 of file serv_imap.c.

{
       FreeStrBuf(&IMAP->TransmittedMessage);
}

Here is the caller graph for this function:

int imap_grabroom ( char *  returned_roomname,
const char *  foldername,
int  zapped_ok 
)

Definition at line 1103 of file serv_imap.c.

{
       int ret;
       char augmented_roomname[ROOMNAMELEN];
       char roomname[ROOMNAMELEN];
       int c;
       struct ctdlroom QRscratch;
       int ra;
       int ok = 0;

       ret = imap_roomname(roomname, sizeof roomname, foldername);
       if (ret < 0) {
              return (1);
       }

       /* First try a regular match */
       c = CtdlGetRoom(&QRscratch, roomname);

       /* Then try a mailbox name match */
       if (c != 0) {
              CtdlMailboxName(augmented_roomname, sizeof augmented_roomname,
                         &CC->user, roomname);
              c = CtdlGetRoom(&QRscratch, augmented_roomname);
              if (c == 0)
                     safestrncpy(roomname, augmented_roomname, sizeof(roomname));
       }

       /* If the room exists, check security/access */
       if (c == 0) {
              /* See if there is an existing user/room relationship */
              CtdlRoomAccess(&QRscratch, &CC->user, &ra, NULL);

              /* normal clients have to pass through security */
              if (ra & UA_KNOWN) {
                     ok = 1;
              }
              if ((zapped_ok) && (ra & UA_ZAPPED)) {
                     ok = 1;
              }
       }

       /* Fail here if no such room */
       if (!ok) {
              strcpy(returned_roomname, "");
              return (2);
       } else {
              safestrncpy(returned_roomname, QRscratch.QRname, ROOMNAMELEN);
              return (0);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void imap_greeting ( void  )

Definition at line 582 of file serv_imap.c.

{
       citimap *Imap;
       CitContext *CCC = CC;

       strcpy(CCC->cs_clientname, "IMAP session");
       CCC->session_specific_data = malloc(sizeof(citimap));
       Imap = (citimap *)CCC->session_specific_data;
       memset(Imap, 0, sizeof(citimap));
       Imap->authstate = imap_as_normal;
       Imap->cached_rfc822_msgnum = (-1);
       Imap->cached_rfc822_withbody = 0;
       Imap->Reply = NewStrBufPlain(NULL, SIZ * 10); /* 40k */

       if (CCC->nologin)
       {
              IAPuts("* BYE; Server busy, try later\r\n");
              CCC->kill_me = KILLME_NOLOGIN;
              IUnbuffer();
              return;
       }

       IAPuts("* OK [");
       imap_output_capability_string();
       IAPrintf("] %s IMAP4rev1 %s ready\r\n", config.c_fqdn, CITADEL);
       IUnbuffer();
}

Here is the call graph for this function:

Here is the caller graph for this function:

void imap_rescan_msgids ( void  )

Definition at line 342 of file serv_imap.c.

{
       struct CitContext *CCC = CC;
       citimap *Imap = CCCIMAP;
       int original_num_msgs = 0;
       long original_highest = 0L;
       int i, j, jstart;
       int message_still_exists;
       struct cdbdata *cdbfr;
       long *msglist = NULL;
       int num_msgs = 0;
       int num_recent = 0;

       if (Imap->selected == 0) {
              IMAPM_syslog(LOG_ERR, "imap_load_msgids() can't run; no room selected");
              return;
       }

       /*
        * Check to see if the room's contents have changed.
        * If not, we can avoid this rescan.
        */
       CtdlGetRoom(&CC->room, CC->room.QRname);
       if (Imap->last_mtime == CC->room.QRmtime) {      /* No changes! */
              return;
       }

       /* Load the *current* message list from disk, so we can compare it
        * to what we have in memory.
        */
       cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
       if (cdbfr != NULL) {
              msglist = malloc(cdbfr->len + 1);
              if (msglist == NULL) {
                     IMAPM_syslog(LOG_CRIT, "malloc() failed");
                     CC->kill_me = KILLME_MALLOC_FAILED;
                     return;
              }
              memcpy(msglist, cdbfr->ptr, (size_t)cdbfr->len);
              num_msgs = cdbfr->len / sizeof(long);
              cdb_free(cdbfr);
       } else {
              num_msgs = 0;
       }

       /*
        * Check to see if any of the messages we know about have been expunged
        */
       if (Imap->num_msgs > 0) {
              jstart = 0;
              for (i = 0; i < Imap->num_msgs; ++i) {

                     message_still_exists = 0;
                     if (num_msgs > 0) {
                            for (j = jstart; j < num_msgs; ++j) {
                                   if (msglist[j] == Imap->msgids[i]) {
                                          message_still_exists = 1;
                                          jstart = j;
                                          break;
                                   }
                            }
                     }

                     if (message_still_exists == 0) {
                            IAPrintf("* %d EXPUNGE\r\n", i + 1);

                            /* Here's some nice stupid nonsense.  When a
                             * message is expunged, we have to slide all
                             * the existing messages up in the message
                             * array.
                             */
                            --Imap->num_msgs;
                            memmove(&Imap->msgids[i],
                                   &Imap->msgids[i + 1],
                                   (sizeof(long) *
                                    (Imap->num_msgs - i)));
                            memmove(&Imap->flags[i],
                                   &Imap->flags[i + 1],
                                   (sizeof(long) *
                                    (Imap->num_msgs - i)));

                            --i;
                     }

              }
       }

       /*
        * Remember how many messages were here before we re-scanned.
        */
       original_num_msgs = Imap->num_msgs;
       if (Imap->num_msgs > 0) {
              original_highest = Imap->msgids[Imap->num_msgs - 1];
       } else {
              original_highest = 0L;
       }

       /*
        * Now peruse the room for *new* messages only.
        * This logic is probably the cause of Bug # 368
        * [ http://bugzilla.citadel.org/show_bug.cgi?id=368 ]
        */
       if (num_msgs > 0) {
              for (j = 0; j < num_msgs; ++j) {
                     if (msglist[j] > original_highest) {
                            imap_add_single_msgid(msglist[j], NULL);
                     }
              }
       }
       imap_set_seen_flags(original_num_msgs);

       /*
        * If new messages have arrived, tell the client about them.
        */
       if (Imap->num_msgs > original_num_msgs) {

              for (j = 0; j < num_msgs; ++j) {
                     if (Imap->flags[j] & IMAP_RECENT) {
                            ++num_recent;
                     }
              }

              IAPrintf("* %d EXISTS\r\n", Imap->num_msgs);
              IAPrintf("* %d RECENT\r\n", num_recent);
       }

       if (msglist != NULL) {
              free(msglist);
       }
       Imap->last_mtime = CC->room.QRmtime;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void registerImapCMD ( const char *  First,
long  FLen,
const char *  Second,
long  SLen,
imap_handler  H,
int  Flags 
)

Definition at line 74 of file serv_imap.c.

{
       imap_handler_hook *h;

       h = (imap_handler_hook*) malloc(sizeof(imap_handler_hook));
       memset(h, 0, sizeof(imap_handler_hook));

       h->Flags = Flags;
       h->h = H;
       if (SLen == 0) {
              Put(ImapCmds, First, FLen, h, NULL);
       }
       else {
              char CMD[SIZ];
              memcpy(CMD, First, FLen);
              memcpy(CMD+FLen, Second, SLen);
              CMD[FLen+SLen] = '\0';
              Put(ImapCmds, CMD, FLen + SLen, h, NULL);
       }
}

Variable Documentation

Definition at line 72 of file serv_imap.c.