Back to index

courier  0.68.2
Functions | Variables
mainloop.c File Reference
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include "imaptoken.h"
#include "imapwrite.h"
#include "numlib/numlib.h"

Go to the source code of this file.

Functions

int do_imap_command (const char *)
static RETSIGTYPE sigexit (int n)
void cmdfail (const char *tag, const char *msg)
void cmdsuccess (const char *tag, const char *msg)
void mainloop (void)

Variables

unsigned long header_count
unsigned long body_count
unsigned long bytes_received_count
unsigned long bytes_sent_count
time_t start_time

Function Documentation

void cmdfail ( const char *  tag,
const char *  msg 
)

Definition at line 70 of file mainloop.c.

{
#if SMAP
       const char *p=getenv("PROTOCOL");

       if (p && strcmp(p, "SMAP1") == 0)
              writes("-ERR ");
       else
#endif
       {
              writes(tag);
              writes(" NO ");
       }
       writes(msg);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void cmdsuccess ( const char *  tag,
const char *  msg 
)

Definition at line 86 of file mainloop.c.

{
#if SMAP
       const char *p=getenv("PROTOCOL");

       if (p && strcmp(p, "SMAP1") == 0)
              writes("+OK ");
       else
#endif
       {
              writes(tag);
              writes(" OK ");
       }
       writes(msg);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int do_imap_command ( const char *  )

Definition at line 4025 of file imapd.c.

{
struct imaptoken *curtoken=nexttoken();
int    uid=0;

       if (curtoken->tokentype != IT_ATOM)       return (-1);

       /* Commands that work in authenticated state */

       if (strcmp(curtoken->tokenbuf, "CAPABILITY") == 0)
       {
              if (nexttoken()->tokentype != IT_EOL)     return (-1);
              writes("* CAPABILITY ");
              imapcapability();
              writes("\r\n");
              writes(tag);
              writes(" OK CAPABILITY completed\r\n");
              return (0);
       }
       if (strcmp(curtoken->tokenbuf, "NOOP") == 0)
       {
              if (nexttoken()->tokentype != IT_EOL)     return (-1);
              if (current_mailbox)
                     doNoop(1);
              writes(tag);
              writes(" OK NOOP completed\r\n");
              return (0);
       }
       if (strcmp(curtoken->tokenbuf, "IDLE") == 0)
       {
              const char *p;

               if (nexttoken()->tokentype != IT_EOL)   return (-1);

              read_eol();

              if ((p=getenv("IMAP_ENHANCEDIDLE")) == NULL
                 || !atoi(p)
                 || imapenhancedidle())
                     imapidle();
              curtoken=nexttoken();
              if (strcmp(curtoken->tokenbuf, "DONE") == 0)
              {
                     if (current_mailbox)
                            doNoop(0);
                     writes(tag);
                     writes(" OK IDLE completed\r\n");
                     return (0);
               }
               return (-1);
       }
       if (strcmp(curtoken->tokenbuf, "LOGOUT") == 0)
       {
              if (nexttoken()->tokentype != IT_EOL)     return (-1);
              fetch_free_cache();
              writes("* BYE Courier-IMAP server shutting down\r\n");
              writes(tag);
              writes(" OK LOGOUT completed\r\n");
              writeflush();
              emptytrash();
              logoutmsg();
              bye();
       }

       if (strcmp(curtoken->tokenbuf, "LIST") == 0
              || strcmp(curtoken->tokenbuf, "LSUB") == 0)
       {
              char   *reference, *name;
              int    rc;
              char   cmdbuf[5];
              int    list_flags=0;

              strcpy(cmdbuf, curtoken->tokenbuf);

              curtoken=nexttoken_nouc();
              if (curtoken->tokentype == IT_LPAREN)
              {
                     while ((curtoken=nexttoken())->tokentype != IT_RPAREN)
                     {
                            if (curtoken->tokentype != IT_QUOTED_STRING &&
                                curtoken->tokentype != IT_ATOM &&
                                curtoken->tokentype != IT_NUMBER)
                                   return (-1);

                            if (strcmp(curtoken->tokenbuf, "ACL") == 0)
                                   list_flags |= LIST_ACL;
                            if (strcmp(curtoken->tokenbuf, "MYRIGHTS")==0)
                                   list_flags |= LIST_MYRIGHTS;
                            if (strcmp(curtoken->tokenbuf,
                                      "POSTADDRESS")==0)
                                   list_flags |= LIST_POSTADDRESS;
                     }

                     curtoken=nexttoken_nouc();
              }


              if (curtoken->tokentype == IT_NIL)
                     reference=my_strdup("");
              else
              {
                     if (curtoken->tokentype != IT_QUOTED_STRING &&
                            curtoken->tokentype != IT_ATOM &&
                            curtoken->tokentype != IT_NUMBER)
                            return (-1);
                     reference=my_strdup(curtoken->tokenbuf);
              }
              curtoken=nexttoken_nouc();

              if (curtoken->tokentype == IT_NIL)
                     name=my_strdup("");
              else
              {
                     if (curtoken->tokentype != IT_QUOTED_STRING &&
                            curtoken->tokentype != IT_ATOM &&
                            curtoken->tokentype != IT_NUMBER)
                            return (-1);
                     name=my_strdup(curtoken->tokenbuf);
              }
              if (nexttoken()->tokentype != IT_EOL)     return (-1);

              if (strcmp(cmdbuf, "LIST"))
                     list_flags |= LIST_SUBSCRIBED;

              rc=mailbox_scan(reference, name,
                            list_flags,
                            list_callback, cmdbuf);
 
              free(reference);
              free(name);
              if (rc == 0)
              {
                     writes(tag);
                     writes(" OK ");
                     writes(cmdbuf);
                     writes(" completed\r\n");
              }
              else
              {
                     writes(tag);
                     writes(" NO ");
                     writes(strerror(errno));
                     writes("\r\n");
                     rc=0;
              }
              writeflush();
              return (rc);
       }

       if (strcmp(curtoken->tokenbuf, "APPEND") == 0)
       {
              struct imaptoken *tok=nexttoken_nouc();
              struct maildir_info mi;

              if (tok->tokentype != IT_NUMBER &&
                     tok->tokentype != IT_ATOM &&
                     tok->tokentype != IT_QUOTED_STRING)
                     return (-1);

              if (maildir_info_imap_find(&mi, tok->tokenbuf,
                                      getenv("AUTHENTICATED")) < 0)
              {
                     writes(tag);
                     writes(" NO Invalid mailbox name.\r\n");
                     return (0);
              }

              if (mi.homedir && mi.maildir)
              {
                     char *p=maildir_name2dir(mi.homedir, mi.maildir);
                     int rc;

                     if (!p)
                     {
                            maildir_info_destroy(&mi);
                            writes(tag);
                            accessdenied("APPEND",
                                        tok->tokenbuf,
                                        ACL_INSERT);
                            return 0;
                     }
                     
                     rc=append(tag, tok->tokenbuf, p);
                     free(p);
                     maildir_info_destroy(&mi);
                     return (rc);
              }
              else if (mi.mailbox_type == MAILBOXTYPE_OLDSHARED)
              {
                     char *p=strchr(tok->tokenbuf, '.');

                     if (p && (p=maildir_shareddir(".", p+1)) != NULL)
                     {
                            int rc;
                            char   *q=malloc(strlen(p)+sizeof("/shared"));

                            if (!q)       write_error_exit(0);

                            strcat(strcpy(q, p), "/shared");
                            free(p);
                            rc=append(tag, tok->tokenbuf, q);
                            free(q);
                            maildir_info_destroy(&mi);
                            return rc;
                     }
              }

              writes(tag);
              accessdenied("APPEND", "folder", ACL_INSERT);
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "GETQUOTAROOT") == 0)
       {
              char   qroot[20];
              struct maildir_info minfo;

              curtoken=nexttoken_nouc();

              if (curtoken->tokentype != IT_NUMBER &&
                     curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
                     return (-1);

              if (maildir_info_imap_find(&minfo, curtoken->tokenbuf,
                                      getenv("AUTHENTICATED")))
              {
                     writes(tag);
                     writes(" NO Invalid mailbox name.\r\n");
                     return (0);
              }

              switch (minfo.mailbox_type) {
              case MAILBOXTYPE_INBOX:
                     strcpy(qroot, "ROOT");
                     break;
              case MAILBOXTYPE_OLDSHARED:
                     strcpy(qroot, "SHARED");
                     break;
              case MAILBOXTYPE_NEWSHARED:
                     strcpy(qroot, "PUBLIC");
                     break;
              }
              maildir_info_destroy(&minfo);

              writes("*");
              writes(" QUOTAROOT \"");
              writeqs(curtoken->tokenbuf);
              writes("\" \"");
              writes(qroot);
              writes("\"\r\n");
              quotainfo_out(qroot);
              writes(tag);
              writes(" OK GETQUOTAROOT Ok.\r\n");
              return(0);
       }


       if (strcmp(curtoken->tokenbuf, "SETQUOTA") == 0)
       {
              writes(tag);
              writes(" NO SETQUOTA No permission.\r\n");
              return(0);
       }

       if (strcmp(curtoken->tokenbuf, "GETQUOTA") == 0)
       {
              curtoken=nexttoken_nouc();

              if (curtoken->tokentype != IT_NUMBER &&
                     curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
                     return (-1);

              quotainfo_out(curtoken->tokenbuf);
              writes(tag);
              writes(" OK GETQUOTA Ok.\r\n");
              return(0);
       }

       if (strcmp(curtoken->tokenbuf, "STATUS") == 0)
       {
              char   *mailbox;
              int    get_messages=0,
                     get_recent=0,
                     get_uidnext=0,
                     get_uidvalidity=0,
                     get_unseen=0;

              struct imapscaninfo other_info, *loaded_infoptr,
                     *infoptr;
              const char *p;
              char   *orig_mailbox;
              int    oneonly;

              curtoken=nexttoken_nouc();
              mailbox=parse_mailbox_error(tag, curtoken, 0, 0);
              if ( mailbox == 0)
                     return (0);

              orig_mailbox=my_strdup(curtoken->tokenbuf);
              curtoken=nexttoken();

              oneonly=0;
              if (curtoken->tokentype != IT_LPAREN)
              {
                     if (curtoken->tokentype != IT_ATOM)
                     {
                            free(mailbox);
                            free(orig_mailbox);
                            return (-1);
                     }
                     oneonly=1;
              }
              else   nexttoken();

              while ((curtoken=currenttoken())->tokentype == IT_ATOM)
              {
                     if (strcmp(curtoken->tokenbuf, "MESSAGES") == 0)
                            get_messages=1;
                     if (strcmp(curtoken->tokenbuf, "RECENT") == 0)
                            get_recent=1;
                     if (strcmp(curtoken->tokenbuf, "UIDNEXT") == 0)
                            get_uidnext=1;
                     if (strcmp(curtoken->tokenbuf, "UIDVALIDITY") == 0)
                            get_uidvalidity=1;
                     if (strcmp(curtoken->tokenbuf, "UNSEEN") == 0)
                            get_unseen=1;
                     nexttoken();
                     if (oneonly)  break;
              }

              if ((!oneonly && curtoken->tokentype != IT_RPAREN) ||
                     nexttoken()->tokentype != IT_EOL)
              {
                     free(mailbox);
                     free(orig_mailbox);
                     return (-1);
              }

              {
                     CHECK_RIGHTSM(orig_mailbox, status_rights, ACL_READ);

                     if (!status_rights[0])
                     {
                            writes(tag);
                            accessdenied("STATUS", orig_mailbox,
                                        ACL_READ);
                            free(mailbox);
                            free(orig_mailbox);
                            return 0;
                     }
              }


              if (current_mailbox && strcmp(current_mailbox, mailbox) == 0)
              {
                     loaded_infoptr=0;
                     infoptr= &current_maildir_info;
              }
              else
              {
                     loaded_infoptr= &other_info;
                     infoptr=loaded_infoptr;

                     imapscan_init(loaded_infoptr);

                     if (imapscan_maildir(infoptr, mailbox, 1, 1, NULL))
                     {
                            writes(tag);
                            writes(" NO [ALERT] STATUS failed\r\n");
                            free(mailbox);
                            free(orig_mailbox);
                            return (0);
                     }
              }

              writes("*");
              writes(" STATUS \"");
              writeqs(orig_mailbox);
              writes("\" (");
              p="";
              if (get_messages)
              {
                     writes("MESSAGES ");
                     writen(infoptr->nmessages+infoptr->left_unseen);
                     p=" ";
              }
              if (get_recent)
              {
              unsigned long n=infoptr->left_unseen;
              unsigned long i;

                     for (i=0; i<infoptr->nmessages; i++)
                            if (infoptr->msgs[i].recentflag)
                                   ++n;
                     writes(p);
                     writes("RECENT ");
                     writen(n);
                     p=" ";
              }

              if (get_uidnext)
              {
                     writes(p);
                     writes("UIDNEXT ");
                     writen(infoptr->nextuid);
                     p=" ";
              }

              if (get_uidvalidity)
              {
                     writes(p);
                     writes("UIDVALIDITY ");
                     writen(infoptr->uidv);
                     p=" ";
              }

              if (get_unseen)
              {
              unsigned long n=infoptr->left_unseen, i;

                     for (i=0; i<infoptr->nmessages; i++)
                     {
                     const char *p=infoptr->msgs[i].filename;

                            p=strrchr(p, MDIRSEP[0]);
                            if (p && strncmp(p, MDIRSEP "2,", 3) == 0 &&
                                   strchr(p, 'S'))      continue;
                            ++n;
                     }
                     writes(p);
                     writes("UNSEEN ");
                     writen(n);
              }
              writes(")\r\n");
              if (loaded_infoptr)
                     imapscan_free(loaded_infoptr);
              free(mailbox);
              free(orig_mailbox);
              writes(tag);
              writes(" OK STATUS Completed.\r\n");
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "CREATE") == 0)
       {
              char   *mailbox, *orig_mailbox, *p;
              int    isdummy;
              struct maildir_info mi;
              struct imapscaninfo minfo;

              curtoken=nexttoken_nouc();

              if (curtoken->tokentype != IT_NUMBER &&
                     curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
                     return (-1);

              isdummy=0;

              p=strrchr(curtoken->tokenbuf, HIERCH);
              if (p && p[1] == '\0')
              {
                     *p=0;
                     isdummy=1;    /* Ignore hierarchy creation */
              }

              if (maildir_info_imap_find(&mi, curtoken->tokenbuf,
                                      getenv("AUTHENTICATED")))
              {
                     writes(tag);
                     writes(" NO Invalid mailbox name.\r\n");
                     return (0);
              }

              if (!mi.homedir || !mi.maildir)
              {
                     maildir_info_destroy(&mi);
                     writes(tag);
                     accessdenied("CREATE",
                                 curtoken->tokenbuf,
                                 ACL_CREATE);
                     maildir_info_destroy(&mi);
                     return (0);
              }

              mailbox=maildir_name2dir(mi.homedir, mi.maildir);
              if (!mailbox)
              {
                     writes(tag);
                     writes(" NO Invalid mailbox name\r\n");
                     maildir_info_destroy(&mi);
                     return (0);
              }

              if (strcmp(mailbox, ".") == 0)
              {
                     writes(tag);
                     writes(" NO INBOX already exists!\r\n");
                     free(mailbox);
                     maildir_info_destroy(&mi);
                     return (0);
              }

              if (check_parent_create(tag, "CREATE", curtoken->tokenbuf))
              {
                     free(mailbox);
                     maildir_info_destroy(&mi);
                     return (0);
              }

              if (isdummy)  *p=HIERCH;
              orig_mailbox=my_strdup(curtoken->tokenbuf);

              if (nexttoken()->tokentype != IT_EOL)
              {
                     free(mailbox);
                     free(orig_mailbox);
                     maildir_info_destroy(&mi);
                     return (-1);
              }

              if (!isdummy)
              {
                     int did_exist;
                     maildir_aclt_list l;

                     if ((did_exist=folder_exists(orig_mailbox)) != 0)
                     {
                            if (acl_read_folder(&l,
                                              mi.homedir,
                                              mi.maildir) < 0)
                            {
                                   free(mailbox);
                                   free(orig_mailbox);
                                   writes(tag);
                                   writes(" NO Cannot create this folder"
                                          ".\r\n");
                                   maildir_info_destroy(&mi);
                                   return (0);
                            }
                            maildir_acl_delete(mi.homedir, mi.maildir);
                            /* Clear out fluff */
                     }

                     if (mdcreate(mailbox))
                     {
                            if (did_exist)
                                   maildir_aclt_list_destroy(&l);
                            free(mailbox);
                            free(orig_mailbox);
                            writes(tag);
                            writes(" NO Cannot create this folder.\r\n");
                            maildir_info_destroy(&mi);
                            return (0);
                     }
                     if (did_exist)
                     {
                            const char *acl_error;

                            acl_write_folder(&l, mi.homedir,
                                           mi.maildir, NULL,
                                           &acl_error);
                            maildir_aclt_list_destroy(&l);
                     }
              }
              writes(tag);
              writes(" OK \"");
              writeqs(orig_mailbox);
              writes("\" created.\r\n");

              /*
              ** This is a dummy call to acl_read_folder that initialized
              ** the default ACLs for this folder to its parent.
              */

              {
                     CHECK_RIGHTSM(curtoken->tokenbuf, create_rights,
                                  ACL_CREATE);
              }

              imapscan_init(&minfo);
              imapscan_maildir(&minfo, mailbox, 0,0, NULL);
              imapscan_free(&minfo);

              free(mailbox);
              free(orig_mailbox);
              maildir_info_destroy(&mi);
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "DELETE") == 0)
       {
       char   *mailbox;
       char   *p;
       char   *mailbox_name;

              curtoken=nexttoken_nouc();

              if (curtoken->tokentype != IT_NUMBER &&
                     curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
                     return (-1);

              p=strrchr(curtoken->tokenbuf, HIERCH);
              if (p && p[1] == '\0')             /* Ignore hierarchy DELETE */
              {
                     if (nexttoken()->tokentype != IT_EOL)
                            return (-1);
                     writes(tag);
                     writes(" OK Folder directory delete punted.\r\n");
                     return (0);
              }

              mailbox_name=my_strdup(curtoken->tokenbuf);
              mailbox=parse_mailbox_error(tag, curtoken, 1, 0);
              if ( mailbox == 0)
              {
                     free(mailbox_name);
                     return (0);
              }

              if (nexttoken()->tokentype != IT_EOL)
              {
                     free(mailbox_name);
                     free(mailbox);
                     return (-1);
              }

              if (current_mailbox && strcmp(mailbox, current_mailbox) == 0)
              {
                     free(mailbox_name);
                     free(mailbox);
                     writes(tag);
                     writes(" NO Cannot delete currently-open folder.\r\n");
                     return (0);
              }

              if (strncmp(curtoken->tokenbuf, SHARED HIERCHS,
                     sizeof(SHARED HIERCHS)-1) == 0)
              {
                     maildir_shared_unsubscribe(0, curtoken->tokenbuf+
                                             sizeof(SHARED HIERCHS)-1);
                     free(mailbox_name);
                     free(mailbox);
                     writes(tag);
                     writes(" OK UNSUBSCRIBEd a shared folder.\r\n");
                     return (0);
              }

              {
                     CHECK_RIGHTSM(curtoken->tokenbuf,
                                  delete_rights,
                                  ACL_DELETEFOLDER);
                     if (delete_rights[0] == 0)
                     {
                            free(mailbox_name);
                            free(mailbox);
                            writes(tag);
                            accessdenied("DELETE",
                                        curtoken->tokenbuf,
                                        ACL_DELETEFOLDER);
                            return 0;
                     }
              }

              if (!broken_uidvs())
                     sleep(2); /* Make sure we never recycle them*/

              fetch_free_cache();


              if (do_folder_delete(mailbox_name))
              {
                     writes(tag);
                     writes(" NO Cannot delete this folder.\r\n");
              }
              else
              {
                     writes(tag);
                     writes(" OK Folder deleted.\r\n");
              }

              free(mailbox_name);
              free(mailbox);
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "RENAME") == 0)
       {
              char *p;
              struct maildir_info mi1, mi2;
              const char *errmsg;

              curtoken=nexttoken_nouc();

              if (curtoken->tokentype != IT_NUMBER &&
                  curtoken->tokentype != IT_ATOM &&
                  curtoken->tokentype != IT_QUOTED_STRING)
              {
                     writes(tag);
                     writes(" NO Invalid mailbox\r\n");
                     return (0);
              }

              if ((p=strrchr(curtoken->tokenbuf, HIERCH))  && p[1] == 0)
                     *p=0;

              if (maildir_info_imap_find(&mi1, curtoken->tokenbuf,
                                      getenv("AUTHENTICATED")) < 0)
              {
                     writes(tag);
                     writes(" NO Invalid mailbox name.\r\n");
                     return (0);
              }

              if (mi1.homedir == NULL || mi1.maildir == NULL)
              {
                     maildir_info_destroy(&mi1);
                     writes(tag);
                     writes(" NO Invalid mailbox\r\n");
                     return (0);
              }

              {
                     CHECK_RIGHTSM(curtoken->tokenbuf,
                                  rename_rights, ACL_DELETEFOLDER);

                     if (rename_rights[0] == 0)
                     {
                            maildir_info_destroy(&mi1);
                            writes(tag);
                            accessdenied("RENAME", curtoken->tokenbuf,
                                        ACL_DELETEFOLDER);
                            return (0);
                     }
              }


              curtoken=nexttoken_nouc();
              if (curtoken->tokentype != IT_NUMBER &&
                     curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
              {
                     maildir_info_destroy(&mi1);
                     return (-1);
              }

              if ((p=strrchr(curtoken->tokenbuf, HIERCH)) && p[1] == 0)
              {
                     *p=0;
              }


              if (maildir_info_imap_find(&mi2, curtoken->tokenbuf,
                                      getenv("AUTHENTICATED")) < 0)
              {
                     maildir_info_destroy(&mi1);
                     writes(tag);
                     writes(" NO Invalid mailbox name.\r\n");
                     return (0);
              }

              if (check_parent_create(tag, "RENAME", curtoken->tokenbuf))
              {
                     maildir_info_destroy(&mi1);
                     maildir_info_destroy(&mi2);
                     return 0;
              }

              if (nexttoken()->tokentype != IT_EOL)
              {
                     maildir_info_destroy(&mi1);
                     maildir_info_destroy(&mi2);
                     return (-1);
              }

              if (!broken_uidvs())
                     sleep(2);
              /* Make sure IMAP uidvs are not recycled */

              if (folder_rename(&mi1, &mi2, &errmsg))
              {
                     writes(tag);
                     writes(" NO ");
                     writes(*errmsg == '@' ? errmsg+1:errmsg);
                     if (*errmsg == '@')
                            writes(strerror(errno));
                     writes("\r\n");
              }
              else
              {
                     writes(tag);
                     writes(" OK Folder renamed.\r\n");
              }

              maildir_info_destroy(&mi1);
              maildir_info_destroy(&mi2);
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "SELECT") == 0 ||
              strcmp(curtoken->tokenbuf, "EXAMINE") == 0)
       {
       char   *mailbox;
       int    ro=curtoken->tokenbuf[0] == 'E';
       const char *p;


              curtoken=nexttoken_nouc();

              if (current_mailbox)
              {
                     free(current_mailbox);
                     imapscan_free(&current_maildir_info);
                     imapscan_init(&current_maildir_info);
                     current_mailbox=0;
              }

              if (current_mailbox_acl)
                     free(current_mailbox_acl);
              current_mailbox_acl=0;

              mailbox=parse_mailbox_error(tag, curtoken, 0, 1);
              if ( mailbox == 0)
                     return (0);

              current_mailbox_acl=get_myrightson(curtoken->tokenbuf);
              if (current_mailbox_acl == NULL)
              {
                     free(mailbox);
                     writes(tag);
                     writes(" NO Unable to read ACLs for ");
                     writes(curtoken->tokenbuf);
                     writes(": ");
                     writes(strerror(errno));
                     writes("\r\n");
                     return 0;
              }

              if (strchr(current_mailbox_acl, ACL_READ[0]) == NULL)
              {
                     free(mailbox);
                     free(current_mailbox_acl);
                     current_mailbox_acl=NULL;
                     writes(tag);
                     accessdenied("SELECT/EXAMINE", curtoken->tokenbuf,
                                 ACL_READ);
                     return 0;
              }

              if (nexttoken()->tokentype != IT_EOL)
              {
                     free(mailbox);
                     return (-1);
              }

              if (imapscan_maildir(&current_maildir_info, mailbox, 0, ro,
                                 NULL))
              {
                     free(mailbox);
                     writes(tag);
                     writes(" NO Unable to open this mailbox.\r\n");
                     return (0);
              }
              current_mailbox=mailbox;

              /* check if this is a shared read-only folder */

              if (is_sharedsubdir(mailbox) &&
                     maildir_sharedisro(mailbox))
                     ro=1;

              current_mailbox_ro=ro;

              mailboxflags(ro);
              mailboxmetrics();
              writes("* OK [UIDVALIDITY ");
              writen(current_maildir_info.uidv);
              writes("] Ok\r\n");
              myrights();
              writes(tag);

              for (p=current_mailbox_acl; *p; p++)
                     if (strchr(ACL_INSERT ACL_EXPUNGE
                               ACL_SEEN ACL_WRITE ACL_DELETEMSGS,
                               *p))
                            break;

              if (*p == 0)
                     ro=1;

              writes(ro ? " OK [READ-ONLY] Ok\r\n":" OK [READ-WRITE] Ok\r\n");
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "SUBSCRIBE") == 0)
       {
       char   *mailbox;
       char   *p;
       struct maildir_info mi;

              curtoken=nexttoken_nouc();
              if (curtoken->tokentype != IT_NUMBER &&
                     curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
                     return (-1);

              p=strrchr(curtoken->tokenbuf, HIERCH);
              if (p && p[1] == '\0')             /* Ignore hierarchy DELETE */
              {
                     if (nexttoken()->tokentype != IT_EOL)
                            return (-1);
                     writes(tag);
                     writes(" OK Folder directory subscribe punted.\r\n");
                     return (0);
              }

              mailbox=my_strdup(curtoken->tokenbuf);
              if (nexttoken()->tokentype != IT_EOL)
                     return (-1);

              if (maildir_info_imap_find(&mi, mailbox,
                                      getenv("AUTHENTICATED")) < 0)
              {
                     free(mailbox);
                     writes(tag);
                     writes(" NO Invalid mailbox name.\r\n");
                     return (0);
              }

              if (mi.mailbox_type != MAILBOXTYPE_OLDSHARED)
              {
                     maildir_info_destroy(&mi);
                     subscribe(mailbox);
                     free(mailbox);
                     writes(tag);
                     writes(" OK Folder subscribed.\r\n");
                     return (0);
              }
              maildir_info_destroy(&mi);

              p=strchr(mailbox, '.');

              p=p ? maildir_shareddir(".", p+1):NULL;

              if (p == NULL || access(p, 0) == 0)
              {
                     if (p)
                            free(p);
                     free(mailbox);
                     writes(tag);
                     writes(" OK Already subscribed.\r\n");
                     return (0);
              }

              if (!p || maildir_shared_subscribe(0, strchr(mailbox, '.')+1))
              {
                     if (p)
                            free(p);
                     free(mailbox);
                     writes(tag);
                     writes(" NO Cannot subscribe to this folder.\r\n");
                     return (0);
              }
              if (p)
                     free(p);
              free(mailbox);
              writes(tag);
              writes(" OK SUBSCRIBE completed.\r\n");
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "UNSUBSCRIBE") == 0)
       {
       char   *mailbox;
       char   *p;
       struct maildir_info mi;

              curtoken=nexttoken_nouc();
              if (curtoken->tokentype != IT_NUMBER &&
                     curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
                     return (-1);

              p=strrchr(curtoken->tokenbuf, HIERCH);
              if (p && p[1] == '\0')             /* Ignore hierarchy DELETE */
              {
                     if (nexttoken()->tokentype != IT_EOL)
                            return (-1);
                     writes(tag);
                     writes(" OK Folder directory unsubscribe punted.\r\n");
                     return (0);
              }

              mailbox=my_strdup(curtoken->tokenbuf);
              if (nexttoken()->tokentype != IT_EOL)
                     return (-1);

              if (maildir_info_imap_find(&mi, mailbox,
                                      getenv("AUTHENTICATED")) < 0)
              {
                     free(mailbox);
                     writes(tag);
                     writes(" NO Invalid mailbox name.\r\n");
                     return (0);
              }

              if (mi.mailbox_type != MAILBOXTYPE_OLDSHARED)
              {
                     maildir_info_destroy(&mi);
                     unsubscribe(mailbox);
                     free(mailbox);
                     writes(tag);
                     writes(" OK Folder unsubscribed.\r\n");
                     return (0);
              }
              maildir_info_destroy(&mi);

              p=strchr(mailbox, '.');

              p=p ? maildir_shareddir(".", p+1):NULL;


              if (p == NULL || access(p, 0))
              {
                     if (p)
                            free(p);
                     free(mailbox);
                     writes(tag);
                     writes(" OK Already unsubscribed.\r\n");
                     return (0);
              }

              fetch_free_cache();

              if (!p || maildir_shared_unsubscribe(0,
                                               strchr(mailbox, '.')+1))
              {
                     if (p)
                            free(p);
                     free(mailbox);
                     writes(tag);
                     writes(" NO Cannot subscribe to this folder.\r\n");
                     return (0);
              }
              if (p)
                     free(p);
              free(mailbox);
              writes(tag);
              writes(" OK UNSUBSCRIBE completed.\r\n");
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "NAMESPACE") == 0)
       {
              if (nexttoken()->tokentype != IT_EOL)
                     return (-1);
              writes("* NAMESPACE ((\"INBOX.\" \".\")) NIL "
                     "((\"#shared.\" \".\")(\""
                     SHARED ".\" \".\"))\r\n");
              writes(tag);
              writes(" OK NAMESPACE completed.\r\n");
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "ACL") == 0)
       {
              if (aclcmd(tag))
              {
                     writes(tag);
                     writes(" ACL FAILED: ");
                     writes(strerror(errno));
                     writes("\r\n");
              }
              return 0;
       }

       /* RFC 2086 */

       if (strcmp(curtoken->tokenbuf, "SETACL") == 0 ||
           strcmp(curtoken->tokenbuf, "DELETEACL") == 0)
       {
              char *mailbox;
              char *identifier;
              struct maildir_info mi;
              maildir_aclt_list aclt_list;
              const char *acl_error;
              int doset=curtoken->tokenbuf[0] == 'S';
              const char *origcmd=doset ? "SETACL":"DELETEACL";

              curtoken=nexttoken_nouc();

              mailbox=parse_mailbox_error(tag, curtoken, 0, 0);
              if (!mailbox)
                     return 0;
              free(mailbox);

              mailbox=my_strdup(curtoken->tokenbuf);

              if (maildir_info_imap_find(&mi, mailbox,
                                      getenv("AUTHENTICATED")) < 0)
              {
                     writes(tag);
                     writes(" NO Invalid mailbox.\r\n");
                     free(mailbox);
                     return 0;
              }

              if (mi.homedir == NULL || mi.maildir == NULL)
              {
                     maildir_info_destroy(&mi);
                     writes(tag);
                     writes(" NO Cannot set ACLs for this mailbox\r\n");
                     free(mailbox);
                     return 0;
              }

              switch ((curtoken=nexttoken_nouc())->tokentype) {
              case IT_QUOTED_STRING:
              case IT_ATOM:
              case IT_NUMBER:
                     break;
              default:
                     maildir_info_destroy(&mi);
                     free(mailbox);
                     return -1;
              }

              identifier=acl2_identifier(tag, curtoken->tokenbuf);

              if (identifier == NULL)
              {
                     maildir_info_destroy(&mi);
                     free(mailbox);
                     return 0;
              }

              if (doset)
              {
                     switch ((curtoken=nexttoken_nouc())->tokentype) {
                     case IT_QUOTED_STRING:
                     case IT_ATOM:
                     case IT_NUMBER:
                            break;
                     default:
                            free(identifier);
                            maildir_info_destroy(&mi);
                            free(mailbox);
                            return -1;
                     }
              }

              {
                     CHECK_RIGHTSM(mailbox,
                                  acl_rights,
                                  ACL_ADMINISTER);
                     if (acl_rights[0] == 0)
                     {
                            writes(tag);
                            accessdenied(origcmd, mailbox,
                                        ACL_ADMINISTER);
                            free(identifier);
                            maildir_info_destroy(&mi);
                            free(mailbox);
                            return 0;
                     }
              }

              if (acl_read_folder(&aclt_list, mi.homedir, mi.maildir))
              {
                     writes(tag);
                     writes(" NO Cannot read existing ACLs.\r\n");
                     free(identifier);
                     maildir_info_destroy(&mi);
                     free(mailbox);
                     return 0;
              }

              if (do_acl_mod(&aclt_list, &mi, identifier,
                            doset ? curtoken->tokenbuf:"",
                            &acl_error) < 0)
              {
                     writes(tag);
                     writes(acl_error ?
                            " NO Cannot modify ACLs as requested.\r\n" :
                            " NO Cannot modify ACLs on this mailbox.\r\n");
              }
              else
              {
                     char *p=get_myrightson(mailbox);

                     if (p)
                            free(p);
                     /* Side effect - change current folder's ACL */

                     writes(tag);
                     writes(" OK ACLs updated.\r\n");
              }

              maildir_aclt_list_destroy(&aclt_list);
              maildir_info_destroy(&mi);
              free(identifier);
              free(mailbox);
              return 0;
       }

       if (strcmp(curtoken->tokenbuf, "GETACL") == 0)
       {
              maildir_aclt_list l;
              char *mailbox_owner;
              char *mb;

              curtoken=nexttoken_nouc();

              mb=parse_mailbox_error(tag, curtoken, 0, 0);
              if (!mb)
                     return 0;
              free(mb);

              {
                     CHECK_RIGHTSM(curtoken->tokenbuf,
                                  acl_rights,
                                  ACL_ADMINISTER);
                     if (acl_rights[0] == 0)
                     {
                            writes(tag);
                            accessdenied("GETACL", curtoken->tokenbuf,
                                        ACL_ADMINISTER);
                            return 0;
                     }
              }

              if (get_acllist(&l, curtoken->tokenbuf,
                            &mailbox_owner) < 0)
              {
                     writes(tag);
                     writes(" NO Cannot retrieve ACLs for mailbox.\r\n");
                     return 0;
              }
              free(mailbox_owner);

              writes("* ACL \"");
              writeqs(curtoken->tokenbuf);
              writes("\"");
              maildir_aclt_list_enum(&l, getacl_cb, NULL);
              writes("\r\n");
              writes(tag);
              writes(" OK GETACL completed.\r\n");
              maildir_aclt_list_destroy(&l);
              return 0;
       }

       if (strcmp(curtoken->tokenbuf, "LISTRIGHTS") == 0)
       {
              maildir_aclt_list l;
              char *mailbox_owner;
              char *mb;

              curtoken=nexttoken_nouc();

              mb=parse_mailbox_error(tag, curtoken, 0, 0);
              if (!mb)
                     return 0;
              free(mb);

              {
                     char *myrights=get_myrightson(curtoken->tokenbuf);

                     if (!strchr(myrights, ACL_LOOKUP[0]) &&
                         !strchr(myrights, ACL_READ[0]) &&
                         !strchr(myrights, ACL_INSERT[0]) &&
                         !strchr(myrights, ACL_CREATE[0]) &&
                         !strchr(myrights, ACL_DELETEFOLDER[0]) &&
                         !strchr(myrights, ACL_EXPUNGE[0]) &&
                         !strchr(myrights, ACL_ADMINISTER[0]))
                     {
                            free(myrights);
                            writes(tag);
                            accessdenied("GETACL", curtoken->tokenbuf,
                                        ACL_ADMINISTER);
                            return 0;
                     }
                     free(myrights);
              }

              if (get_acllist(&l, curtoken->tokenbuf,
                            &mailbox_owner) < 0)
              {
                     writes(tag);
                     writes(" NO Cannot retrieve ACLs for mailbox.\r\n");
                     return 0;
              }

              mb=my_strdup(curtoken->tokenbuf);

              switch ((curtoken=nexttoken_nouc())->tokentype) {
              case IT_QUOTED_STRING:
              case IT_ATOM:
              case IT_NUMBER:
                     break;
              default:
                     free(mb);
                     free(mailbox_owner);
                     maildir_aclt_list_destroy(&l);
                     return -1;
              }

              writes("* LISTRIGHTS \"");
              writeqs(mb);
              writes("\" \"");
              writeqs(curtoken->tokenbuf);
              writes("\"");
              free(mb);


              if (curtoken->tokenbuf[0] == '-' &&
                  (MAILDIR_ACL_ANYONE(curtoken->tokenbuf+1) ||
                   (strncmp(mailbox_owner, "user=", 5) == 0 &&
                    strcmp(curtoken->tokenbuf+1, mailbox_owner+5) == 0)))
              {
                     writes(" \"\" "
                            ACL_CREATE " "
                            ACL_DELETE_SPECIAL " "
                            ACL_INSERT " "
                            ACL_POST " "
                            ACL_READ " "
                            ACL_SEEN " "
                            ACL_WRITE "\r\n");
              }
              else if (strncmp(mailbox_owner, "user=", 5) == 0 &&
                      strcmp(curtoken->tokenbuf, mailbox_owner+5) == 0)
              {
                     writes(" \""
                            ACL_ADMINISTER
                            ACL_LOOKUP "\" "
                            ACL_CREATE " "
                            ACL_DELETE_SPECIAL " "
                            ACL_INSERT " "
                            ACL_POST " "
                            ACL_READ " "
                            ACL_SEEN " "
                            ACL_WRITE "\r\n");
              }
              else
              {
                     writes(" \"\" "
                            ACL_ADMINISTER " "
                            ACL_CREATE " "
                            ACL_DELETE_SPECIAL " "
                            ACL_INSERT " "
                            ACL_LOOKUP " "
                            ACL_POST " "
                            ACL_READ " "
                            ACL_SEEN " "
                            ACL_WRITE "\r\n");
              }
              writes(tag);
              writes(" OK LISTRIGHTS completed.\r\n");
              free(mailbox_owner);
              maildir_aclt_list_destroy(&l);
              return 0;
       }

       if (strcmp(curtoken->tokenbuf, "MYRIGHTS") == 0)
       {
              char *mb;

              curtoken=nexttoken_nouc();

              mb=parse_mailbox_error(tag, curtoken, 0, 0);
              if (!mb)
                     return 0;
              free(mb);

              {
                     char *myrights=get_myrightson(curtoken->tokenbuf);

                     if (!strchr(myrights, ACL_LOOKUP[0]) &&
                         !strchr(myrights, ACL_READ[0]) &&
                         !strchr(myrights, ACL_INSERT[0]) &&
                         !strchr(myrights, ACL_CREATE[0]) &&
                         !strchr(myrights, ACL_DELETEFOLDER[0]) &&
                         !strchr(myrights, ACL_EXPUNGE[0]) &&
                         !strchr(myrights, ACL_ADMINISTER[0]))
                     {
                            free(myrights);
                            writes(tag);
                            accessdenied("GETACL", curtoken->tokenbuf,
                                        ACL_ADMINISTER);
                            return 0;
                     }
                     free(myrights);
              }

              mb=get_myrightson(curtoken->tokenbuf);

              if (!mb)
              {
                     writes(tag);
                     writes(" NO Cannot retrieve ACLs for mailbox.\r\n");
                     return 0;
              }

              writes("* MYRIGHTS \"");
              writeqs(curtoken->tokenbuf);
              writes("\" \"");

              writeacl1(mb);
              free(mb);
              writes("\"\r\n");
              writes(tag);
              writes(" OK MYRIGHTS completed.\r\n");
              return 0;
       }

       /* mailbox commands */

       if (current_mailbox == 0)   return (-1);

       if (strcmp(curtoken->tokenbuf, "UID") == 0)
       {
              uid=1;
              if ((curtoken=nexttoken())->tokentype != IT_ATOM)
                     return (-1);
              if (strcmp(curtoken->tokenbuf, "COPY") &&
                  strcmp(curtoken->tokenbuf, "FETCH") &&
                  strcmp(curtoken->tokenbuf, "SEARCH") &&
                  strcmp(curtoken->tokenbuf, "THREAD") &&
                  strcmp(curtoken->tokenbuf, "SORT") &&
                  strcmp(curtoken->tokenbuf, "STORE") &&
                  strcmp(curtoken->tokenbuf, "EXPUNGE"))
                     return (-1);
       }

       if (strcmp(curtoken->tokenbuf, "CLOSE") == 0)
       {
              if (nexttoken()->tokentype != IT_EOL)
                     return (-1);

              if (!current_mailbox_ro
                  && strchr(current_mailbox_acl, ACL_EXPUNGE[0]))
                     expunge();
              free(current_mailbox);
              imapscan_free(&current_maildir_info);
              imapscan_init(&current_maildir_info);
              current_mailbox=0;
              writes(tag);
              writes(" OK mailbox closed.\r\n");
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "FETCH") == 0)
       {
       struct fetchinfo *fi;
       char   *msgset;

              curtoken=nexttoken();
              if (!ismsgset(curtoken))    return (-1);
              msgset=my_strdup(curtoken->tokenbuf);

              if ((curtoken=nexttoken())->tokentype != IT_LPAREN)
              {
                     if (curtoken->tokentype != IT_ATOM)
                     {
                            free(msgset);
                            return (-1);
                     }
                     fi=fetchinfo_alloc(1);
              }
              else
              {
                     (void)nexttoken();
                     fi=fetchinfo_alloc(0);
                     if (fi && currenttoken()->tokentype != IT_RPAREN)
                     {
                            fetchinfo_free(fi);
                            fi=0;
                     }
                     nexttoken();
              }

              if (fi == 0 || currenttoken()->tokentype != IT_EOL)
              {
                     free(msgset);
                     if (fi)       fetchinfo_free(fi);
                     return (-1);
              }

              do_msgset(msgset, &do_fetch, fi, uid);
              fetchinfo_free(fi);
              free(msgset);
              writes(tag);
              writes(" OK FETCH completed.\r\n");
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "STORE") == 0)
       {
       char   *msgset;
       struct storeinfo storeinfo_s;

              curtoken=nexttoken();
              if (!ismsgset(curtoken))    return (-1);
              msgset=my_strdup(curtoken->tokenbuf);

              (void)nexttoken();
              current_maildir_info.keywordList->keywordAddedRemoved=0;

              if (storeinfo_init(&storeinfo_s) ||
                     currenttoken()->tokentype != IT_EOL)
              {
                     if (storeinfo_s.keywords)
                            libmail_kwmDestroy(storeinfo_s.keywords);
                     free(msgset);
                     return (-1);
              }

              /* Do not change \Deleted if this is a readonly mailbox */

              if (current_mailbox_ro && storeinfo_s.flags.deleted)
              {
                     if (storeinfo_s.keywords)
                            libmail_kwmDestroy(storeinfo_s.keywords);
                     free(msgset);
                     writes(tag);
                     writes(" NO Current box is selected READ-ONLY.\r\n");
                     return (0);
              }

              fetch_free_cache();

              if (current_maildir_info.keywordList->keywordAddedRemoved)
                     mailboxflags(current_mailbox_ro);

              current_maildir_info.keywordList->keywordAddedRemoved=0;

              if (do_msgset(msgset, &do_store, &storeinfo_s, uid))
              {
                     if (storeinfo_s.keywords)
                            libmail_kwmDestroy(storeinfo_s.keywords);
                     free(msgset);
                     if (current_maildir_info.keywordList
                         ->keywordAddedRemoved)
                            mailboxflags(current_mailbox_ro);

                     writes(tag);
                     writes(" NO [ALERT] You exceeded your mail quota.\r\n");
                     return (0);
              }
              if (storeinfo_s.keywords)
              {
                     struct imap_addRemoveKeywordInfo imapInfo;

                     switch (storeinfo_s.plusminus) {
                     case '+':
                     case '-':

                            imapInfo.msgset=msgset;
                            imapInfo.uid=uid;

                            if (!fastkeywords() &&
                                addRemoveKeywords(&imap_addRemoveKeywords,
                                                &imapInfo, &storeinfo_s))
                            {
                                   libmail_kwmDestroy(storeinfo_s.keywords);
                                   free(msgset);
                                   writes(tag);
                                   writes(" NO An error occured while"
                                          " updating keywords: ");
                                   writes(strerror(errno));
                                   writes(".\r\n");
                                   return 0;
                            }
                            break;
                     }

                     libmail_kwmDestroy(storeinfo_s.keywords);
              }
              free(msgset);
              if (current_maildir_info.keywordList->keywordAddedRemoved)
                     mailboxflags(current_mailbox_ro);
              writes(tag);
              writes(" OK STORE completed.\r\n");
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "SEARCH") == 0)
       {
              char *charset=0;
              struct searchinfo *si, *sihead;
              unsigned long i;

              curtoken=nexttoken_okbracket();
              if (curtoken->tokentype == IT_ATOM &&
                     strcmp(curtoken->tokenbuf, "CHARSET") == 0)
              {
                     curtoken=nexttoken();
                     if (curtoken->tokentype != IT_ATOM &&
                            curtoken->tokentype != IT_QUOTED_STRING)
                            return (-1);

                     charset=my_strdup(curtoken->tokenbuf);
                     curtoken=nexttoken();
              }

              if (validate_charset(tag, &charset))
              {
                     if (charset)
                            free(charset);
                     return (0);
              }

              if ((si=alloc_parsesearch(&sihead)) == 0)
              {
                     free(charset);
                     return (-1);
              }
              if (currenttoken()->tokentype != IT_EOL)
              {
                     free(charset);
                     free_search(sihead);
                     return (-1);
              }

#if 0
              writes("* OK ");
              debug_search(si);
              writes("\r\n");
#endif
              writes("* SEARCH");
              dosearch(si, sihead, charset, uid);
              writes("\r\n");
              free(charset);

              for (i=0; i<current_maildir_info.nmessages; i++)
                     if (current_maildir_info.msgs[i].changedflags)
                            fetchflags(i);
              writes(tag);
              writes(" OK SEARCH done.\r\n");
              free_search(sihead);
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "THREAD") == 0)
       {
       char *charset=0;
       struct searchinfo *si, *sihead;
       unsigned long i;

              /* The following jazz is mainly for future extensions */

       void (*thread_func)(struct searchinfo *, struct searchinfo *,
                         const char *, int);
       search_type thread_type;

              {
              const char *p=getenv("IMAP_DISABLETHREADSORT");
              int n= p ? atoi(p):0;

                     if (n > 0)
                     {
                            writes(tag);
                            writes(" NO This command is disabled by the system administrator.\r\n");
                            return (0);
                     }
              }

              curtoken=nexttoken();
              if (curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
                     return (-1);

              if (strcmp(curtoken->tokenbuf, "ORDEREDSUBJECT") == 0)
              {
                     thread_func=dothreadorderedsubj;
                     thread_type=search_orderedsubj;
              }
              else if (strcmp(curtoken->tokenbuf, "REFERENCES") == 0)
              {
                     thread_func=dothreadreferences;
                     thread_type=search_references1;
              }
              else
              {
                     return (-1);
              }

              curtoken=nexttoken();
              if (curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
                     return (-1);

              charset=my_strdup(curtoken->tokenbuf);
              curtoken=nexttoken();

              if ((si=alloc_parsesearch(&sihead)) == 0)
              {
                     if (charset)  free(charset);
                     return (-1);
              }

              si=alloc_searchextra(si, &sihead, thread_type);

              if (currenttoken()->tokentype != IT_EOL)
              {
                     if (charset)  free(charset);
                     free_search(sihead);
                     return (-1);
              }

              if (validate_charset(tag, &charset))
              {
                     if (charset)
                            free(charset);
                     return (0);
              }

              writes("* THREAD ");
              (*thread_func)(si, sihead, charset, uid);
              writes("\r\n");
              free(charset);

              for (i=0; i<current_maildir_info.nmessages; i++)
                     if (current_maildir_info.msgs[i].changedflags)
                            fetchflags(i);
              writes(tag);
              writes(" OK THREAD done.\r\n");
              free_search(sihead);
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "SORT") == 0)
       {
       char *charset=0;
       struct searchinfo *si, *sihead;
       unsigned long i;
       struct temp_sort_stack *ts=0;

              {
              const char *p=getenv("IMAP_DISABLETHREADSORT");
              int n= p ? atoi(p):0;

                     if (n > 0)
                     {
                            writes(tag);
                            writes(" NO This command is disabled by the system administrator.\r\n");
                            return (0);
                     }
              }

              curtoken=nexttoken();
              if (curtoken->tokentype != IT_LPAREN)     return (-1);
              while ((curtoken=nexttoken())->tokentype != IT_RPAREN)
              {
              search_type st;
              struct temp_sort_stack *newts;

                     if (curtoken->tokentype != IT_ATOM &&
                            curtoken->tokentype != IT_QUOTED_STRING)
                     {
                            free_temp_sort_stack(ts);
                            return (-1);
                     }

                     if (strcmp(curtoken->tokenbuf, "SUBJECT") == 0)
                     {
                            st=search_orderedsubj;
                     }
                     else if (strcmp(curtoken->tokenbuf, "ARRIVAL") == 0)
                     {
                            st=search_arrival;
                     }
                     else if (strcmp(curtoken->tokenbuf, "CC") == 0)
                     {
                            st=search_cc;
                     }
                     else if (strcmp(curtoken->tokenbuf, "DATE") == 0)
                     {
                            st=search_date;
                     }
                     else if (strcmp(curtoken->tokenbuf, "FROM") == 0)
                     {
                            st=search_from;
                     }
                     else if (strcmp(curtoken->tokenbuf, "REVERSE") == 0)
                     {
                            st=search_reverse;
                     }
                     else if (strcmp(curtoken->tokenbuf, "SIZE") == 0)
                     {
                            st=search_size;
                     }
                     else if (strcmp(curtoken->tokenbuf, "TO") == 0)
                     {
                            st=search_to;
                     }
                     else
                     {
                            free_temp_sort_stack(ts);
                            return (-1);
                     }

                     newts=(struct temp_sort_stack *)malloc(
                            sizeof(struct temp_sort_stack));
                     if (!newts)   write_error_exit(0);
                     newts->next=ts;
                     newts->type=st;
                     ts=newts;
              }

              if (ts == 0   /* No criteria */
                     || ts->type == search_reverse)
                            /* Can't end with the REVERSE keyword */
              {
                     free_temp_sort_stack(ts);
                     return (-1);
              }

              curtoken=nexttoken();
              if (curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
              {
                     free_temp_sort_stack(ts);
                     return (-1);
              }

              charset=my_strdup(curtoken->tokenbuf);
              curtoken=nexttoken();

              if ((si=alloc_parsesearch(&sihead)) == 0)
              {
                     if (charset)  free(charset);
                     free_temp_sort_stack(ts);
                     return (-1);
              }

              while (ts)
              {
              struct temp_sort_stack *cts=ts;

                     ts=cts->next;
                     si=alloc_searchextra(si, &sihead, cts->type);
                     free(cts);
              }

              if (currenttoken()->tokentype != IT_EOL)
              {
                     if (charset)  free(charset);
                     free_search(sihead);
                     return (-1);
              }

              if (validate_charset(tag, &charset))
              {
                     if (charset) free(charset);
                     free_search(sihead);
                     return (0);
              }

              writes("* SORT");
              dosortmsgs(si, sihead, charset, uid);
              writes("\r\n");
              free(charset);

              for (i=0; i<current_maildir_info.nmessages; i++)
                     if (current_maildir_info.msgs[i].changedflags)
                            fetchflags(i);
              writes(tag);
              writes(" OK SORT done.\r\n");
              free_search(sihead);
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "CHECK") == 0)
       {
              if (nexttoken()->tokentype != IT_EOL)     return (-1);
              doNoop(0);
              writes(tag);
              writes(" OK CHECK completed\r\n");
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "EXPUNGE") == 0)
       {
              if (strchr(current_mailbox_acl, ACL_EXPUNGE[0]) == NULL)
              {
                     writes(tag);
                     accessdenied("EXPUNGE", "current mailbox",
                                 ACL_EXPUNGE);
                     return 0;
              }

              if (current_mailbox_ro)
              {
                     writes(tag);
                     writes(" NO Cannot expunge read-only mailbox.\r\n");
                     return 0;
              }

              if (uid)
              {
                     char *msgset;

                     curtoken=nexttoken();
                     if (!ismsgset(curtoken))    return (-1);
                     msgset=my_strdup(curtoken->tokenbuf);
                     if (nexttoken()->tokentype != IT_EOL)     return (-1);

                     do_msgset(msgset, &uid_expunge, NULL, 1);
                     free(msgset);
              }
              else
              {
                     if (nexttoken()->tokentype != IT_EOL)     return (-1);
                     expunge();
              }
              doNoop(0);
              writes(tag);
              writes(" OK EXPUNGE completed\r\n");
              return (0);
       }

       if (strcmp(curtoken->tokenbuf, "COPY") == 0)
       {
       struct maildirsize quotainfo;
       char   *mailbox;
       char   *msgset;
       struct copyquotainfo cqinfo;
       int    has_quota;
       int    isshared;
       struct do_copy_info copy_info;
       unsigned long copy_uidv;
       char access_rights[8];

              curtoken=nexttoken();
              if (!ismsgset(curtoken))    return (-1);
              msgset=my_strdup(curtoken->tokenbuf);

              curtoken=nexttoken_nouc();

              if (curtoken->tokentype != IT_NUMBER &&
                     curtoken->tokentype != IT_ATOM &&
                     curtoken->tokentype != IT_QUOTED_STRING)
              {
                     free(msgset);
                     return (-1);
              }

              mailbox=decode_valid_mailbox(curtoken->tokenbuf, 1);

              if (!mailbox)
              {
                     struct maildir_info mi;

                     free(msgset);

                     if (maildir_info_imap_find(&mi, curtoken->tokenbuf,
                                             getenv("AUTHENTICATED"))
                         == 0)
                     {
                            if (nexttoken()->tokentype == IT_EOL)
                            {
                                   maildir_info_destroy(&mi);
                                   writes(tag);
                                   writes(" NO [TRYCREATE] Mailbox does not exist.\r\n");
                                   return (0);
                            }
                            maildir_info_destroy(&mi);
                     }
                     return (-1);
              }

              {
                     CHECK_RIGHTSM(curtoken->tokenbuf,
                                  append_rights,
                                  ACL_INSERT ACL_DELETEMSGS
                                  ACL_SEEN ACL_WRITE);
                     
                     if (strchr(append_rights, ACL_INSERT[0]) == NULL)
                     {
                            writes(tag);
                            accessdenied("COPY",
                                        curtoken->tokenbuf,
                                        ACL_INSERT);
                            return 0;
                     }

                     strcpy(access_rights, append_rights);
              }

              if (nexttoken()->tokentype != IT_EOL)
              {
                     free(msgset);
                     return (-1);
              }

              if (access(mailbox, 0))
              {
                     writes(tag);
                     writes(" NO [TRYCREATE] Mailbox does not exist.\r\n");
                     free(msgset);
                     free(mailbox);
                     return (0);
              }

              fetch_free_cache();
              cqinfo.destmailbox=mailbox;
              cqinfo.acls=access_rights;

              /*
              ** If the destination is a shared folder, copy it into the
              ** real shared folder.
              */

              isshared=0;
              if (is_sharedsubdir(cqinfo.destmailbox))
              {
              char   *p=malloc(strlen(cqinfo.destmailbox)+sizeof("/shared"));

                     if (!p)       write_error_exit(0);
                     strcat(strcpy(p, cqinfo.destmailbox), "/shared");

                     free(mailbox);
                     mailbox=cqinfo.destmailbox=p;
                     isshared=1;
              }

              cqinfo.nbytes=0;
              cqinfo.nfiles=0;

              has_quota=0;
              if (!isshared && maildirquota_countfolder(cqinfo.destmailbox))
              {
                     if (maildir_openquotafile(&quotainfo,
                                            ".") == 0)
                     {
                            if (quotainfo.fd >= 0)
                                   has_quota=1;
                            maildir_closequotafile(&quotainfo);
                     }

                     if (has_quota > 0 &&
                         do_msgset(msgset, &do_copy_quota_calc, &cqinfo,
                                  uid))
                            has_quota= -1;
              }

              if (has_quota > 0 && cqinfo.nfiles > 0)
              {

                     if (maildir_quota_add_start(".", &quotainfo,
                                              cqinfo.nbytes,
                                              cqinfo.nfiles,
                                              getenv("MAILDIRQUOTA")))
                     {
                            writes(tag);
                            writes(
                     " NO [ALERT] You exceeded your mail quota.\r\n");
                            free(msgset);
                            free(mailbox);
                            return (0);
                     }

                     maildir_quota_add_end(&quotainfo,
                                         cqinfo.nbytes,
                                         cqinfo.nfiles);
              }

              if (is_outbox(mailbox))
              {
                     int counter=0;

                     if (do_msgset(msgset, &do_count, &counter, uid) ||
                         counter > 1)
                     {
                            writes(tag);
                            writes(" NO [ALERT] Only one message may be sent at a time.\r\n");
                            free(msgset);
                            free(mailbox);
                            return (0);
                     }
              }

              copy_info.mailbox=mailbox;
              copy_info.uidplus_list=NULL;
              copy_info.uidplus_tail= &copy_info.uidplus_list;
              copy_info.acls=access_rights;

              if (has_quota < 0 ||
                  do_msgset(msgset, &do_copy_message, &copy_info, uid) ||
                  uidplus_fill(copy_info.mailbox, copy_info.uidplus_list,
                             &copy_uidv))
              {
                     uidplus_abort(copy_info.uidplus_list);
                     writes(tag);
                     writes(" NO [ALERT] COPY failed - no write permission or out of disk space.\r\n");
                     free(msgset);
                     free(mailbox);
                     return (0);
              }

              dirsync(mailbox);

              writes(tag);
              writes(" OK");

              if (copy_info.uidplus_list != NULL)
              {
                     writes(" [COPYUID ");
                     writen(copy_uidv);
                     uidplus_writemsgset(copy_info.uidplus_list, 0);
                     uidplus_writemsgset(copy_info.uidplus_list, 1);
                     writes("]");
              }

              writes(" COPY completed.\r\n");
              uidplus_free(copy_info.uidplus_list);

              free(msgset);
              free(mailbox);
              return (0);
       }
       return (-1);
}

Here is the caller graph for this function:

void mainloop ( void  )

Definition at line 102 of file mainloop.c.

{
       int noerril = 0;

       signal(SIGTERM, sigexit);
       signal(SIGHUP, sigexit);
       signal(SIGINT, sigexit);

       for (;;)
       {
       char   tag[IT_MAX_ATOM_SIZE+1];
       struct imaptoken *curtoken;

              read_timeout(30 * 60);
              curtoken=nexttoken_nouc();
              tag[0]=0;
              if (curtoken->tokentype == IT_ATOM ||
                     curtoken->tokentype == IT_NUMBER)
              {
              int    rc;

                     if (strlen(tag)+strlen(curtoken->tokenbuf) > IT_MAX_ATOM_SIZE)
                            write_error_exit("max atom size too small");
                            
                     strncat(tag, curtoken->tokenbuf, IT_MAX_ATOM_SIZE);
                     rc=do_imap_command(tag);

                     if (rc == 0)
                     {
                            noerril = 0;
                            writeflush();
                            read_eol();
                            continue;
                     }
                     if (rc == -2)
                            continue;
              }

              noerril++;
              if (noerril > 9)
              {
                     errno = 0;
                     write_error_exit("TOO MANY CONSECUTIVE PROTOCOL VIOLATIONS");
              }
              read_eol();
              cmdfail(tag[0] ? tag:"*",
                     "Error in IMAP command received by server.\r\n");
              writeflush();
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static RETSIGTYPE sigexit ( int  n) [static]

Definition at line 28 of file mainloop.c.

{
       static char byemsg[]="* BYE Courier-IMAP server shut down by signal.\r\n";
       const char *a=getenv("AUTHENTICATED");
       char buf[NUMBUFSIZE];
       char msg[1024];
       int l = 0;
       const char *tls=getenv("IMAP_TLS");
       const char *ip=getenv("TCPREMOTEIP");

       if (write(1, byemsg, sizeof(byemsg)-1) < 0)
              exit(1);

       bytes_sent_count += sizeof(byemsg);

       libmail_str_time_t(time(NULL)-start_time, buf);

       if (tls && atoi(tls))
              tls=", starttls=1";
       else
              tls="";

       if (a && *a)
              l = snprintf(msg, sizeof(msg) - 1, "NOTICE: Disconnected during shutdown by signal, user=%s, "
                     "ip=[%s], headers=%lu, body=%lu, rcvd=%lu, sent=%lu, time=%s%s\n",
                     a, ip, header_count, body_count, bytes_received_count, bytes_sent_count,
                     buf, tls);
       else
              l = snprintf(msg, sizeof(msg) - 1, "NOTICE: Disconnected during shutdown by signal, ip=[%s], time=%s%s\n",
                     getenv("TCPREMOTEIP"),
                     buf, tls);

       if (l > 0 && write(2, msg, l))
              ; /* Suppress gcc warning */

       exit(0);
#if    RETSIGTYPE != void
       return (0);
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

unsigned long body_count

Definition at line 42 of file fetch.c.

unsigned long bytes_received_count

Definition at line 41 of file imaptoken.c.

unsigned long bytes_sent_count

Definition at line 42 of file imaptoken.c.

unsigned long header_count

Definition at line 42 of file fetch.c.

time_t start_time

Definition at line 33 of file imaptoken.c.