1 |
/* GNU Mailutils -- a suite of utilities for electronic mail |
/* GNU Mailutils -- a suite of utilities for electronic mail |
2 |
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. |
Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. |
3 |
|
|
4 |
GNU Mailutils is free software; you can redistribute it and/or modify |
GNU Mailutils is free software; you can redistribute it and/or modify |
5 |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
13 |
|
|
14 |
You should have received a copy of the GNU General Public License |
You should have received a copy of the GNU General Public License |
15 |
along with GNU Mailutils; if not, write to the Free Software |
along with GNU Mailutils; if not, write to the Free Software |
16 |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
17 |
|
|
18 |
#include "imap4d.h" |
#include "imap4d.h" |
19 |
|
|
20 |
|
static FILE *ifile; |
21 |
|
static FILE *ofile; |
22 |
|
#ifdef WITH_TLS |
23 |
|
static gnutls_session sfile; |
24 |
|
#endif /* WITH_TLS */ |
25 |
|
|
26 |
static int add2set __P ((size_t **, int *, unsigned long)); |
static int add2set __P ((size_t **, int *, unsigned long)); |
27 |
static const char *sc2string __P ((int)); |
static const char *sc2string __P ((int)); |
28 |
|
|
42 |
char *p; |
char *p; |
43 |
if ((p = s) || (p = *save)) |
if ((p = s) || (p = *save)) |
44 |
{ |
{ |
45 |
while (isspace ((unsigned)*p)) |
while (isspace ((unsigned) *p)) |
46 |
p++; |
p++; |
47 |
if (*p == '"') |
if (*p == '"') |
48 |
{ |
{ |
51 |
while (*p && *p != '"') |
while (*p && *p != '"') |
52 |
p++; |
p++; |
53 |
if (*p == '"') |
if (*p == '"') |
54 |
p++; |
p++; |
55 |
*save = (*p) ? p + 1 : p; |
*save = (*p) ? p + 1 : p; |
56 |
*p = '\0'; |
*p = '\0'; |
57 |
return s; |
return s; |
76 |
for (i = 1; **ptr && i < len; (*ptr)++, buf++, i++) |
for (i = 1; **ptr && i < len; (*ptr)++, buf++, i++) |
77 |
{ |
{ |
78 |
if (**ptr == ' ' || **ptr == '.' |
if (**ptr == ' ' || **ptr == '.' |
79 |
|| **ptr == '(' || **ptr == ')' |
|| **ptr == '(' || **ptr == ')' |
80 |
|| **ptr == '[' || **ptr == ']' |
|| **ptr == '[' || **ptr == ']' |
81 |
|| **ptr == '<' || **ptr == '>' |
|| **ptr == '<' || **ptr == '>' || **ptr == '\r' || **ptr == '\n') |
82 |
|| **ptr == '\r' || **ptr == '\n') |
{ |
83 |
{ |
/* Advance. */ |
84 |
/* Advance. */ |
if (start == (*ptr)) |
85 |
if (start == (*ptr)) |
(*ptr)++; |
86 |
(*ptr)++; |
break; |
87 |
break; |
} |
|
} |
|
88 |
*buf = **ptr; |
*buf = **ptr; |
89 |
} |
} |
90 |
*buf = '\0'; |
*buf = '\0'; |
91 |
/* Skip trailing space. */ |
/* Skip trailing space. */ |
92 |
while (**ptr && **ptr == ' ') |
while (**ptr && **ptr == ' ') |
93 |
(*ptr)++; |
(*ptr)++; |
94 |
return *ptr - start; |
return *ptr - start; |
95 |
} |
} |
96 |
|
|
97 |
/* Remove the surrounding double quotes. */ |
/* Remove the surrounding double quotes. */ |
105 |
{ |
{ |
106 |
char *p = ++s; |
char *p = ++s; |
107 |
while (*p && *p != '"') |
while (*p && *p != '"') |
108 |
p++; |
p++; |
109 |
if (*p == '"') |
if (*p == '"') |
110 |
*p = '\0'; |
*p = '\0'; |
111 |
} |
} |
112 |
*ptr = s; |
*ptr = s; |
113 |
} |
} |
128 |
char *p = util_tilde_expansion (name, delim); |
char *p = util_tilde_expansion (name, delim); |
129 |
if (*p != delim[0]) |
if (*p != delim[0]) |
130 |
{ |
{ |
131 |
char *s = calloc (strlen (homedir) + strlen (delim) + strlen (p) + 1, 1); |
char *s = |
132 |
|
calloc (strlen (homedir) + strlen (delim) + strlen (p) + 1, 1); |
133 |
sprintf (s, "%s%s%s", homedir, delim, p); |
sprintf (s, "%s%s%s", homedir, delim, p); |
134 |
free (p); |
free (p); |
135 |
p = s; |
p = s; |
140 |
static int |
static int |
141 |
comp_int (const void *a, const void *b) |
comp_int (const void *a, const void *b) |
142 |
{ |
{ |
143 |
return *(int*)a - *(int*)b; |
return *(int *) a - *(int *) b; |
144 |
} |
} |
145 |
|
|
146 |
/* Return in set an allocated array contain (n) numbers, for imap messsage set |
/* Return in set an allocated array contain (n) numbers, for imap messsage set |
156 |
FIXME: The algo below is to relaxe, things like <,,,> or <:12> or <20:10> |
FIXME: The algo below is to relaxe, things like <,,,> or <:12> or <20:10> |
157 |
will not generate an error. */ |
will not generate an error. */ |
158 |
int |
int |
159 |
util_msgset (char *s, size_t **set, int *n, int isuid) |
util_msgset (char *s, size_t ** set, int *n, int isuid) |
160 |
{ |
{ |
161 |
unsigned long val = 0; |
unsigned long val = 0; |
162 |
unsigned long low = 0; |
unsigned long low = 0; |
164 |
int status = 0; |
int status = 0; |
165 |
size_t max = 0; |
size_t max = 0; |
166 |
size_t *tmp; |
size_t *tmp; |
167 |
int i,j; |
int i, j; |
168 |
|
|
169 |
status = mailbox_messages_count (mbox, &max); |
status = mailbox_messages_count (mbox, &max); |
170 |
if (status != 0) |
if (status != 0) |
184 |
switch (*s) |
switch (*s) |
185 |
{ |
{ |
186 |
/* isdigit */ |
/* isdigit */ |
187 |
case '0': case '1': case '2': case '3': case '4': |
case '0': |
188 |
case '5': case '6': case '7': case '8': case '9': |
case '1': |
189 |
|
case '2': |
190 |
|
case '3': |
191 |
|
case '4': |
192 |
|
case '5': |
193 |
|
case '6': |
194 |
|
case '7': |
195 |
|
case '8': |
196 |
|
case '9': |
197 |
{ |
{ |
198 |
errno = 0; |
errno = 0; |
199 |
val = strtoul (s, &s, 10); |
val = strtoul (s, &s, 10); |
220 |
low = val; |
low = val; |
221 |
val = tmp; |
val = tmp; |
222 |
} |
} |
223 |
for (;low && low <= val; low++) |
for (; low && low <= val; low++) |
224 |
{ |
{ |
225 |
status = add2set (set, n, low); |
status = add2set (set, n, low); |
226 |
if (status != 0) |
if (status != 0) |
241 |
contiguous set of mesages ranging from the first number to the |
contiguous set of mesages ranging from the first number to the |
242 |
second: |
second: |
243 |
3:5 --> 3 4 5 |
3:5 --> 3 4 5 |
244 |
*/ |
*/ |
245 |
case ':': |
case ':': |
246 |
low = val + 1; |
low = val + 1; |
247 |
s++; |
s++; |
250 |
/* As a convenience. '*' is provided to refer to the highest message |
/* As a convenience. '*' is provided to refer to the highest message |
251 |
number int the mailbox: |
number int the mailbox: |
252 |
5:* --> 5 6 7 8 |
5:* --> 5 6 7 8 |
253 |
*/ |
*/ |
254 |
case '*': |
case '*': |
255 |
{ |
{ |
256 |
val = max; |
val = max; |
264 |
/* IMAP also allows a set of noncontiguous numbers to be specified |
/* IMAP also allows a set of noncontiguous numbers to be specified |
265 |
with the ',' character: |
with the ',' character: |
266 |
1,3,5,7 --> 1 3 5 7 |
1,3,5,7 --> 1 3 5 7 |
267 |
*/ |
*/ |
268 |
case ',': |
case ',': |
269 |
s++; |
s++; |
270 |
break; |
break; |
276 |
*n = 0; |
*n = 0; |
277 |
return EINVAL; |
return EINVAL; |
278 |
|
|
279 |
} /* switch */ |
} /* switch */ |
280 |
|
|
281 |
if (done) |
if (done) |
282 |
break; |
break; |
283 |
} /* while */ |
} /* while */ |
284 |
|
|
285 |
if (low) |
if (low) |
286 |
{ |
{ |
298 |
low = val; |
low = val; |
299 |
val = tmp; |
val = tmp; |
300 |
} |
} |
301 |
for (;low && low <= val; low++) |
for (; low && low <= val; low++) |
302 |
{ |
{ |
303 |
status = add2set (set, n, low); |
status = add2set (set, n, low); |
304 |
if (status != 0) |
if (status != 0) |
312 |
/* Remove duplicates. tmp serves to avoid extra dereferences */ |
/* Remove duplicates. tmp serves to avoid extra dereferences */ |
313 |
tmp = *set; |
tmp = *set; |
314 |
for (i = 0, j = 1; i < *n; i++) |
for (i = 0, j = 1; i < *n; i++) |
315 |
if (tmp[j-1] != tmp[i]) |
if (tmp[j - 1] != tmp[i]) |
316 |
tmp[j++] = tmp[i]; |
tmp[j++] = tmp[i]; |
317 |
*n = j; |
*n = j; |
318 |
return 0; |
return 0; |
319 |
} |
} |
320 |
|
|
321 |
/* Use vfprintf for the dirty work. */ |
static int |
322 |
|
util_send_lowlevel (char *buf) |
323 |
|
{ |
324 |
|
int status; |
325 |
|
|
326 |
|
if (buf) |
327 |
|
{ |
328 |
|
#ifdef WITH_TLS |
329 |
|
if (tls_done) |
330 |
|
status = gnutls_record_send (sfile, buf, strlen (buf)); |
331 |
|
else |
332 |
|
#endif /* WITH_TLS */ |
333 |
|
status = fprintf (ofile, buf); |
334 |
|
} |
335 |
|
|
336 |
|
return status; |
337 |
|
} |
338 |
|
|
339 |
int |
int |
340 |
util_send (const char *format, ...) |
util_send (const char *format, ...) |
341 |
{ |
{ |
342 |
int status; |
char *buf = NULL; |
343 |
|
int status = 0; |
344 |
va_list ap; |
va_list ap; |
345 |
|
|
346 |
va_start (ap, format); |
va_start (ap, format); |
347 |
|
vasprintf (&buf, format, ap); |
348 |
|
|
349 |
if (daemon_param.transcript) |
if (buf) |
350 |
{ |
{ |
351 |
char *buf; |
if (daemon_param.transcript) |
352 |
vasprintf (&buf, format, ap); |
syslog (LOG_DEBUG, "sent: %s", buf); |
353 |
if (buf) |
|
354 |
{ |
status = util_send_lowlevel (buf); |
355 |
syslog (LOG_DEBUG, "sent: %s", buf); |
free (buf); |
|
free (buf); |
|
|
} |
|
356 |
} |
} |
357 |
|
|
|
status = vfprintf (ofile, format, ap); |
|
358 |
va_end (ap); |
va_end (ap); |
359 |
return status; |
return status; |
360 |
} |
} |
392 |
int |
int |
393 |
util_out (int rc, const char *format, ...) |
util_out (int rc, const char *format, ...) |
394 |
{ |
{ |
395 |
|
char *tempbuf = NULL; |
396 |
char *buf = NULL; |
char *buf = NULL; |
397 |
int status; |
int status = 0; |
398 |
va_list ap; |
va_list ap; |
399 |
asprintf (&buf, "* %s%s\r\n", sc2string (rc), format); |
|
400 |
|
asprintf (&tempbuf, "* %s%s\r\n", sc2string (rc), format); |
401 |
va_start (ap, format); |
va_start (ap, format); |
402 |
if (daemon_param.transcript) |
vasprintf (&buf, tempbuf, ap); |
403 |
|
|
404 |
|
if (buf) |
405 |
{ |
{ |
406 |
char *buf1 = NULL; |
if (daemon_param.transcript) |
407 |
vasprintf (&buf1, buf, ap); |
syslog (LOG_DEBUG, "sent: %s", buf); |
408 |
if (buf1) |
|
409 |
{ |
status = util_send_lowlevel (buf); |
410 |
syslog (LOG_DEBUG, "sent: %s", buf1); |
free (buf); |
|
free (buf1); |
|
|
} |
|
411 |
} |
} |
412 |
status = vfprintf (ofile, buf, ap); |
|
413 |
va_end (ap); |
va_end (ap); |
414 |
free (buf); |
free (tempbuf); |
415 |
return status; |
return status; |
416 |
} |
} |
417 |
|
|
419 |
int |
int |
420 |
util_finish (struct imap4d_command *command, int rc, const char *format, ...) |
util_finish (struct imap4d_command *command, int rc, const char *format, ...) |
421 |
{ |
{ |
422 |
|
char *tempbuf = NULL; |
423 |
char *buf = NULL; |
char *buf = NULL; |
424 |
int new_state; |
int new_state; |
425 |
int status; |
int status = 0; |
426 |
va_list ap; |
va_list ap; |
427 |
|
|
428 |
asprintf (&buf, "%s %s%s %s\r\n", command->tag, sc2string (rc), |
asprintf (&tempbuf, "%s %s%s %s\r\n", command->tag, sc2string (rc), |
429 |
command->name, format); |
command->name, format); |
|
|
|
430 |
va_start (ap, format); |
va_start (ap, format); |
431 |
if (daemon_param.transcript) |
vasprintf (&buf, tempbuf, ap); |
432 |
|
|
433 |
|
if (buf) |
434 |
{ |
{ |
435 |
char *buf1 = NULL; |
if (daemon_param.transcript) |
436 |
vasprintf (&buf1, buf, ap); |
syslog (LOG_DEBUG, "sent: %s", buf); |
437 |
if (buf1) |
|
438 |
{ |
status = util_send_lowlevel (buf); |
439 |
syslog (LOG_DEBUG, "sent: %s", buf1); |
free (buf); |
|
free (buf1); |
|
|
} |
|
440 |
} |
} |
441 |
|
|
|
status = vfprintf (ofile, buf, ap); |
|
442 |
va_end (ap); |
va_end (ap); |
443 |
free (buf); |
free (tempbuf); |
444 |
|
|
445 |
/* Reset the state. */ |
/* Reset the state. */ |
446 |
if (rc == RESP_OK) |
if (rc == RESP_OK) |
447 |
new_state = command->success; |
new_state = command->success; |
449 |
new_state = command->failure; |
new_state = command->failure; |
450 |
else |
else |
451 |
new_state = STATE_NONE; |
new_state = STATE_NONE; |
452 |
|
|
453 |
if (new_state != STATE_NONE) |
if (new_state != STATE_NONE) |
454 |
state = new_state; |
state = new_state; |
455 |
|
|
456 |
return status; |
return status; |
457 |
} |
} |
458 |
|
|
463 |
the number of octets, close brace ("}"), and CRLF. |
the number of octets, close brace ("}"), and CRLF. |
464 |
*/ |
*/ |
465 |
char * |
char * |
466 |
imap4d_readline (FILE *fp) |
imap4d_readline (void) |
467 |
{ |
{ |
468 |
char buffer[512]; |
char buffer[512]; |
469 |
size_t len; |
size_t len; |
474 |
if (!line) |
if (!line) |
475 |
imap4d_bye (ERR_NO_MEM); |
imap4d_bye (ERR_NO_MEM); |
476 |
|
|
477 |
line[0] = '\0'; /* start with a empty string. */ |
line[0] = '\0'; /* start with a empty string. */ |
478 |
do |
do |
479 |
{ |
{ |
480 |
alarm (daemon_param.timeout); |
alarm (daemon_param.timeout); |
481 |
if (fgets (buffer, sizeof (buffer), fp) == NULL) |
#ifdef WITH_TLS |
482 |
|
if (tls_done) |
483 |
|
{ |
484 |
|
len = gnutls_record_recv (sfile, buffer, sizeof (buffer) - 1); |
485 |
|
if (len < 0) |
486 |
|
{ |
487 |
|
syslog (LOG_INFO, _("TLS error on read: %s"), |
488 |
|
gnutls_strerror (len)); |
489 |
|
imap4d_bye (ERR_TLS); |
490 |
|
} |
491 |
|
else |
492 |
|
buffer[len] = 0; |
493 |
|
} |
494 |
|
else |
495 |
|
#endif /* WITH_TLS */ |
496 |
|
if (fgets (buffer, sizeof (buffer), ifile) == NULL) |
497 |
{ |
{ |
498 |
if (feof (fp)) |
if (feof (ifile)) |
499 |
syslog (LOG_INFO, _("unexpected eof on input")); |
syslog (LOG_INFO, _("unexpected eof on input")); |
500 |
else if (errno) |
else if (errno) |
501 |
syslog (LOG_INFO, _("error reading from input file: %m")); |
syslog (LOG_INFO, _("error reading from input file: %m")); |
507 |
|
|
508 |
len = strlen (buffer); |
len = strlen (buffer); |
509 |
/* If we were in a litteral substract. We have to do it here since the CR |
/* If we were in a litteral substract. We have to do it here since the CR |
510 |
is part of the count in a literal. */ |
is part of the count in a literal. */ |
511 |
if (number) |
if (number) |
512 |
number -= len; |
number -= len; |
513 |
|
|
514 |
/* Remove CR. */ |
/* Remove CR. */ |
515 |
if (len > 1 && buffer[len - 1] == '\n') |
if (len > 1 && buffer[len - 1] == '\n') |
528 |
total = strlen (line); |
total = strlen (line); |
529 |
|
|
530 |
/* I observe some client requesting long FETCH operations since, I did |
/* I observe some client requesting long FETCH operations since, I did |
531 |
not see any limit in the command length in the RFC, catch things |
not see any limit in the command length in the RFC, catch things |
532 |
here. */ |
here. */ |
533 |
/* Check that we do have a terminated NL line and we are not retrieving |
/* Check that we do have a terminated NL line and we are not retrieving |
534 |
a literal. If we don't continue the read. */ |
a literal. If we don't continue the read. */ |
535 |
if (number <= 0 && total && line[total - 1] != '\n') |
if (number <= 0 && total && line[total - 1] != '\n') |
536 |
continue; |
continue; |
537 |
|
|
538 |
/* Check if the client try to send a literal and make sure we are not |
/* Check if the client try to send a literal and make sure we are not |
539 |
already retrieving a literal. */ |
already retrieving a literal. */ |
540 |
if (number <= 0 && len > 2) |
if (number <= 0 && len > 2) |
541 |
{ |
{ |
542 |
size_t n = total - 1; /* C arrays are 0-based. */ |
size_t n = total - 1; /* C arrays are 0-based. */ |
543 |
/* A literal is this "{number}\n". The CR is already strip. */ |
/* A literal is this "{number}\n". The CR is already strip. */ |
544 |
if (line[n] == '\n' && line[n - 1] == '}') |
if (line[n] == '\n' && line[n - 1] == '}') |
545 |
{ |
{ |
546 |
/* Search for the matching bracket. */ |
/* Search for the matching bracket. */ |
547 |
while (n && line[n] != '{') n--; |
while (n && line[n] != '{') |
548 |
if (line [n] == '{') |
n--; |
549 |
{ |
if (line[n] == '{') |
550 |
char *sp = NULL; |
{ |
551 |
|
char *sp = NULL; |
552 |
/* Truncate where the literal number was. */ |
/* Truncate where the literal number was. */ |
553 |
line[n] = '\0'; |
line[n] = '\0'; |
554 |
number = strtoul (line + n + 1, &sp, 10); |
number = strtoul (line + n + 1, &sp, 10); |
555 |
/* Client can ask for non synchronise literal, |
/* Client can ask for non synchronise literal, |
556 |
if a '+' is append to the octet count. */ |
if a '+' is append to the octet count. */ |
557 |
if (*sp != '+') |
if (*sp != '+') |
558 |
util_send ("+ GO AHEAD\r\n"); |
util_send ("+ GO AHEAD\r\n"); |
559 |
} |
} |
560 |
} |
} |
561 |
} |
} |
562 |
} |
} |
563 |
while (number > 0 || (total && line[total - 1] != '\n')); |
while (number > 0 || (total && line[total - 1] != '\n')); |
564 |
if (daemon_param.transcript) |
if (daemon_param.transcript) |
567 |
} |
} |
568 |
|
|
569 |
char * |
char * |
570 |
imap4d_readline_ex (FILE *fp) |
imap4d_readline_ex (void) |
571 |
{ |
{ |
572 |
int len; |
int len; |
573 |
char *s = imap4d_readline (fp); |
char *s = imap4d_readline (); |
574 |
|
|
575 |
if (s && (len = strlen (s)) > 0 && s[len-1] == '\n') |
if (s && (len = strlen (s)) > 0 && s[len - 1] == '\n') |
576 |
s[len-1] = 0; |
s[len - 1] = 0; |
577 |
return s; |
return s; |
578 |
} |
} |
579 |
|
|
580 |
int |
int |
581 |
util_do_command (char *prompt) |
util_do_command (char *prompt) |
582 |
{ |
{ |
590 |
if (!tag) |
if (!tag) |
591 |
{ |
{ |
592 |
nullcommand.name = ""; |
nullcommand.name = ""; |
593 |
nullcommand.tag = (char *)"*"; |
nullcommand.tag = (char *) "*"; |
594 |
return util_finish (&nullcommand, RESP_BAD, "Null command"); |
return util_finish (&nullcommand, RESP_BAD, "Null command"); |
595 |
} |
} |
596 |
else if (!cmd) |
else if (!cmd) |
607 |
{ |
{ |
608 |
nullcommand.name = ""; |
nullcommand.name = ""; |
609 |
nullcommand.tag = tag; |
nullcommand.tag = tag; |
610 |
return util_finish (&nullcommand, RESP_BAD, "Invalid command"); |
return util_finish (&nullcommand, RESP_BAD, "Invalid command"); |
611 |
} |
} |
612 |
|
|
613 |
command->tag = tag; |
command->tag = tag; |
614 |
|
|
615 |
if (command->states && (command->states & state) == 0) |
if (command->states && (command->states & state) == 0) |
616 |
return util_finish (command, RESP_BAD, "Wrong state"); |
return util_finish (command, RESP_BAD, "Wrong state"); |
617 |
|
|
618 |
len = strlen (sp); |
len = strlen (sp); |
619 |
if (len && sp[len - 1] == '\n') |
if (len && sp[len - 1] == '\n') |
620 |
sp[len - 1] = '\0'; |
sp[len - 1] = '\0'; |
621 |
return command->func (command, sp); |
return command->func (command, sp); |
622 |
} |
} |
627 |
if (!s) |
if (!s) |
628 |
return 0; |
return 0; |
629 |
for (; *s; s++) |
for (; *s; s++) |
630 |
*s = toupper ((unsigned)*s); |
*s = toupper ((unsigned) *s); |
631 |
return 0; |
return 0; |
632 |
} |
} |
633 |
|
|
635 |
int |
int |
636 |
util_start (char *tag) |
util_start (char *tag) |
637 |
{ |
{ |
638 |
(void)tag; |
(void) tag; |
639 |
return 0; |
return 0; |
640 |
} |
} |
641 |
|
|
682 |
} |
} |
683 |
|
|
684 |
static int |
static int |
685 |
add2set (size_t **set, int *n, unsigned long val) |
add2set (size_t ** set, int *n, unsigned long val) |
686 |
{ |
{ |
687 |
size_t *tmp; |
size_t *tmp; |
688 |
tmp = realloc (*set, (*n + 1) * sizeof (**set)); |
tmp = realloc (*set, (*n + 1) * sizeof (**set)); |
700 |
} |
} |
701 |
|
|
702 |
int |
int |
703 |
util_parse_internal_date0 (char *date, time_t *timep, char **endp) |
util_parse_internal_date0 (char *date, time_t * timep, char **endp) |
704 |
{ |
{ |
705 |
struct tm tm; |
struct tm tm; |
706 |
mu_timezone tz; |
mu_timezone tz; |
707 |
time_t time; |
time_t time; |
708 |
char **datep = &date; |
char **datep = &date; |
709 |
|
|
710 |
if (mu_parse_imap_date_time((const char **)datep, &tm, &tz)) |
if (mu_parse_imap_date_time ((const char **) datep, &tm, &tz)) |
711 |
return 1; |
return 1; |
712 |
|
|
713 |
time = mu_tm2time (&tm, &tz); |
time = mu_tm2time (&tm, &tz); |
714 |
if (time == (time_t) -1) |
if (time == (time_t) - 1) |
715 |
return 2; |
return 2; |
716 |
|
|
717 |
*timep = time; |
*timep = time; |
721 |
} |
} |
722 |
|
|
723 |
int |
int |
724 |
util_parse_internal_date (char *date, time_t *timep) |
util_parse_internal_date (char *date, time_t * timep) |
725 |
{ |
{ |
726 |
return util_parse_internal_date0 (date, timep, NULL); |
return util_parse_internal_date0 (date, timep, NULL); |
727 |
} |
} |
728 |
|
|
729 |
|
|
730 |
int |
int |
731 |
util_parse_822_date (char *date, time_t *timep) |
util_parse_822_date (char *date, time_t * timep) |
732 |
{ |
{ |
733 |
struct tm tm; |
struct tm tm; |
734 |
mu_timezone tz; |
mu_timezone tz; |
735 |
const char* p = date; |
const char *p = date; |
736 |
|
|
737 |
if (parse822_date_time(&p, date+strlen(date), &tm, &tz) == 0) |
if (parse822_date_time (&p, date + strlen (date), &tm, &tz) == 0) |
738 |
{ |
{ |
739 |
*timep = mu_tm2time (&tm, &tz); |
*timep = mu_tm2time (&tm, &tz); |
740 |
return 0; |
return 0; |
743 |
} |
} |
744 |
|
|
745 |
int |
int |
746 |
util_parse_ctime_date (const char *date, time_t *timep) |
util_parse_ctime_date (const char *date, time_t * timep) |
747 |
{ |
{ |
748 |
struct tm tm; |
struct tm tm; |
749 |
mu_timezone tz; |
mu_timezone tz; |
750 |
|
|
751 |
if (mu_parse_ctime_date_time(&date, &tm, &tz) == 0) |
if (mu_parse_ctime_date_time (&date, &tm, &tz) == 0) |
752 |
{ |
{ |
753 |
*timep = mu_tm2time (&tm, &tz); |
*timep = mu_tm2time (&tm, &tz); |
754 |
return 0; |
return 0; |
761 |
char * |
char * |
762 |
util_strcasestr (const char *haystack, const char *needle) |
util_strcasestr (const char *haystack, const char *needle) |
763 |
{ |
{ |
764 |
register char *needle_end = strchr(needle, '\0'); |
register char *needle_end = strchr (needle, '\0'); |
765 |
register char *haystack_end = strchr(haystack, '\0'); |
register char *haystack_end = strchr (haystack, '\0'); |
766 |
register size_t needle_len = needle_end - needle; |
register size_t needle_len = needle_end - needle; |
767 |
register size_t needle_last = needle_len - 1; |
register size_t needle_last = needle_len - 1; |
768 |
register const char *begin; |
register const char *begin; |
779 |
register const char *h = begin; |
register const char *h = begin; |
780 |
|
|
781 |
do |
do |
782 |
if (tolower(*h) != tolower(*n)) |
if (tolower (*h) != tolower (*n)) |
783 |
goto loop; /* continue for loop */ |
goto loop; /* continue for loop */ |
784 |
while (--n >= needle && --h >= haystack); |
while (--n >= needle && --h >= haystack); |
785 |
|
|
796 |
{ |
{ |
797 |
char *name; |
char *name; |
798 |
int flag; |
int flag; |
799 |
} _imap4d_attrlist[] = { |
} |
800 |
{ "\\Answered", MU_ATTRIBUTE_ANSWERED }, |
_imap4d_attrlist[] = |
801 |
{ "\\Flagged", MU_ATTRIBUTE_FLAGGED }, |
{ |
802 |
{ "\\Deleted", MU_ATTRIBUTE_DELETED }, |
{ |
803 |
{ "\\Draft", MU_ATTRIBUTE_DRAFT }, |
"\\Answered", MU_ATTRIBUTE_ANSWERED} |
804 |
{ "\\Seen", MU_ATTRIBUTE_READ }, |
, |
805 |
{ "\\Recent", MU_ATTRIBUTE_RECENT }, |
{ |
806 |
}; |
"\\Flagged", MU_ATTRIBUTE_FLAGGED} |
807 |
|
, |
808 |
|
{ |
809 |
|
"\\Deleted", MU_ATTRIBUTE_DELETED} |
810 |
|
, |
811 |
|
{ |
812 |
|
"\\Draft", MU_ATTRIBUTE_DRAFT} |
813 |
|
, |
814 |
|
{ |
815 |
|
"\\Seen", MU_ATTRIBUTE_READ} |
816 |
|
, |
817 |
|
{ |
818 |
|
"\\Recent", MU_ATTRIBUTE_RECENT} |
819 |
|
,}; |
820 |
|
|
821 |
#define NATTR sizeof(_imap4d_attrlist)/sizeof(_imap4d_attrlist[0]) |
#define NATTR sizeof(_imap4d_attrlist)/sizeof(_imap4d_attrlist[0]) |
822 |
|
|
844 |
int i; |
int i; |
845 |
size_t len = 0; |
size_t len = 0; |
846 |
|
|
847 |
if (MU_ATTRIBUTE_IS_UNSEEN(type)) |
if (MU_ATTRIBUTE_IS_UNSEEN (type)) |
848 |
*attr_str = strdup("\\Recent"); |
*attr_str = strdup ("\\Recent"); |
849 |
else |
else |
850 |
*attr_str = NULL; |
*attr_str = NULL; |
851 |
|
|
853 |
if (type & _imap4d_attrlist[i].flag) |
if (type & _imap4d_attrlist[i].flag) |
854 |
{ |
{ |
855 |
attr_list[nattr++] = _imap4d_attrlist[i].name; |
attr_list[nattr++] = _imap4d_attrlist[i].name; |
856 |
len += 1 + strlen(_imap4d_attrlist[i].name); |
len += 1 + strlen (_imap4d_attrlist[i].name); |
857 |
} |
} |
858 |
|
|
859 |
*attr_str = malloc(len+1); |
*attr_str = malloc (len + 1); |
860 |
(*attr_str)[0] = 0; |
(*attr_str)[0] = 0; |
861 |
if (*attr_str) |
if (*attr_str) |
862 |
{ |
{ |
863 |
for (i = 0; i < nattr; i++) |
for (i = 0; i < nattr; i++) |
864 |
{ |
{ |
865 |
strcat(*attr_str, attr_list[i]); |
strcat (*attr_str, attr_list[i]); |
866 |
if (i != nattr-1) |
if (i != nattr - 1) |
867 |
strcat(*attr_str, " "); |
strcat (*attr_str, " "); |
868 |
} |
} |
869 |
} |
} |
870 |
|
|
871 |
if (!*attr_str) |
if (!*attr_str) |
872 |
imap4d_bye (ERR_NO_MEM); |
imap4d_bye (ERR_NO_MEM); |
873 |
return 0; |
return 0; |
874 |
} |
} |
875 |
|
|
876 |
void |
void |
877 |
util_print_flags(attribute_t attr) |
util_print_flags (attribute_t attr) |
878 |
{ |
{ |
879 |
int i; |
int i; |
880 |
int flags = 0; |
int flags = 0; |
881 |
int space = 0; |
int space = 0; |
882 |
|
|
883 |
attribute_get_flags (attr, &flags); |
attribute_get_flags (attr, &flags); |
884 |
for (i = 0; i < _imap4d_nattr; i++) |
for (i = 0; i < _imap4d_nattr; i++) |
885 |
if (flags & _imap4d_attrlist[i].flag) |
if (flags & _imap4d_attrlist[i].flag) |
890 |
space = 1; |
space = 1; |
891 |
util_send (_imap4d_attrlist[i].name); |
util_send (_imap4d_attrlist[i].name); |
892 |
} |
} |
893 |
|
|
894 |
if (MU_ATTRIBUTE_IS_UNSEEN(flags)) |
if (MU_ATTRIBUTE_IS_UNSEEN (flags)) |
895 |
{ |
{ |
896 |
if (space) |
if (space) |
897 |
util_send (" "); |
util_send (" "); |
898 |
util_send ("\\Recent"); |
util_send ("\\Recent"); |
899 |
} |
} |
900 |
} |
} |
903 |
util_attribute_matches_flag (attribute_t attr, const char *item) |
util_attribute_matches_flag (attribute_t attr, const char *item) |
904 |
{ |
{ |
905 |
int flags = 0, mask = 0; |
int flags = 0, mask = 0; |
906 |
|
|
907 |
attribute_get_flags (attr, &flags); |
attribute_get_flags (attr, &flags); |
908 |
util_attribute_to_type (item, &mask); |
util_attribute_to_type (item, &mask); |
909 |
if (mask == MU_ATTRIBUTE_RECENT) |
if (mask == MU_ATTRIBUTE_RECENT) |
914 |
|
|
915 |
|
|
916 |
int |
int |
917 |
util_parse_attributes(char *items, char **save, int *flags) |
util_parse_attributes (char *items, char **save, int *flags) |
918 |
{ |
{ |
919 |
int rc = 0; |
int rc = 0; |
920 |
|
|
943 |
|
|
944 |
int |
int |
945 |
util_base64_encode (const unsigned char *input, size_t input_len, |
util_base64_encode (const unsigned char *input, size_t input_len, |
946 |
unsigned char **output, size_t *output_len) |
unsigned char **output, size_t * output_len) |
947 |
{ |
{ |
948 |
static char b64tab[] = |
static char b64tab[] = |
949 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
950 |
size_t olen = 4 * (input_len + 2) / 3; |
size_t olen = 4 * (input_len + 2) / 3; |
951 |
unsigned char *out = malloc (olen); |
unsigned char *out = malloc (olen); |
952 |
|
|
953 |
if (!out) |
if (!out) |
954 |
return 1; |
return 1; |
955 |
*output = out; |
*output = out; |
959 |
*out++ = b64tab[((input[0] << 4) & 0x30) | (input[1] >> 4)]; |
*out++ = b64tab[((input[0] << 4) & 0x30) | (input[1] >> 4)]; |
960 |
*out++ = b64tab[((input[1] << 2) & 0x3c) | (input[2] >> 6)]; |
*out++ = b64tab[((input[1] << 2) & 0x3c) | (input[2] >> 6)]; |
961 |
*out++ = b64tab[input[2] & 0x3f]; |
*out++ = b64tab[input[2] & 0x3f]; |
962 |
olen -= 4; |
olen -= 4; |
963 |
input_len -= 3; |
input_len -= 3; |
964 |
input += 3; |
input += 3; |
965 |
} |
} |
980 |
|
|
981 |
int |
int |
982 |
util_base64_decode (const unsigned char *input, size_t input_len, |
util_base64_decode (const unsigned char *input, size_t input_len, |
983 |
unsigned char **output, size_t *output_len) |
unsigned char **output, size_t * output_len) |
984 |
{ |
{ |
985 |
static int b64val[128] = { |
static int b64val[128] = { |
986 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
987 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
988 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, |
989 |
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, |
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, |
990 |
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
991 |
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, |
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, |
992 |
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
993 |
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 |
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 |
994 |
}; |
}; |
995 |
int olen = input_len; |
int olen = input_len; |
996 |
unsigned char *out = malloc (olen); |
unsigned char *out = malloc (olen); |
1003 |
if (input[0] > 127 || b64val[input[0]] == -1 |
if (input[0] > 127 || b64val[input[0]] == -1 |
1004 |
|| input[1] > 127 || b64val[input[1]] == -1 |
|| input[1] > 127 || b64val[input[1]] == -1 |
1005 |
|| input[2] > 127 || ((input[2] != '=') && (b64val[input[2]] == -1)) |
|| input[2] > 127 || ((input[2] != '=') && (b64val[input[2]] == -1)) |
1006 |
|| input[3] > 127 || ((input[3] != '=') && (b64val[input[3]] == -1))) |
|| input[3] > 127 || ((input[3] != '=') |
1007 |
|
&& (b64val[input[3]] == -1))) |
1008 |
return -1; |
return -1; |
1009 |
*out++ = (b64val[input[0]] << 2) | (b64val[input[1]] >> 4); |
*out++ = (b64val[input[0]] << 2) | (b64val[input[1]] >> 4); |
1010 |
if (input[2] != '=') |
if (input[2] != '=') |
1032 |
int name_len = 256; |
int name_len = 256; |
1033 |
int status = 1; |
int status = 1; |
1034 |
struct hostent *hp; |
struct hostent *hp; |
1035 |
|
|
1036 |
name = malloc (name_len); |
name = malloc (name_len); |
1037 |
while (name |
while (name |
1038 |
&& (status = gethostname (name, name_len)) == 0 |
&& (status = gethostname (name, name_len)) == 0 |
1045 |
{ |
{ |
1046 |
syslog (LOG_CRIT, _("Can't find out my own hostname")); |
syslog (LOG_CRIT, _("Can't find out my own hostname")); |
1047 |
exit (1); |
exit (1); |
1048 |
} |
} |
1049 |
|
|
1050 |
hp = gethostbyname (name); |
hp = gethostbyname (name); |
1051 |
if (hp) |
if (hp) |
1052 |
{ |
{ |
1053 |
struct in_addr inaddr; |
struct in_addr inaddr; |
1054 |
inaddr.s_addr = *(unsigned int*)hp->h_addr; |
inaddr.s_addr = *(unsigned int *) hp->h_addr; |
1055 |
hp = gethostbyaddr ((const char *)&inaddr, |
hp = gethostbyaddr ((const char *) &inaddr, |
1056 |
sizeof (struct in_addr), AF_INET); |
sizeof (struct in_addr), AF_INET); |
1057 |
if (hp) |
if (hp) |
1058 |
{ |
{ |
1059 |
free (name); |
free (name); |
1060 |
name = strdup ((char *)hp->h_name); |
name = strdup ((char *) hp->h_name); |
1061 |
} |
} |
1062 |
} |
} |
1063 |
localname = name; |
localname = name; |
1073 |
const char *p = pattern, *n = string; |
const char *p = pattern, *n = string; |
1074 |
char c; |
char c; |
1075 |
|
|
1076 |
for (;(c = *p++) != '\0' && *n; n++) |
for (; (c = *p++) != '\0' && *n; n++) |
1077 |
{ |
{ |
1078 |
switch (c) |
switch (c) |
1079 |
{ |
{ |
1135 |
smbox = mbox; |
smbox = mbox; |
1136 |
return mailbox_uidvalidity (smbox, uidvp); |
return mailbox_uidvalidity (smbox, uidvp); |
1137 |
} |
} |
1138 |
|
|
1139 |
|
|
1140 |
|
void |
1141 |
|
util_setio (int infile, int outfile) |
1142 |
|
{ |
1143 |
|
ifile = fdopen (infile, "r"); |
1144 |
|
ofile = fdopen (outfile, "w"); |
1145 |
|
if (!ofile || !ifile) |
1146 |
|
imap4d_bye (ERR_NO_OFILE); |
1147 |
|
|
1148 |
|
setvbuf (ofile, NULL, _IOLBF, 0); |
1149 |
|
} |
1150 |
|
|
1151 |
|
void |
1152 |
|
util_flush_output () |
1153 |
|
{ |
1154 |
|
if (!tls_done) |
1155 |
|
fflush (ofile); |
1156 |
|
} |
1157 |
|
|
1158 |
|
FILE * |
1159 |
|
util_is_ofile () |
1160 |
|
{ |
1161 |
|
return ofile; |
1162 |
|
} |
1163 |
|
|
1164 |
|
#ifdef WITH_TLS |
1165 |
|
|
1166 |
|
int |
1167 |
|
imap4d_init_tls_server () |
1168 |
|
{ |
1169 |
|
sfile = |
1170 |
|
(gnutls_session) mu_init_tls_server (fileno (ifile), fileno (ofile)); |
1171 |
|
if (!sfile) |
1172 |
|
return 0; |
1173 |
|
return 1; |
1174 |
|
} |
1175 |
|
|
1176 |
|
void |
1177 |
|
imap4d_deinit_tls_server () |
1178 |
|
{ |
1179 |
|
mu_deinit_tls_server (sfile); |
1180 |
|
} |
1181 |
|
|
1182 |
|
#endif /* WITH_TLS */ |