Back to index

citadel  8.12
Defines | Functions
imap_list.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Defines

#define MAX_PATTERNS   20

Functions

void imap_list (int num_parms, ConstStr *Params)

Define Documentation

#define MAX_PATTERNS   20

Definition at line 6 of file imap_list.h.


Function Documentation

void imap_list ( int  num_parms,
ConstStr *  Params 
)

Definition at line 190 of file imap_list.c.

{
       struct CitContext *CCC = CC;
       citimap *Imap = CCCIMAP;
       int i, j, paren_nest;
       ImapRoomListFilter ImapFilter;
       int selection_left = (-1);
       int selection_right = (-1);
       int return_left = (-1);
       int root_pos = 2;
       int patterns_left = 3;
       int patterns_right = 3;
       int extended_list_in_use = 0;

       if (num_parms < 4) {
              IReply("BAD arguments invalid");
              return;
       }

       ImapFilter.num_patterns = 1;
       ImapFilter.return_subscribed = 0;
       ImapFilter.return_children = 0;
       ImapFilter.subscribed_rooms_only = 0;
       

       /* parms[1] is the IMAP verb being used (e.g. LIST or LSUB)
        * This tells us how to behave, and what verb to return back to the caller
        */
       safestrncpy(ImapFilter.verb, Params[1].Key, sizeof ImapFilter.verb);
       j = Params[1].len;
       for (i=0; i<j; ++i) {
              ImapFilter.verb[i] = toupper(ImapFilter.verb[i]);
       }

       if (!strcasecmp(ImapFilter.verb, "LSUB")) {
              ImapFilter.subscribed_rooms_only = 1;
       }

       /*
        * Partial implementation of LIST-EXTENDED (which will not get used because
        * we don't advertise it in our capabilities string).  Several requirements:
        *
        * Extraction of selection options:
        *     SUBSCRIBED option: done
        *     RECURSIVEMATCH option: not done yet
        *     REMOTE: safe to silently ignore
        *
        * Extraction of return options:
        *     SUBSCRIBED option: done
        *     CHILDREN option: done, but needs a non-ugly rewrite
        *
        * Multiple match patterns: done
        */

       /*
        * If parameter 2 begins with a '(' character, the client is specifying
        * selection options.  Extract their exact position, and then modify our
        * expectation of where the root folder will be specified.
        */
       if (Params[2].Key[0] == '(') {
              extended_list_in_use = 1;
              selection_left = 2;
              paren_nest = 0;
              for (i=2; i<num_parms; ++i) {
                     for (j=0; Params[i].Key[j]; ++j) {
                            if (Params[i].Key[j] == '(') ++paren_nest;
                            if (Params[i].Key[j] == ')') --paren_nest;
                     }
                     if (paren_nest == 0) {
                            selection_right = i; /* found end of selection options */
                            root_pos = i+1;             /* folder root appears after selection options */
                            i = num_parms + 1;   /* break out of the loop */
                     }
              }
       }

       /* If selection options were found, do something with them.
        */
       if ((selection_left > 0) && (selection_right >= selection_left)) {

              /* Strip off the outer parentheses */
              if (Params[selection_left].Key[0] == '(') {
                     TokenCutLeft(&Imap->Cmd, 
                                 &Params[selection_left], 
                                 1);
              }
              if (Params[selection_right].Key[Params[selection_right].len-1] == ')') {
                     TokenCutRight(&Imap->Cmd, 
                                  &Params[selection_right], 
                                  1);
              }

              for (i=selection_left; i<=selection_right; ++i) {

                     if (!strcasecmp(Params[i].Key, "SUBSCRIBED")) {
                            ImapFilter.subscribed_rooms_only = 1;
                     }

                     else if (!strcasecmp(Params[i].Key, "RECURSIVEMATCH")) {
                            /* FIXME - do this! */
                     }

              }

       }

       /* The folder root appears immediately after the selection options,
        * or in position 2 if no selection options were specified.
        */
       ImapFilter.num_patterns_avail = num_parms + 1;
       ImapFilter.patterns = malloc(ImapFilter.num_patterns_avail * sizeof(StrBuf*));
       memset(ImapFilter.patterns, 0, ImapFilter.num_patterns_avail * sizeof(StrBuf*));

       patterns_left = root_pos + 1;
       patterns_right = root_pos + 1;

       if (Params[patterns_left].Key[0] == '(') {
              extended_list_in_use = 1;
              paren_nest = 0;
              for (i=patterns_left; i<num_parms; ++i) {
                     for (j=0; &Params[i].Key[j]; ++j) {
                            if (Params[i].Key[j] == '(') ++paren_nest;
                            if (Params[i].Key[j] == ')') --paren_nest;
                     }
                     if (paren_nest == 0) {
                            patterns_right = i;  /* found end of patterns */
                            i = num_parms + 1;   /* break out of the loop */
                     }
              }
              ImapFilter.num_patterns = patterns_right - patterns_left + 1;
              for (i=0; i<ImapFilter.num_patterns; ++i) {
                     if (i < MAX_PATTERNS) {
                            ImapFilter.patterns[i] = NewStrBufPlain(NULL, 
                                                               Params[root_pos].len + 
                                                               Params[patterns_left+i].len);
                            if (i == 0) {
                                   if (Params[root_pos].len > 1)
                                          StrBufAppendBufPlain(ImapFilter.patterns[i], 
                                                             1 + CKEY(Params[root_pos]) - 1, 0);
                            }
                            else
                                   StrBufAppendBufPlain(ImapFilter.patterns[i], 
                                                      CKEY(Params[root_pos]), 0);

                            if (i == ImapFilter.num_patterns-1) {
                                   if (Params[patterns_left+i].len > 1)
                                          StrBufAppendBufPlain(ImapFilter.patterns[i], 
                                                             CKEY(Params[patterns_left+i]) - 1, 0);
                            }
                            else StrBufAppendBufPlain(ImapFilter.patterns[i], 
                                                   CKEY(Params[patterns_left+i]), 0);

                     }

              }
       }
       else {
              ImapFilter.num_patterns = 1;
              ImapFilter.patterns[0] = NewStrBufPlain(NULL, 
                                                 Params[root_pos].len + 
                                                 Params[patterns_left].len);
              StrBufAppendBufPlain(ImapFilter.patterns[0], 
                                 CKEY(Params[root_pos]), 0);
              StrBufAppendBufPlain(ImapFilter.patterns[0], 
                                 CKEY(Params[patterns_left]), 0);
       }

       /* If the word "RETURN" appears after the folder pattern list, then the client
        * is specifying return options.
        */
       if (num_parms - patterns_right > 2) if (!strcasecmp(Params[patterns_right+1].Key, "RETURN")) {
              return_left = patterns_right + 2;
              extended_list_in_use = 1;
              paren_nest = 0;
              for (i=return_left; i<num_parms; ++i) {
                     for (j=0;   Params[i].Key[j]; ++j) {
                            if (Params[i].Key[j] == '(') ++paren_nest;
                            if (Params[i].Key[j] == ')') --paren_nest;
                     }

                     /* Might as well look for these while we're in here... */
                     if (Params[i].Key[0] == '(') 
                            TokenCutLeft(&Imap->Cmd, 
                                        &Params[i], 
                                        1);
                     if (Params[i].Key[Params[i].len-1] == ')')
                         TokenCutRight(&Imap->Cmd, 
                                     &Params[i], 
                                     1);

                     IMAP_syslog(LOG_DEBUG, "evaluating <%s>", Params[i].Key);

                     if (!strcasecmp(Params[i].Key, "SUBSCRIBED")) {
                            ImapFilter.return_subscribed = 1;
                     }

                     else if (!strcasecmp(Params[i].Key, "CHILDREN")) {
                            ImapFilter.return_children = 1;
                     }

                     if (paren_nest == 0) {
                            i = num_parms + 1;   /* break out of the loop */
                     }
              }
       }

       /* Now start setting up the data we're going to send to the CtdlForEachRoom() callback.
        */
       
       /* The non-extended LIST command is required to treat an empty
        * ("" string) mailbox name argument as a special request to return the
        * hierarchy delimiter and the root name of the name given in the
        * reference parameter.
        */
       if ( (StrLength(ImapFilter.patterns[0]) == 0) && (extended_list_in_use == 0) ) {
              IAPrintf("* %s (\\Noselect) \"/\" \"\"\r\n", ImapFilter.verb);
       }

       /* Non-empty mailbox names, and any form of the extended LIST command,
        * is handled by this loop.
        */
       else {
              imap_list_floors(ImapFilter.verb, 
                             ImapFilter.num_patterns, 
                             ImapFilter.patterns);
              CtdlForEachRoom(imap_listroom, (char**)&ImapFilter);
       }

       /* 
        * Free the pattern buffers we allocated above.
        */
       for (i=0; i<ImapFilter.num_patterns; ++i) {
              FreeStrBuf(&ImapFilter.patterns[i]);
              free(ImapFilter.patterns);

       }

       IReplyPrintf("OK %s completed", ImapFilter.verb);
}

Here is the call graph for this function:

Here is the caller graph for this function: