+++ /dev/null
-/*
- * Utility functions for the IMAP module.
- *
- * Copyright (c) 2001-2017 by the citadel.org team and others, except for
- * most of the UTF7 and UTF8 handling code which was lifted from Evolution.
- *
- * This program is open source software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#define SHOW_ME_VAPPEND_PRINTF
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdarg.h>
-#include <libcitadel.h>
-#include "citadel.h"
-#include "sysdep_decls.h"
-#include "internet_addressing.h"
-#include "serv_imap.h"
-#include "imap_tools.h"
-#include "ctdl_module.h"
-
-/* String handling helpers */
-
-/* This code uses some pretty nasty string manipulation. To make everything
- * manageable, we use this semi-high-level string manipulation API. Strings are
- * always \0-terminated, despite the fact that we keep track of the size.
- */
-struct string {
- char* buffer;
- int maxsize;
- int size;
-};
-
-static void string_init(struct string* s, char* buf, int bufsize)
-{
- s->buffer = buf;
- s->maxsize = bufsize-1;
- s->size = strlen(buf);
-}
-
-static char* string_end(struct string* s)
-{
- return s->buffer + s->size;
-}
-
-/* Append a UTF8 string of a particular length (in bytes). -1 to autocalculate. */
-
-static void string_append_sn(struct string* s, char* p, int len)
-{
- if (len == -1)
- len = strlen(p);
- if ((s->size+len) > s->maxsize)
- len = s->maxsize - s->size;
- memcpy(s->buffer + s->size, p, len);
- s->size += len;
- s->buffer[s->size] = '\0';
-}
-
-/* As above, always autocalculate. */
-
-#define string_append_s(s, p) string_append_sn((s), (p), -1)
-
-/* Appends a UTF8 character --- which may make the size change by more than 1!
- * If the string overflows, the last character may become invalid. */
-
-static void string_append_c(struct string* s, int c)
-{
- char UmlChar[5];
- int len = 0;
-
- /* Don't do anything if there's no room. */
-
- if (s->size == s->maxsize)
- return;
-
- if (c <= 0x7F)
- {
- /* This is the most common case, so we optimise it. */
-
- s->buffer[s->size++] = c;
- s->buffer[s->size] = 0;
- return;
- }
- else if (c <= 0x7FF)
- {
- UmlChar[0] = 0xC0 | (c >> 6);
- UmlChar[1] = 0x80 | (c & 0x3F);
- len = 2;
- }
- else if (c <= 0xFFFF)
- {
- UmlChar[0] = 0xE0 | (c >> 12);
- UmlChar[1] = 0x80 | ((c >> 6) & 0x3f);
- UmlChar[2] = 0x80 | (c & 0x3f);
- len = 3;
- }
- else
- {
- UmlChar[0] = 0xf0 | c >> 18;
- UmlChar[1] = 0x80 | ((c >> 12) & 0x3f);
- UmlChar[2] = 0x80 | ((c >> 6) & 0x3f);
- UmlChar[3] = 0x80 | (c & 0x3f);
- len = 4;
- }
-
- string_append_sn(s, UmlChar, len);
-}
-
-/* Reads a UTF8 character from a char*, advancing the pointer. */
-
-int utf8_getc(char** ptr)
-{
- unsigned char* p = (unsigned char*) *ptr;
- unsigned char c, r;
- int v, m;
-
- for (;;)
- {
- r = *p++;
- loop:
- if (r < 0x80)
- {
- *ptr = (char*) p;
- v = r;
- break;
- }
- else if (r < 0xf8)
- {
- /* valid start char? (max 4 octets) */
- v = r;
- m = 0x7f80; /* used to mask out the length bits */
- do {
- c = *p++;
- if ((c & 0xc0) != 0x80)
- {
- r = c;
- goto loop;
- }
- v = (v<<6) | (c & 0x3f);
- r<<=1;
- m<<=5;
- } while (r & 0x40);
-
- *ptr = (char*)p;
-
- v &= ~m;
- break;
- }
- }
-
- return v;
-}
-
-/* IMAP name safety */
-
-/* IMAP has certain special requirements in its character set, which means we
- * have to do a fair bit of work to convert Citadel's UTF8 strings to IMAP
- * strings. The next two routines (and their data tables) do that.
- */
-
-static char *utf7_alphabet =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
-
-static unsigned char utf7_rank[256] = {
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3E,0x3F,0xFF,0xFF,0xFF,
- 0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,
- 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
- 0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-};
-
-/* Base64 helpers. */
-
-static void utf7_closeb64(struct string* out, int v, int i)
-{
- int x;
-
- if (i > 0)
- {
- x = (v << (6-i)) & 0x3F;
- string_append_c(out, utf7_alphabet[x]);
- }
- string_append_c(out, '-');
-}
-
-/* Convert from a Citadel name to an IMAP-safe name. Returns the end
- * of the destination.
- */
-static char* toimap(char* destp, char* destend, char* src)
-{
- struct string dest;
- int state = 0;
- int v = 0;
- int i = 0;
-
- *destp = 0;
- string_init(&dest, destp, destend-destp);
- /* syslog(LOG_DEBUG, "toimap %s", src); */
-
- for (;;)
- {
- int c = utf8_getc(&src);
- if (c == '\0')
- break;
-
- if (c >= 0x20 && c <= 0x7e)
- {
- if (state == 1)
- {
- utf7_closeb64(&dest, v, i);
- state = 0;
- i = 0;
- }
-
- switch (c)
- {
- case '&':
- string_append_sn(&dest, "&-", 2);
- break;
-
- case '/':
- /* Citadel extension: / becomes |, because /
- * isn't valid as part of an IMAP name. */
-
- c = '|';
- goto defaultcase;
-
- case '\\':
- /* Citadel extension: backslashes mark folder
- * seperators in the IMAP subfolder emulation
- * hack. We turn them into / characters,
- * *except* if it's the last character in the
- * string. */
-
- if (*src != '\0')
- c = '/';
- /* fall through */
-
- default:
- defaultcase:
- string_append_c(&dest, c);
- }
- }
- else
- {
- if (state == 0)
- {
- string_append_c(&dest, '&');
- state = 1;
- }
- v = (v << 16) | c;
- i += 16;
- while (i >= 6)
- {
- int x = (v >> (i-6)) & 0x3f;
- string_append_c(&dest, utf7_alphabet[x]);
- i -= 6;
- }
- }
- }
-
- if (state == 1)
- utf7_closeb64(&dest, v, i);
- /* syslog(LOG_DEBUG, " -> %s", destp); */
- return string_end(&dest);
-}
-
-/* Convert from an IMAP-safe name back into a Citadel name. Returns the end of the destination. */
-
-static int cfrommap(int c);
-static char* fromimap(char* destp, char* destend, const char* src)
-{
- struct string dest;
- unsigned const char *p = (unsigned const char*) src;
- int v = 0;
- int i = 0;
- int state = 0;
- int c;
-
- *destp = 0;
- string_init(&dest, destp, destend-destp);
- /* syslog(LOG_DEBUG, "fromimap %s", src); */
-
- do {
- c = *p++;
- switch (state)
- {
- case 0:
- /* US-ASCII characters. */
-
- if (c == '&')
- state = 1;
- else
- string_append_c(&dest, cfrommap(c));
- break;
-
- case 1:
- if (c == '-')
- {
- string_append_c(&dest, '&');
- state = 0;
- }
- else if (utf7_rank[c] != 0xff)
- {
- v = utf7_rank[c];
- i = 6;
- state = 2;
- }
- else
- {
- /* invalid char */
- string_append_sn(&dest, "&-", 2);
- state = 0;
- }
- break;
-
- case 2:
- if (c == '-')
- state = 0;
- else if (utf7_rank[c] != 0xFF)
- {
- v = (v<<6) | utf7_rank[c];
- i += 6;
- if (i >= 16)
- {
- int x = (v >> (i-16)) & 0xFFFF;
- string_append_c(&dest, cfrommap(x));
- i -= 16;
- }
- }
- else
- {
- string_append_c(&dest, cfrommap(c));
- state = 0;
- }
- break;
- }
- } while (c != '\0');
-
- /* syslog(LOG_DEBUG, " -> %s", destp); */
- return string_end(&dest);
-}
-
-/* Undoes the special character conversion. */
-static int cfrommap(int c)
-{
- switch (c)
- {
- case '|': return '/';
- case '/': return '\\';
- }
- return c;
-}
-
-
-/* Break a command down into tokens, unquoting any escaped characters. */
-void MakeStringOf(StrBuf *Buf, int skip)
-{
- int i;
- citimap_command *Cmd = &IMAP->Cmd;
-
- for (i=skip; i<Cmd->num_parms; ++i) {
- StrBufAppendBufPlain(Buf, Cmd->Params[i].Key, Cmd->Params[i].len, 0);
- if (i < (Cmd->num_parms-1)) StrBufAppendBufPlain(Buf, HKEY(" "), 0);
- }
-}
-
-
-void TokenCutRight(citimap_command *Cmd,
- ConstStr *CutMe,
- int n)
-{
- const char *CutAt;
-
- if (CutMe->len < n) {
- CutAt = CutMe->Key;
- CutMe->len = 0;
- }
- else {
- CutAt = CutMe->Key + CutMe->len - n;
- CutMe->len -= n;
- }
- StrBufPeek(Cmd->CmdBuf, CutAt, -1, '\0');
-}
-
-void TokenCutLeft(citimap_command *Cmd,
- ConstStr *CutMe,
- int n)
-{
- if (CutMe->len < n) {
- CutMe->Key += CutMe->len;
- CutMe->len = 0;
- }
- else {
- CutMe->Key += n;
- CutMe->len -= n;
- }
-}
-
-
-
-int CmdAdjust(citimap_command *Cmd,
- int nArgs,
- int Realloc)
-{
- ConstStr *Params;
- if (nArgs > Cmd->avail_parms) {
- Params = (ConstStr*) malloc(sizeof(ConstStr) * nArgs);
- if (Realloc) {
- memcpy(Params,
- Cmd->Params,
- sizeof(ConstStr) * Cmd->avail_parms);
-
- memset(Cmd->Params +
- sizeof(ConstStr) * Cmd->avail_parms,
- 0,
- sizeof(ConstStr) * nArgs -
- sizeof(ConstStr) * Cmd->avail_parms
- );
- }
- else {
- Cmd->num_parms = 0;
- memset(Params, 0,
- sizeof(ConstStr) * nArgs);
- }
- Cmd->avail_parms = nArgs;
- if (Cmd->Params != NULL)
- free (Cmd->Params);
- Cmd->Params = Params;
- }
- else {
- if (!Realloc) {
- memset(Cmd->Params,
- 0,
- sizeof(ConstStr) * Cmd->avail_parms);
- Cmd->num_parms = 0;
- }
- }
- return Cmd->avail_parms;
-}
-
-int imap_parameterize(citimap_command *Cmd)
-{
- int nArgs;
- const char *In, *End;
-
- In = ChrPtr(Cmd->CmdBuf);
- End = In + StrLength(Cmd->CmdBuf);
-
- /* we start with 10 chars per arg, maybe we need to realloc later. */
- nArgs = StrLength(Cmd->CmdBuf) / 10 + 10;
- nArgs = CmdAdjust(Cmd, nArgs, 0);
- while (In < End)
- {
- /* Skip whitespace. */
- while (isspace(*In))
- In++;
- if (*In == '\0')
- break;
-
- /* Found the start of a token. */
-
- Cmd->Params[Cmd->num_parms].Key = In;
-
- /* Read in the token. */
-
- for (;;)
- {
- if (isspace(*In))
- break;
-
- if (*In == '\"')
- {
- /* Found a quoted section. */
-
- Cmd->Params[Cmd->num_parms].Key++;
- //In++;
- for (;;)
- {
- In++;
- if (*In == '\"') {
- StrBufPeek(Cmd->CmdBuf, In, -1, '\0');
- break;
- }
- else if (*In == '\\')
- In++;
-
- if (*In == '\0') {
- Cmd->Params[Cmd->num_parms].len =
- In - Cmd->Params[Cmd->num_parms].Key;
- Cmd->num_parms++;
- return Cmd->num_parms;
- }
- }
- break;
- }
- else if (*In == '\\')
- {
- In++;
- }
-
- if (*In == '\0') {
- Cmd->Params[Cmd->num_parms].len =
- In - Cmd->Params[Cmd->num_parms].Key;
- Cmd->num_parms++;
- return Cmd->num_parms;
- }
- In++;
- }
- StrBufPeek(Cmd->CmdBuf, In, -1, '\0');
- Cmd->Params[Cmd->num_parms].len =
- In - Cmd->Params[Cmd->num_parms].Key;
- if (Cmd->num_parms + 1 >= Cmd->avail_parms) {
- nArgs = CmdAdjust(Cmd, nArgs * 2, 1);
- }
- Cmd->num_parms ++;
- In++;
- }
- return Cmd->num_parms;
-}
-
-
-/* Convert a struct ctdlroom to an IMAP-compatible mailbox name. */
-long imap_mailboxname(char *buf, int bufsize, struct ctdlroom *qrbuf)
-{
- char* bufend = buf+bufsize;
- struct floor *fl;
- char* p = buf;
- const char *pend;
-
- /* For mailboxes, just do it straight.
- * Do the Cyrus-compatible thing: all private folders are
- * subfolders of INBOX. */
-
- if (qrbuf->QRflags & QR_MAILBOX)
- {
- if (strcasecmp(qrbuf->QRname+11, MAILROOM) == 0)
- {
- pend = toimap(p, bufend, "INBOX");
- return pend - buf;
- }
- else
- {
- p = toimap(p, bufend, "INBOX");
- if (p < bufend)
- *p++ = '/';
- pend = toimap(p, bufend, qrbuf->QRname+11);
- return pend - buf;
- }
- }
- else
- {
- /* Otherwise, prefix the floor name as a "public folders" moniker. */
-
- fl = CtdlGetCachedFloor(qrbuf->QRfloor);
- p = toimap(p, bufend, fl->f_name);
- if (p < bufend)
- *p++ = '/';
- pend = toimap(p, bufend, qrbuf->QRname);
- return pend - buf;
- }
-}
-
-/*
- * Convert an inputted folder name to our best guess as to what an equivalent
- * room name should be.
- *
- * If an error occurs, it returns -1. Otherwise...
- *
- * The lower eight bits of the return value are the floor number on which the
- * room most likely resides. The upper eight bits may contain flags,
- * including IR_MAILBOX if we're dealing with a personal room.
- *
- */
-int imap_roomname(char *rbuf, int bufsize, const char *foldername)
-{
- int levels;
- char floorname[ROOMNAMELEN*2];
- char roomname[ROOMNAMELEN];
- int i;
- struct floor *fl;
- int ret = (-1);
-
- if (foldername == NULL)
- return(-1);
-
- /* Unmunge the entire string into the output buffer. */
-
- fromimap(rbuf, rbuf+bufsize, foldername);
-
- /* Is this an IMAP inbox? */
-
- if (strncasecmp(rbuf, "INBOX", 5) == 0)
- {
- if (rbuf[5] == 0)
- {
- /* It's the system inbox. */
-
- safestrncpy(rbuf, MAILROOM, bufsize);
- ret = (0 | IR_MAILBOX);
- goto exit;
- }
- else if (rbuf[5] == FDELIM)
- {
- /* It's another personal mail folder. */
-
- safestrncpy(rbuf, rbuf+6, bufsize);
- ret = (0 | IR_MAILBOX);
- goto exit;
- }
-
- /* If we get here, the folder just happens to start with INBOX
- * --- fall through. */
- }
-
- /* Is this a multi-level room name? */
-
- levels = num_tokens(rbuf, FDELIM);
- if (levels > 1)
- {
- long len;
- /* Extract the main room name. */
-
- len = extract_token(floorname, rbuf, 0, FDELIM, sizeof floorname);
- if (len < 0) len = 0;
- safestrncpy(roomname, &rbuf[len + 1], sizeof(roomname));
-
- /* Try and find it on any floor. */
-
- for (i = 0; i < MAXFLOORS; ++i)
- {
- fl = CtdlGetCachedFloor(i);
- if (fl->f_flags & F_INUSE)
- {
- if (strcasecmp(floorname, fl->f_name) == 0)
- {
- /* Got it! */
-
- safestrncpy(rbuf, roomname, bufsize);
- ret = i;
- goto exit;
- }
- }
- }
- }
-
- /* Meh. It's either not a multi-level room name, or else we
- * couldn't find it.
- */
- ret = (0 | IR_MAILBOX);
-
-exit:
- syslog(LOG_DEBUG, "(That translates to \"%s\")", rbuf);
- return(ret);
-}
-
-
-/*
- * Determine whether the supplied string is a valid message set.
- * If the string contains only numbers, colons, commas, and asterisks,
- * return 1 for a valid message set. If any other character is found,
- * return 0.
- */
-int imap_is_message_set(const char *buf)
-{
- int i;
-
- if (buf == NULL)
- return (0); /* stupidity checks */
- if (IsEmptyStr(buf))
- return (0);
-
- if (!strcasecmp(buf, "ALL"))
- return (1); /* macro? why? */
-
- for (i = 0; buf[i]; ++i) { /* now start the scan */
- if (
- (!isdigit(buf[i]))
- && (buf[i] != ':')
- && (buf[i] != ',')
- && (buf[i] != '*')
- )
- return (0);
- }
-
- return (1); /* looks like we're good */
-}
-
-
-/*
- * imap_match.c, based on wildmat.c from INN
- * hacked for Citadel/IMAP by Daniel Malament
- */
-
-/* note: not all return statements use these; don't change them */
-#define WILDMAT_TRUE 1
-#define WILDMAT_FALSE 0
-#define WILDMAT_ABORT -1
-#define WILDMAT_DELIM '/'
-
-/*
- * Match text and p, return TRUE, FALSE, or ABORT.
- */
-static int do_imap_match(const char *supplied_text, const char *supplied_p)
-{
- int matched, i;
- char lcase_text[SIZ], lcase_p[SIZ];
- char *text;
- char *p;
-
- /* Copy both strings and lowercase them, in order to
- * make this entire operation case-insensitive.
- */
- for (i=0;
- ((supplied_text[i] != '\0') &&
- (i < sizeof(lcase_text)));
- ++i)
- lcase_text[i] = tolower(supplied_text[i]);
- lcase_text[i] = '\0';
-
- for (i=0;
- ((supplied_p[i] != '\0') &&
- (i < sizeof(lcase_p)));
- ++i)
- lcase_p[i] = tolower(supplied_p[i]);
- lcase_p[i] = '\0';
-
- /* Start matching */
- for (p = lcase_p, text = lcase_text;
- !IsEmptyStr(p) && !IsEmptyStr(text);
- text++, p++) {
- if ((*text == '\0') && (*p != '*') && (*p != '%')) {
- return WILDMAT_ABORT;
- }
- switch (*p) {
- default:
- if (*text != *p) {
- return WILDMAT_FALSE;
- }
- continue;
- case '*':
-star:
- while (++p, ((*p == '*') || (*p == '%'))) {
- /* Consecutive stars or %'s act
- * just like one star.
- */
- continue;
- }
- if (*p == '\0') {
- /* Trailing star matches everything. */
- return WILDMAT_TRUE;
- }
- while (*text) {
- if ((matched = do_imap_match(text++, p))
- != WILDMAT_FALSE) {
- return matched;
- }
- }
- return WILDMAT_ABORT;
- case '%':
- while (++p, (!IsEmptyStr(p) && ((*p == '*') || (*p == '%'))))
- {
- /* Consecutive %'s act just like one, but even
- * a single star makes the sequence act like
- * one star, instead.
- */
- if (*p == '*') {
- goto star;
- }
- continue;
- }
- if (*p == '\0') {
- /*
- * Trailing % matches everything
- * without a delimiter.
- */
- while (!IsEmptyStr(text)) {
- if (*text == WILDMAT_DELIM) {
- return WILDMAT_FALSE;
- }
- text++;
- }
- return WILDMAT_TRUE;
- }
- while (!IsEmptyStr(text) &&
- /* make sure text - 1 isn't before lcase_p */
- ((text == lcase_text) || (*(text - 1) != WILDMAT_DELIM)))
- {
- if ((matched = do_imap_match(text++, p))
- != WILDMAT_FALSE) {
- return matched;
- }
- }
- return WILDMAT_ABORT;
- }
- }
-
- if ((*text == '\0') && (*p == '\0')) return WILDMAT_TRUE;
- else return WILDMAT_FALSE;
-}
-
-
-/*
- * Support function for mailbox pattern name matching in LIST and LSUB
- * Returns nonzero if the supplied mailbox name matches the supplied pattern.
- */
-int imap_mailbox_matches_pattern(const char *pattern, char *mailboxname)
-{
- /* handle just-star case quickly */
- if ((pattern[0] == '*') && (pattern[1] == '\0')) {
- return WILDMAT_TRUE;
- }
- return (do_imap_match(mailboxname, pattern) == WILDMAT_TRUE);
-}
-
-
-
-/*
- * Compare an IMAP date string (date only, no time) to the date found in
- * a Unix timestamp.
- */
-int imap_datecmp(const char *datestr, time_t msgtime) {
- char daystr[256];
- char monthstr[256];
- char yearstr[256];
- int i;
- int day, month, year;
- int msgday, msgmonth, msgyear;
- struct tm msgtm;
-
- char *imap_datecmp_ascmonths[12] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
-
- if (datestr == NULL) return(0);
-
- /* Expecting a date in the form dd-Mmm-yyyy */
- extract_token(daystr, datestr, 0, '-', sizeof daystr);
- extract_token(monthstr, datestr, 1, '-', sizeof monthstr);
- extract_token(yearstr, datestr, 2, '-', sizeof yearstr);
-
- day = atoi(daystr);
- year = atoi(yearstr);
- month = 0;
- for (i=0; i<12; ++i) {
- if (!strcasecmp(monthstr, imap_datecmp_ascmonths[i])) {
- month = i;
- }
- }
-
- /* Extract day/month/year from message timestamp */
- localtime_r(&msgtime, &msgtm);
- msgday = msgtm.tm_mday;
- msgmonth = msgtm.tm_mon;
- msgyear = msgtm.tm_year + 1900;
-
- /* Now start comparing */
-
- if (year < msgyear) return(+1);
- if (year > msgyear) return(-1);
-
- if (month < msgmonth) return(+1);
- if (month > msgmonth) return(-1);
-
- if (day < msgday) return(+1);
- if (day > msgday) return(-1);
-
- return(0);
-}
-
-
-void IAPrintf(const char *Format, ...)
-{
- va_list arg_ptr;
-
- va_start(arg_ptr, Format);
- StrBufVAppendPrintf(IMAP->Reply, Format, arg_ptr);
- va_end(arg_ptr);
-}
-
-
-void iaputs(const char *Str, long Len)
-{
- StrBufAppendBufPlain(IMAP->Reply, Str, Len, 0);
-}
-
-
-void ireply(const char *Msg, long len)
-{
- citimap *Imap = IMAP;
-
- StrBufAppendBufPlain(Imap->Reply,
- CKEY(Imap->Cmd.Params[0]), 0);
- StrBufAppendBufPlain(Imap->Reply,
- HKEY(" "), 0);
- StrBufAppendBufPlain(Imap->Reply,
- Msg, len, 0);
-
- StrBufAppendBufPlain(Imap->Reply,
- HKEY("\r\n"), 0);
-
-}
-
-
-void IReplyPrintf(const char *Format, ...)
-{
- citimap *Imap = IMAP;
- va_list arg_ptr;
-
-
- StrBufAppendBufPlain(Imap->Reply,
- CKEY(Imap->Cmd.Params[0]), 0);
-
- StrBufAppendBufPlain(Imap->Reply,
- HKEY(" "), 0);
-
- va_start(arg_ptr, Format);
- StrBufVAppendPrintf(IMAP->Reply, Format, arg_ptr);
- va_end(arg_ptr);
-
- StrBufAppendBufPlain(Imap->Reply,
- HKEY("\r\n"), 0);
-
-}
-
-
-/* Output a string to the IMAP client, either as a literal or quoted.
- * (We do a literal if it has any double-quotes or backslashes.) */
-void IPutStr(const char *Msg, long Len)
-{
- int i;
- int is_literal = 0;
- citimap *Imap = IMAP;
-
-
- if ((Msg == NULL) || (Len == 0))
- { /* yeah, we handle this */
- StrBufAppendBufPlain(Imap->Reply, HKEY("NIL"), 0);
- return;
- }
-
- for (i = 0; i < Len; ++i) {
- if ((Msg[i] == '\"') || (Msg[i] == '\\'))
- is_literal = 1;
- }
-
- if (is_literal) {
- StrBufAppendPrintf(Imap->Reply, "{%ld}\r\n", Len);
- StrBufAppendBufPlain(Imap->Reply, Msg, Len, 0);
- } else {
- StrBufAppendBufPlain(Imap->Reply,
- HKEY("\""), 0);
- StrBufAppendBufPlain(Imap->Reply,
- Msg, Len, 0);
- StrBufAppendBufPlain(Imap->Reply,
- HKEY("\""), 0);
- }
-}
-
-void IUnbuffer (void)
-{
- citimap *Imap = IMAP;
-
- cputbuf(Imap->Reply);
- FlushStrBuf(Imap->Reply);
-}