4 * Utility functions for the IMAP module.
14 #include "sysdep_decls.h"
17 #include "internet_addressing.h"
18 #include "imap_tools.h"
22 * Output a string to the IMAP client, either as a literal or quoted.
23 * (We do a literal if it has any double-quotes or backslashes.)
25 void imap_strout(char *buf)
30 if (buf == NULL) { /* yeah, we handle this */
34 for (i = 0; i < strlen(buf); ++i) {
35 if ((buf[i] == '\"') || (buf[i] == '\\'))
40 cprintf("{%d}\r\n%s", strlen(buf), buf);
42 cprintf("\"%s\"", buf);
51 * Break a command down into tokens, taking into consideration the
52 * possibility of escaping spaces using quoted tokens
54 int imap_parameterize(char **args, char *buf)
64 original_len = strlen(buf);
66 for (i = 0; i < original_len; ++i) {
68 if ((isspace(buf[i])) && (!in_quote)) {
70 args[num] = &buf[start];
72 if (args[num][0] == '\"') {
74 args[num][strlen(args[num]) - 1] = 0;
77 } else if ((buf[i] == '\"') && (!in_quote)) {
79 } else if ((buf[i] == '\"') && (in_quote)) {
88 * Convert a struct quickroom to an IMAP-compatible mailbox name.
90 void imap_mailboxname(char *buf, int bufsize, struct quickroom *qrbuf)
95 * For mailboxes, just do it straight...
97 if (qrbuf->QRflags & QR_MAILBOX) {
98 safestrncpy(buf, qrbuf->QRname, bufsize);
99 strcpy(buf, &buf[11]);
100 if (!strcasecmp(buf, MAILROOM))
101 strcpy(buf, "INBOX");
104 * Otherwise, prefix the floor name as a "public folders" moniker
107 fl = cgetfloor(qrbuf->QRfloor);
108 snprintf(buf, bufsize, "%s|%s",
116 * Convert an inputted folder name to our best guess as to what an equivalent
117 * room name should be.
119 * If an error occurs, it returns -1. Otherwise...
121 * The lower eight bits of the return value are the floor number on which the
122 * room most likely resides. The upper eight bits may contain flags,
123 * including IR_MAILBOX if we're dealing with a personal room.
126 int imap_roomname(char *rbuf, int bufsize, char *foldername)
133 if (foldername == NULL)
135 levels = num_parms(foldername);
137 /* When we can support hierarchial mailboxes, take this out. */
142 * Convert the crispy idiot's reserved names to our reserved names.
144 if (!strcasecmp(foldername, "INBOX")) {
145 safestrncpy(rbuf, MAILROOM, bufsize);
146 return (0 | IR_MAILBOX);
149 extract(buf, foldername, 0);
150 for (i = 0; i < MAXFLOORS; ++i) {
152 lprintf(9, "floor %d: %s\n", i, fl->f_name); /* FIXME take out */
153 if (fl->f_flags & F_INUSE) {
154 if (!strcasecmp(buf, fl->f_name)) {
155 extract(rbuf, foldername, 1);
161 /* since we don't allow multi-level yet, fail.
162 extract(rbuf, buf, 1);
167 safestrncpy(rbuf, foldername, bufsize);
168 return (0 | IR_MAILBOX);
176 * Output a struct internet_address_list in the form an IMAP client wants
178 void imap_ial_out(struct internet_address_list *ialist)
180 struct internet_address_list *iptr;
182 if (ialist == NULL) {
188 for (iptr = ialist; iptr != NULL; iptr = iptr->next) {
190 imap_strout(iptr->ial_name);
192 imap_strout(iptr->ial_user);
194 imap_strout(iptr->ial_node);
204 * Determine whether the supplied string is a valid message set.
205 * If the string contains only numbers, colons, commas, and asterisks,
206 * return 1 for a valid message set. If any other character is found,
209 int imap_is_message_set(char *buf)
214 return (0); /* stupidity checks */
215 if (strlen(buf) == 0)
218 if (!strcasecmp(buf, "ALL"))
219 return (1); /* macro? why? */
221 for (i = 0; i < strlen(buf); ++i) { /* now start the scan */
231 return (1); /* looks like we're good */
236 * imap_match.c, based on wildmat.c from INN
237 * hacked for Citadel/IMAP by Daniel Malament
240 /* note: not all return statements use these; don't change them */
241 #define WILDMAT_TRUE 1
242 #define WILDMAT_FALSE 0
243 #define WILDMAT_ABORT -1
244 #define WILDMAT_DELIM '|'
247 * Match text and p, return TRUE, FALSE, or ABORT.
249 static int do_imap_match(const char *supplied_text, const char *supplied_p)
252 char lcase_text[SIZ], lcase_p[SIZ];
253 char *text = lcase_text;
256 /* Copy both strings and lowercase them, in order to
257 * make this entire operation case-insensitive.
259 for (i=0; i<=strlen(supplied_text); ++i)
260 lcase_text[i] = tolower(supplied_text[i]);
261 for (i=0; i<=strlen(supplied_p); ++i)
262 p[i] = tolower(supplied_p[i]);
265 for (; *p; text++, p++) {
266 if ((*text == '\0') && (*p != '*') && (*p != '%')) {
267 return WILDMAT_ABORT;
272 return WILDMAT_FALSE;
277 while (++p, ((*p == '*') || (*p == '%'))) {
278 /* Consecutive stars or %'s act
279 * just like one star.
284 /* Trailing star matches everything. */
288 if ((matched = do_imap_match(text++, p))
293 return WILDMAT_ABORT;
295 while (++p, ((*p == '*') || (*p == '%'))) {
296 /* Consecutive %'s act just like one, but even
297 * a single star makes the sequence act like
307 * Trailing % matches everything
308 * without a delimiter.
311 if (*text == WILDMAT_DELIM) {
312 return WILDMAT_FALSE;
318 while (*text && (*(text - 1) != WILDMAT_DELIM)) {
319 if ((matched = do_imap_match(text++, p))
324 return WILDMAT_ABORT;
328 return (*text == '\0');
334 * Support function for mailbox pattern name matching in LIST and LSUB
335 * Returns nonzero if the supplied mailbox name matches the supplied pattern.
337 int imap_mailbox_matches_pattern(char *pattern, char *mailboxname)
339 /* handle just-star case quickly */
340 if ((pattern[0] == '*') && (pattern[1] == '\0')) {
343 return (do_imap_match(mailboxname, pattern) == WILDMAT_TRUE);