~ubuntu-branches/debian/stretch/alpine/stretch

« back to all changes in this revision

Viewing changes to pith/imap.c

  • Committer: Bazaar Package Importer
  • Author(s): Asheesh Laroia
  • Date: 2007-02-17 13:17:42 UTC
  • Revision ID: james.westby@ubuntu.com-20070217131742-99x5c6cpg1pbkdhw
Tags: upstream-0.82+dfsg
ImportĀ upstreamĀ versionĀ 0.82+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if !defined(lint) && !defined(DOS)
 
2
static char rcsid[] = "$Id: imap.c 394 2007-01-25 20:29:45Z hubert@u.washington.edu $";
 
3
#endif
 
4
 
 
5
/*
 
6
 * ========================================================================
 
7
 * Copyright 2006 University of Washington
 
8
 *
 
9
 * Licensed under the Apache License, Version 2.0 (the "License");
 
10
 * you may not use this file except in compliance with the License.
 
11
 * You may obtain a copy of the License at
 
12
 *
 
13
 *     http://www.apache.org/licenses/LICENSE-2.0
 
14
 *
 
15
 * ========================================================================
 
16
 */
 
17
 
 
18
#include "../pith/headers.h"
 
19
#include "../pith/imap.h"
 
20
#include "../pith/msgno.h"
 
21
#include "../pith/state.h"
 
22
#include "../pith/flag.h"
 
23
#include "../pith/status.h"
 
24
#include "../pith/conftype.h"
 
25
#include "../pith/context.h"
 
26
#include "../pith/thread.h"
 
27
#include "../pith/mailview.h"
 
28
#include "../pith/mailpart.h"
 
29
#include "../pith/mailindx.h"
 
30
#include "../pith/save.h"
 
31
#include "../pith/util.h"
 
32
#include "../pith/stream.h"
 
33
 
 
34
 
 
35
/*
 
36
 * Internal prototypes
 
37
 */
 
38
long  imap_seq_exec(MAILSTREAM *, char *, long (*)(MAILSTREAM *, long, void *), void *);
 
39
long  imap_seq_exec_append(MAILSTREAM *, long, void *);
 
40
char *ps_get(size_t);
 
41
 
 
42
 
 
43
/*
 
44
 * Exported globals setup by searching functions to tell mm_searched
 
45
 * where to put message numbers that matched the search criteria,
 
46
 * and to allow mm_searched to return number of matches.
 
47
 */
 
48
MAILSTREAM *mm_search_stream;
 
49
long        mm_search_count  = 0L;
 
50
MAILSTATUS  mm_status_result;
 
51
 
 
52
MM_LIST_S  *mm_list_info;
 
53
 
 
54
MMLOGIN_S  *mm_login_list     = NULL;
 
55
MMLOGIN_S  *cert_failure_list = NULL;
 
56
 
 
57
/*
 
58
 * Instead of storing cached passwords in free storage, store them in this
 
59
 * private space. This makes it easier and more reliable when we want
 
60
 * to zero this space out. We only store passwords here (char *) so we
 
61
 * don't need to worry about alignment.
 
62
 */
 
63
static  char       private_store[1024];
 
64
 
 
65
static  int        critical_depth = 0;
 
66
 
 
67
#ifdef  SIGINT
 
68
RETSIGTYPE (*hold_int)(int);
 
69
#endif
 
70
 
 
71
#ifdef  SIGTERM
 
72
RETSIGTYPE (*hold_term)(int);
 
73
#endif
 
74
 
 
75
#ifdef  SIGHUP
 
76
RETSIGTYPE (*hold_hup)(int);
 
77
#endif
 
78
 
 
79
#ifdef  SIGUSR2
 
80
RETSIGTYPE (*hold_usr2)(int);
 
81
#endif
 
82
 
 
83
 
 
84
 
 
85
/*---------------------------------------------------------------------- 
 
86
        receive notification that search found something           
 
87
 
 
88
 Input:  mail stream and message number of located item
 
89
 
 
90
 Result: nothing, not used by pine
 
91
  ----*/
 
92
void
 
93
mm_searched(MAILSTREAM *stream, long unsigned int rawno)
 
94
{
 
95
    MESSAGECACHE *mc;
 
96
 
 
97
    if(rawno > 0L && stream && rawno <= stream->nmsgs
 
98
       && (mc = mail_elt(stream, rawno))){
 
99
        mc->searched = 1;
 
100
        if(stream == mm_search_stream)
 
101
          mm_search_count++;
 
102
    }
 
103
}
 
104
 
 
105
 
 
106
/*----------------------------------------------------------------------
 
107
       receive notification of new mail from imap daemon
 
108
 
 
109
   Args: stream -- The stream the message count report is for.
 
110
         number -- The number of messages now in folder.
 
111
 
 
112
  Result: Sets value in pine state indicating new mailbox size
 
113
 
 
114
     Called when the number of messages in the mailbox goes up.  This
 
115
 may also be called as a result of an expunge. It increments the
 
116
 new_mail_count based on a the difference between the current idea of
 
117
 the maximum number of messages and what mm_exists claims. The new mail
 
118
 notification is done in newmail.c
 
119
 
 
120
 Only worry about the cases when the number grows, as mm_expunged
 
121
 handles shrinkage...
 
122
 
 
123
 ----*/
 
124
void
 
125
mm_exists(MAILSTREAM *stream, long unsigned int number)
 
126
{
 
127
    long     new_this_call, n;
 
128
    int      exbits = 0, lflags = 0;
 
129
    MSGNO_S *msgmap;
 
130
 
 
131
#ifdef DEBUG
 
132
    if(ps_global->debug_imap > 1 || ps_global->debugmem)
 
133
      dprint((3, "=== mm_exists(%lu,%s) called ===\n", number,
 
134
     !stream ? "(no stream)" : !stream->mailbox ? "(null)" : stream->mailbox));
 
135
#endif
 
136
 
 
137
    msgmap = sp_msgmap(stream);
 
138
    if(!msgmap)
 
139
      return;
 
140
 
 
141
    if(mn_get_nmsgs(msgmap) != (long) number){
 
142
        sp_set_mail_box_changed(stream, 1);
 
143
        /* titlebar will be affected */
 
144
        if(ps_global->mail_stream == stream)
 
145
          ps_global->mangled_header = 1;
 
146
    }
 
147
 
 
148
    if(mn_get_nmsgs(msgmap) < (long) number){
 
149
        new_this_call = (long) number - mn_get_nmsgs(msgmap);
 
150
        sp_set_new_mail_count(stream,
 
151
                              sp_new_mail_count(stream) + new_this_call);
 
152
        if(ps_global->mail_stream != stream)
 
153
          sp_set_recent_since_visited(stream,
 
154
                              sp_recent_since_visited(stream) + new_this_call);
 
155
 
 
156
        mn_add_raw(msgmap, new_this_call);
 
157
 
 
158
        /*
 
159
         * Set local "recent" and "hidden" bits...
 
160
         */
 
161
        for(n = 0; n < new_this_call; n++, number--){
 
162
            if(msgno_exceptions(stream, number, "0", &exbits, FALSE))
 
163
              exbits |= MSG_EX_RECENT;
 
164
            else
 
165
              exbits = MSG_EX_RECENT;
 
166
 
 
167
            msgno_exceptions(stream, number, "0", &exbits, TRUE);
 
168
 
 
169
            if(SORT_IS_THREADED(msgmap))
 
170
              lflags |= MN_USOR;
 
171
 
 
172
            /*
 
173
             * If we're zoomed, then hide this message too since
 
174
             * it couldn't have possibly been selected yet...
 
175
             */
 
176
            lflags |= (any_lflagged(msgmap, MN_HIDE) ? MN_HIDE : 0);
 
177
            if(lflags)
 
178
              set_lflag(stream, msgmap, mn_get_total(msgmap) - n, lflags, 1);
 
179
        }
 
180
    }
 
181
}
 
182
 
 
183
 
 
184
/*----------------------------------------------------------------------
 
185
    Receive notification from IMAP that a single message has been expunged
 
186
 
 
187
   Args: stream -- The stream/folder the message is expunged from
 
188
         rawno  -- The raw message number that was expunged
 
189
 
 
190
mm_expunged is always called on an expunge.  Simply remove all 
 
191
reference to the expunged message, shifting internal mappings as
 
192
necessary.
 
193
  ----*/
 
194
void
 
195
mm_expunged(MAILSTREAM *stream, long unsigned int rawno)
 
196
{
 
197
    MESSAGECACHE *mc;
 
198
    long          i;
 
199
    int           is_current = 0;
 
200
    MSGNO_S      *msgmap;
 
201
 
 
202
#ifdef DEBUG
 
203
    if(ps_global->debug_imap > 1 || ps_global->debugmem)
 
204
      dprint((3, "mm_expunged(%s,%lu)\n",
 
205
               stream
 
206
                ? (stream->mailbox
 
207
                    ? stream->mailbox
 
208
                    : "(no stream)")
 
209
                : "(null)", rawno));
 
210
#endif
 
211
 
 
212
    msgmap = sp_msgmap(stream);
 
213
    if(!msgmap)
 
214
      return;
 
215
 
 
216
    if(ps_global->mail_stream == stream)
 
217
      is_current++;
 
218
 
 
219
    if(i = mn_raw2m(msgmap, (long) rawno)){
 
220
        dprint((7, "mm_expunged: rawno=%lu msgno=%ld nmsgs=%ld max_msgno=%ld flagged_exld=%ld\n", rawno, i, mn_get_nmsgs(msgmap), mn_get_total(msgmap), msgmap->flagged_exld));
 
221
 
 
222
        sp_set_mail_box_changed(stream, 1);
 
223
        sp_set_expunge_count(stream, sp_expunge_count(stream) + 1);
 
224
 
 
225
        if(is_current){
 
226
            reset_check_point(stream);
 
227
            ps_global->mangled_header = 1;
 
228
 
 
229
            /* flush invalid cache entries */
 
230
            while(i <= mn_get_total(msgmap))
 
231
              clear_index_cache_ent(stream, i++, 0);
 
232
 
 
233
            /* let app know what happened */
 
234
            mm_expunged_current(rawno);
 
235
        }
 
236
    }
 
237
    else{
 
238
        dprint((7,
 
239
               "mm_expunged: rawno=%lu was excluded, flagged_exld was %d\n",
 
240
               rawno, msgmap->flagged_exld));
 
241
        dprint((7, "             nmsgs=%ld max_msgno=%ld\n",
 
242
               mn_get_nmsgs(msgmap), mn_get_total(msgmap)));
 
243
        if(rawno > 0L && rawno <= stream->nmsgs)
 
244
          mc = mail_elt(stream, rawno);
 
245
 
 
246
        if(!mc){
 
247
            dprint((7, "             cannot get mail_elt(%lu)\n",
 
248
                   rawno));
 
249
        }
 
250
        else{
 
251
            dprint((7, "             mail_elt(%lu)->spare2=%d\n",
 
252
                   rawno, (int) (mc->spare2)));
 
253
        }
 
254
    }
 
255
 
 
256
    if(SORT_IS_THREADED(msgmap)
 
257
       && (SEP_THRDINDX()
 
258
           || ps_global->thread_disp_style != THREAD_NONE)){
 
259
        long cur;
 
260
 
 
261
        /*
 
262
         * When we're sorting with a threaded method an expunged
 
263
         * message may cause the rest of the sort to be wrong. This
 
264
         * isn't so bad if we're just looking at the index. However,
 
265
         * it also causes the thread tree (PINETHRD_S) to become
 
266
         * invalid, so if we're using a threading view we need to
 
267
         * sort in order to fix the tree and to protect fetch_thread().
 
268
         */
 
269
        sp_set_need_to_rethread(stream, 1);
 
270
 
 
271
        /*
 
272
         * If we expunged the current message which was a member of the
 
273
         * viewed thread, and the adjustment to current will take us
 
274
         * out of that thread, fix it if we can, by backing current up
 
275
         * into the thread. We'd like to just check after mn_flush_raw
 
276
         * below but the problem is that the elts won't change until
 
277
         * after we return from mm_expunged. So we have to manually
 
278
         * check the other messages for CHID2 flags instead of thinking
 
279
         * that we can expunge the current message and then check. It won't
 
280
         * work because the elt will still refer to the expunged message.
 
281
         */
 
282
        if(sp_viewing_a_thread(stream)
 
283
           && get_lflag(stream, NULL, rawno, MN_CHID2)
 
284
           && mn_total_cur(msgmap) == 1
 
285
           && mn_is_cur(msgmap, mn_raw2m(msgmap, (long) rawno))
 
286
           && (cur = mn_get_cur(msgmap)) > 1L
 
287
           && cur < mn_get_total(msgmap)
 
288
           && !get_lflag(stream, msgmap, cur + 1L, MN_CHID2)
 
289
           && get_lflag(stream, msgmap, cur - 1L, MN_CHID2))
 
290
          mn_set_cur(msgmap, cur - 1L);
 
291
    }
 
292
 
 
293
    /*
 
294
     * Keep on top of our special flag counts.
 
295
     * 
 
296
     * NOTE: This is allowed since mail_expunged releases
 
297
     * data for this message after the callback.
 
298
     */
 
299
    if(rawno > 0L && rawno <= stream->nmsgs && (mc = mail_elt(stream, rawno))){
 
300
        if(mc->spare)
 
301
          msgmap->flagged_hid--;
 
302
 
 
303
        if(mc->spare2)
 
304
          msgmap->flagged_exld--;
 
305
 
 
306
        if(mc->spare3)
 
307
          msgmap->flagged_tmp--;
 
308
 
 
309
        if(mc->spare4)
 
310
          msgmap->flagged_chid--;
 
311
 
 
312
        if(mc->spare8)
 
313
          msgmap->flagged_chid2--;
 
314
 
 
315
        if(mc->spare5)
 
316
          msgmap->flagged_coll--;
 
317
 
 
318
        if(mc->spare6)
 
319
          msgmap->flagged_stmp--;
 
320
 
 
321
        if(mc->spare7)
 
322
          msgmap->flagged_usor--;
 
323
 
 
324
        if(mc->spare || mc->spare4)
 
325
          msgmap->flagged_invisible--;
 
326
 
 
327
        free_pine_elt(&mc->sparep);
 
328
    }
 
329
 
 
330
    /*
 
331
     * if it's in the sort array, flush it, otherwise
 
332
     * decrement raw sequence numbers greater than "rawno"
 
333
     */
 
334
    mn_flush_raw(msgmap, (long) rawno);
 
335
}
 
336
 
 
337
 
 
338
void
 
339
mm_flags(MAILSTREAM *stream, long unsigned int rawno)
 
340
{
 
341
    /*
 
342
     * The idea here is to clean up any data pine might have cached
 
343
     * that has anything to do with the indicated message number.
 
344
     */
 
345
    if(stream == ps_global->mail_stream){
 
346
        long        msgno, t;
 
347
        PINETHRD_S *thrd;
 
348
 
 
349
        if(scores_are_used(SCOREUSE_GET) & SCOREUSE_STATEDEP)
 
350
          clear_msg_score(stream, rawno);
 
351
 
 
352
        msgno = mn_raw2m(sp_msgmap(stream), (long) rawno);
 
353
 
 
354
        /* if in thread index */
 
355
        if(THRD_INDX()){
 
356
            if((thrd = fetch_thread(stream, rawno))
 
357
               && thrd->top
 
358
               && (thrd = fetch_thread(stream, thrd->top))
 
359
               && thrd->rawno
 
360
               && (t = mn_raw2m(sp_msgmap(stream), thrd->rawno)))
 
361
              clear_index_cache_ent(stream, t, 0);
 
362
        }
 
363
        else if(THREADING()){
 
364
            if(msgno > 0L)
 
365
              clear_index_cache_ent(stream, msgno, 0);
 
366
 
 
367
            /*
 
368
             * If a parent is collapsed, clear that parent's
 
369
             * index cache entry.
 
370
             */
 
371
            if((thrd = fetch_thread(stream, rawno)) && thrd->parent){
 
372
                thrd = fetch_thread(stream, thrd->parent);
 
373
                while(thrd){
 
374
                    if(get_lflag(stream, NULL, thrd->rawno, MN_COLL)
 
375
                       && (t = mn_raw2m(sp_msgmap(stream), (long) thrd->rawno)))
 
376
                      clear_index_cache_ent(stream, t, 0);
 
377
 
 
378
                    if(thrd->parent)
 
379
                      thrd = fetch_thread(stream, thrd->parent);
 
380
                    else
 
381
                      thrd = NULL;
 
382
                }
 
383
            }
 
384
        }
 
385
        else if(msgno > 0L)
 
386
          clear_index_cache_ent(stream, msgno, 0);
 
387
 
 
388
        if(msgno && mn_is_cur(sp_msgmap(stream), msgno))
 
389
          ps_global->mangled_header = 1;
 
390
    }
 
391
            
 
392
    /*
 
393
     * We count up flag changes here. The
 
394
     * dont_count_flagchanges variable tries to prevent us from
 
395
     * counting when we're just fetching flags.
 
396
     */
 
397
    if(!(ps_global->dont_count_flagchanges
 
398
         && stream == ps_global->mail_stream)){
 
399
        int exbits;
 
400
 
 
401
        check_point_change(stream);
 
402
 
 
403
        /* we also note flag changes for filtering purposes */
 
404
        if(msgno_exceptions(stream, rawno, "0", &exbits, FALSE))
 
405
          exbits |= MSG_EX_STATECHG;
 
406
        else
 
407
          exbits = MSG_EX_STATECHG;
 
408
 
 
409
        msgno_exceptions(stream, rawno, "0", &exbits, TRUE);
 
410
    }
 
411
}
 
412
 
 
413
 
 
414
void
 
415
mm_list(MAILSTREAM *stream, int delimiter, char *mailbox, long int attributes)
 
416
{
 
417
#ifdef DEBUG
 
418
    if(ps_global->debug_imap > 2 || ps_global->debugmem)
 
419
      dprint((5, "mm_list \"%s\": delim: '%c', %s%s%s%s%s%s\n",
 
420
               mailbox ? mailbox : "?", delimiter ? delimiter : 'X',
 
421
               (attributes & LATT_NOINFERIORS) ? ", no inferiors" : "",
 
422
               (attributes & LATT_NOSELECT) ? ", no select" : "",
 
423
               (attributes & LATT_MARKED) ? ", marked" : "",
 
424
               (attributes & LATT_UNMARKED) ? ", unmarked" : "",
 
425
               (attributes & LATT_HASCHILDREN) ? ", has children" : "",
 
426
               (attributes & LATT_HASNOCHILDREN) ? ", has no children" : ""));
 
427
#endif
 
428
 
 
429
    if(!mm_list_info->stream || stream == mm_list_info->stream)
 
430
      (*mm_list_info->filter)(stream, mailbox, delimiter,
 
431
                              attributes, mm_list_info->data,
 
432
                              mm_list_info->options);
 
433
}
 
434
 
 
435
 
 
436
void
 
437
mm_lsub(MAILSTREAM *stream, int delimiter, char *mailbox, long int attributes)
 
438
{
 
439
#ifdef DEBUG
 
440
    if(ps_global->debug_imap > 2 || ps_global->debugmem)
 
441
      dprint((5, "LSUB \"%s\": delim: '%c', %s%s%s%s%s%s\n",
 
442
               mailbox ? mailbox : "?", delimiter ? delimiter : 'X',
 
443
               (attributes & LATT_NOINFERIORS) ? ", no inferiors" : "",
 
444
               (attributes & LATT_NOSELECT) ? ", no select" : "",
 
445
               (attributes & LATT_MARKED) ? ", marked" : "",
 
446
               (attributes & LATT_UNMARKED) ? ", unmarked" : "",
 
447
               (attributes & LATT_HASCHILDREN) ? ", has children" : "",
 
448
               (attributes & LATT_HASNOCHILDREN) ? ", has no children" : ""));
 
449
#endif
 
450
 
 
451
    if(!mm_list_info->stream || stream == mm_list_info->stream)
 
452
      (*mm_list_info->filter)(stream, mailbox, delimiter,
 
453
                              attributes, mm_list_info->data,
 
454
                              mm_list_info->options);
 
455
}
 
456
 
 
457
 
 
458
void
 
459
mm_status(MAILSTREAM *stream, char *mailbox, MAILSTATUS *status)
 
460
{
 
461
    /*
 
462
     * We implement mail_status for the #move namespace by adding a wrapper
 
463
     * routine, pine_mail_status. It may have to call the real mail_status
 
464
     * twice for #move folders and combine the results. It sets
 
465
     * pine_cached_status to point to a local status variable to store the
 
466
     * intermediate results.
 
467
     */
 
468
    if(pine_cached_status != NULL)
 
469
      *pine_cached_status = *status;
 
470
    else
 
471
      mm_status_result = *status;
 
472
 
 
473
#ifdef DEBUG
 
474
    if(status){
 
475
        if(pine_cached_status)
 
476
          dprint((2,
 
477
                 "mm_status: Preliminary pass for #move\n"));
 
478
 
 
479
        dprint((2, "mm_status: Mailbox \"%s\"",
 
480
               mailbox ? mailbox : "?"));
 
481
        if(status->flags & SA_MESSAGES)
 
482
          dprint((2, ", %lu messages", status->messages));
 
483
 
 
484
        if(status->flags & SA_RECENT)
 
485
          dprint((2, ", %lu recent", status->recent));
 
486
 
 
487
        if(status->flags & SA_UNSEEN)
 
488
          dprint((2, ", %lu unseen", status->unseen));
 
489
 
 
490
        if(status->flags & SA_UIDVALIDITY)
 
491
          dprint((2, ", %lu UID validity", status->uidvalidity));
 
492
 
 
493
        if(status->flags & SA_UIDNEXT)
 
494
          dprint((2, ", %lu next UID", status->uidnext));
 
495
 
 
496
        dprint((2, "\n"));
 
497
    }
 
498
#endif
 
499
}
 
500
 
 
501
 
 
502
/*----------------------------------------------------------------------
 
503
      Write imap debugging information into log file
 
504
 
 
505
   Args: strings -- the string for the debug file
 
506
 
 
507
 Result: message written to the debug log file
 
508
  ----*/
 
509
void
 
510
mm_dlog(char *string)
 
511
{
 
512
    char *p, *q = NULL, save, *continued;
 
513
    int   more = 1;
 
514
 
 
515
#ifdef  _WINDOWS
 
516
    mswin_imaptelemetry(string);
 
517
#endif
 
518
#ifdef  DEBUG
 
519
    continued = "";
 
520
    p = string;
 
521
#ifdef DEBUGJOURNAL
 
522
    /* because string can be really long and we don't want to lose any of it */
 
523
    if(p)
 
524
      more = 1;
 
525
 
 
526
    while(more){
 
527
        if(q){
 
528
            *q = save;
 
529
            p = q;
 
530
            continued = "(Continuation line) ";
 
531
        }
 
532
 
 
533
        if(strlen(p) > 63000){
 
534
            q = p + 60000;
 
535
            save = *q;
 
536
            *q = '\0';
 
537
        }
 
538
        else
 
539
          more = 0;
 
540
#endif
 
541
        dprint(((ps_global->debug_imap >= 4 && debug < 4) ? debug : 4,
 
542
                "IMAP DEBUG %s%s: %s\n",
 
543
                continued ? continued : "",
 
544
                debug_time(1, ps_global->debug_timestamp), p ? p : "?"));
 
545
#ifdef DEBUGJOURNAL
 
546
    }
 
547
#endif
 
548
#endif
 
549
}
 
550
 
 
551
 
 
552
/*----------------------------------------------------------------------
 
553
     Ignore signals when imap is running through critical code
 
554
 
 
555
 Args: stream -- The stream on which critical operation is proceeding
 
556
 ----*/
 
557
 
 
558
void 
 
559
mm_critical(MAILSTREAM *stream)
 
560
{
 
561
    stream = stream; /* For compiler complaints that this isn't used */
 
562
 
 
563
    if(++critical_depth == 1){
 
564
 
 
565
#ifdef  SIGHUP
 
566
        hold_hup  = signal(SIGHUP, SIG_IGN);
 
567
#endif
 
568
#ifdef  SIGUSR2
 
569
        hold_usr2 = signal(SIGUSR2, SIG_IGN);
 
570
#endif
 
571
#ifdef  SIGINT
 
572
        hold_int  = signal(SIGINT, SIG_IGN);
 
573
#endif
 
574
#ifdef  SIGTERM
 
575
        hold_term = signal(SIGTERM, SIG_IGN);
 
576
#endif
 
577
    }
 
578
 
 
579
    dprint((9, "IMAP critical (depth now %d) on %s\n",
 
580
              critical_depth,
 
581
              (stream && stream->mailbox) ? stream->mailbox : "<no folder>" ));
 
582
}
 
583
 
 
584
 
 
585
/*----------------------------------------------------------------------
 
586
   Reset signals after critical imap code
 
587
 ----*/
 
588
void
 
589
mm_nocritical(MAILSTREAM *stream)
 
590
 
591
    stream = stream; /* For compiler complaints that this isn't used */
 
592
 
 
593
    if(--critical_depth == 0){
 
594
 
 
595
#ifdef  SIGHUP
 
596
        (void)signal(SIGHUP, hold_hup);
 
597
#endif
 
598
#ifdef  SIGUSR2
 
599
        (void)signal(SIGUSR2, hold_usr2);
 
600
#endif
 
601
#ifdef  SIGINT
 
602
        (void)signal(SIGINT, hold_int);
 
603
#endif
 
604
#ifdef  SIGTERM
 
605
        (void)signal(SIGTERM, hold_term);
 
606
#endif
 
607
    }
 
608
 
 
609
    critical_depth = MAX(critical_depth, 0);
 
610
 
 
611
    dprint((9, "Done with IMAP critical (depth now %d) on %s\n",
 
612
              critical_depth,
 
613
              (stream && stream->mailbox) ? stream->mailbox : "<no folder>" ));
 
614
}
 
615
 
 
616
 
 
617
void
 
618
mm_fatal(char *message)
 
619
{
 
620
    panic(message);
 
621
}
 
622
 
 
623
 
 
624
char *
 
625
imap_referral(MAILSTREAM *stream, char *ref, long int code)
 
626
{
 
627
    char *buf = NULL;
 
628
 
 
629
    if(ref && !struncmp(ref, "imap://", 7)){
 
630
        char *folder = NULL;
 
631
        imapuid_t uid_val, uid;
 
632
        int rv;
 
633
 
 
634
        rv = url_imap_folder(ref, &folder, &uid, &uid_val, NULL, 1);
 
635
        switch(code){
 
636
          case REFAUTHFAILED :
 
637
          case REFAUTH :
 
638
            if((rv & URL_IMAP_IMAILBOXLIST) && (rv & URL_IMAP_ISERVERONLY))
 
639
              buf = cpystr(folder);
 
640
 
 
641
            break;
 
642
 
 
643
          case REFSELECT :
 
644
          case REFCREATE :
 
645
          case REFDELETE :
 
646
          case REFRENAME :
 
647
          case REFSUBSCRIBE :
 
648
          case REFUNSUBSCRIBE :
 
649
          case REFSTATUS :
 
650
          case REFCOPY :
 
651
          case REFAPPEND :
 
652
            if(rv & URL_IMAP_IMESSAGELIST)
 
653
              buf = cpystr(folder);
 
654
 
 
655
            break;
 
656
 
 
657
          default :
 
658
            break;
 
659
        }
 
660
 
 
661
        if(folder)
 
662
          fs_give((void **) &folder);
 
663
    }
 
664
 
 
665
    return(buf);
 
666
}
 
667
 
 
668
 
 
669
long
 
670
imap_proxycopy(MAILSTREAM *stream, char *sequence, char *mailbox, long int flags)
 
671
{
 
672
    SE_APP_S args;
 
673
 
 
674
    args.folder = mailbox;
 
675
    args.flags  = flags;
 
676
 
 
677
    return(imap_seq_exec(stream, sequence, imap_seq_exec_append, &args));
 
678
}
 
679
 
 
680
 
 
681
long
 
682
imap_seq_exec(MAILSTREAM *stream, char *sequence,
 
683
              long int (*func)(MAILSTREAM *, long int, void *),
 
684
              void *args)
 
685
{
 
686
    unsigned long i,j,x;
 
687
    MESSAGECACHE *mc;
 
688
 
 
689
    while (*sequence) {         /* while there is something to parse */
 
690
        if (*sequence == '*') { /* maximum message */
 
691
            if(!(i = stream->nmsgs)){
 
692
                mm_log ("No messages, so no maximum message number",ERROR);
 
693
                return(0L);
 
694
            }
 
695
 
 
696
            sequence++;         /* skip past * */
 
697
        }
 
698
        else if (!(i = strtoul ((const char *) sequence,&sequence,10))
 
699
                 || (i > stream->nmsgs)){
 
700
            mm_log ("Sequence invalid",ERROR);
 
701
            return(0L);
 
702
        }
 
703
 
 
704
        switch (*sequence) {    /* see what the delimiter is */
 
705
          case ':':                     /* sequence range */
 
706
            if (*++sequence == '*') {   /* maximum message */
 
707
                if (stream->nmsgs) j = stream->nmsgs;
 
708
                else {
 
709
                    mm_log ("No messages, so no maximum message number",ERROR);
 
710
                    return NIL;
 
711
                }
 
712
 
 
713
                sequence++;             /* skip past * */
 
714
            }
 
715
                                /* parse end of range */
 
716
            else if (!(j = strtoul ((const char *) sequence,&sequence,10)) ||
 
717
                     (j > stream->nmsgs)) {
 
718
                mm_log ("Sequence range invalid",ERROR);
 
719
                return NIL;
 
720
            }
 
721
 
 
722
            if (*sequence && *sequence++ != ',') {
 
723
                mm_log ("Sequence range syntax error",ERROR);
 
724
                return NIL;
 
725
            }
 
726
 
 
727
            if (i > j) {                /* swap the range if backwards */
 
728
                x = i; i = j; j = x;
 
729
            }
 
730
 
 
731
            while (i <= j)
 
732
              if(!(*func)(stream, i++, args))
 
733
                return(0L);
 
734
 
 
735
            break;
 
736
          case ',':                     /* single message */
 
737
            ++sequence;         /* skip the delimiter, fall into end case */
 
738
          case '\0':            /* end of sequence */
 
739
            if(!(*func)(stream, i, args))
 
740
              return(0L);
 
741
 
 
742
            break;
 
743
          default:                      /* anything else is a syntax error! */
 
744
            mm_log ("Sequence syntax error",ERROR);
 
745
            return NIL;
 
746
        }
 
747
    }
 
748
 
 
749
    return T;                   /* successfully parsed sequence */
 
750
}
 
751
 
 
752
 
 
753
long
 
754
imap_seq_exec_append(MAILSTREAM *stream, long int msgno, void *args)
 
755
{
 
756
    char         *save_folder, flags[64], date[64];
 
757
    CONTEXT_S    *cntxt = NULL;
 
758
    int           our_stream = 0;
 
759
    long          rv = 0L;
 
760
    MAILSTREAM   *save_stream;
 
761
    SE_APP_S     *sa = (SE_APP_S *) args;
 
762
    MESSAGECACHE *mc;
 
763
    STORE_S      *so;
 
764
 
 
765
    save_folder = (strucmp(sa->folder, ps_global->inbox_name) == 0)
 
766
                    ? ps_global->VAR_INBOX_PATH : sa->folder;
 
767
 
 
768
    save_stream = save_msg_stream(cntxt, save_folder, &our_stream);
 
769
 
 
770
    if(so = so_get(CharStar, NULL, WRITE_ACCESS)){
 
771
        /* store flags before the fetch so UNSEEN bit isn't flipped */
 
772
        mc = (msgno > 0L && stream && msgno <= stream->nmsgs)
 
773
                ? mail_elt(stream, msgno) : NULL;
 
774
 
 
775
        flag_string(mc, F_ANS|F_FLAG|F_SEEN, flags, sizeof(flags));
 
776
        if(mc && mc->day)
 
777
          mail_date(date, mc);
 
778
        else
 
779
          *date = '\0';
 
780
 
 
781
        rv = save_fetch_append(stream, msgno, NULL,
 
782
                               save_stream, save_folder, NULL,
 
783
                               mc ? mc->rfc822_size : 0L, flags, date, so);
 
784
        if(rv < 0 || sp_expunge_count(stream)){
 
785
            cmd_cancelled("Attached message Save");
 
786
            rv = 0L;
 
787
        }
 
788
        /* else whatever broke in save_fetch_append shoulda bitched */
 
789
 
 
790
        so_give(&so);
 
791
    }
 
792
    else{
 
793
        dprint((1, "Can't allocate store for save: %s\n",
 
794
                   error_description(errno)));
 
795
        q_status_message(SM_ORDER | SM_DING, 3, 4,
 
796
                         "Problem creating space for message text.");
 
797
    }
 
798
 
 
799
    if(our_stream)
 
800
      mail_close(save_stream);
 
801
 
 
802
    return(rv);
 
803
}
 
804
 
 
805
 
 
806
 
 
807
/*----------------------------------------------------------------------
 
808
      Get login and password from user for IMAP login
 
809
  
 
810
  Args:  mb -- The mail box property struct
 
811
         user   -- Buffer to return the user name in 
 
812
         passwd -- Buffer to return the passwd in
 
813
         trial  -- The trial number or number of attempts to login
 
814
    user is at least size NETMAXUSER
 
815
    passwd is apparently at least MAILTMPLEN, but mrc has asked us to
 
816
      use a max size of about 100 instead
 
817
 
 
818
 Result: username and password passed back to imap
 
819
  ----*/
 
820
void
 
821
mm_login(NETMBX *mb, char *user, char *pwd, long int trial)
 
822
{
 
823
    mm_login_work(mb, user, pwd, trial, NULL, NULL);
 
824
}
 
825
 
 
826
 
 
827
/*----------------------------------------------------------------------
 
828
   Exported method to retrieve logged in user name associated with stream
 
829
 
 
830
   Args: host -- host to find associated login name with.
 
831
 
 
832
 Result: 
 
833
  ----*/
 
834
char *
 
835
cached_user_name(char *host)
 
836
{
 
837
    MMLOGIN_S *l;
 
838
    STRLIST_S *h;
 
839
 
 
840
    if((l = mm_login_list) && host)
 
841
      do
 
842
        for(h = l->hosts; h; h = h->next)
 
843
          if(!strucmp(host, h->name))
 
844
            return(l->user);
 
845
      while(l = l->next);
 
846
 
 
847
    return(NULL);
 
848
}
 
849
 
 
850
 
 
851
int
 
852
imap_same_host(STRLIST_S *hl1, STRLIST_S *hl2)
 
853
{
 
854
    STRLIST_S *lp;
 
855
 
 
856
    for( ; hl1; hl1 = hl1->next)
 
857
      for(lp = hl2; lp; lp = lp->next)
 
858
      if(!strucmp(hl1->name, lp->name))
 
859
        return(TRUE);
 
860
 
 
861
    return(FALSE);
 
862
}
 
863
 
 
864
 
 
865
/*
 
866
 * For convenience, we use the same m_list structure (but a different
 
867
 * instance) for storing a list of hosts we've asked the user about when
 
868
 * SSL validation fails. If this function returns TRUE, that means we
 
869
 * have previously asked the user about this host. Ok_novalidate == 1 means
 
870
 * the user said yes, it was ok. Ok_novalidate == 0 means the user
 
871
 * said no. Warned means we warned them already.
 
872
 */
 
873
int
 
874
imap_get_ssl(MMLOGIN_S *m_list, STRLIST_S *hostlist, int *ok_novalidate, int *warned)
 
875
{
 
876
    MMLOGIN_S *l;
 
877
    
 
878
    for(l = m_list; l; l = l->next)
 
879
      if(imap_same_host(l->hosts, hostlist)){
 
880
          if(ok_novalidate)
 
881
            *ok_novalidate = l->ok_novalidate;
 
882
 
 
883
          if(warned)
 
884
            *warned = l->warned;
 
885
 
 
886
          return(TRUE);
 
887
      }
 
888
 
 
889
    return(FALSE);
 
890
}
 
891
 
 
892
 
 
893
/*
 
894
 * Just trying to guess the username the user might want to use on this
 
895
 * host, the user will confirm.
 
896
 */
 
897
char *
 
898
imap_get_user(MMLOGIN_S *m_list, STRLIST_S *hostlist)
 
899
{
 
900
    MMLOGIN_S *l;
 
901
    
 
902
    for(l = m_list; l; l = l->next)
 
903
      if(imap_same_host(l->hosts, hostlist))
 
904
        return(l->user);
 
905
 
 
906
    return(NULL);
 
907
}
 
908
 
 
909
 
 
910
/*
 
911
 * If we have a matching hostname, username, and altflag in our cache,
 
912
 * attempt to login with the password from the cache.
 
913
 */
 
914
int
 
915
imap_get_passwd(MMLOGIN_S *m_list, char *passwd, char *user, STRLIST_S *hostlist, int altflag)
 
916
{
 
917
    MMLOGIN_S *l;
 
918
    
 
919
    dprint((9,
 
920
               "imap_get_passwd: checking user=%s alt=%d host=%s%s%s\n",
 
921
               user ? user : "(null)",
 
922
               altflag,
 
923
               hostlist->name ? hostlist->name : "",
 
924
               (hostlist->next && hostlist->next->name) ? ", " : "",
 
925
               (hostlist->next && hostlist->next->name) ? hostlist->next->name
 
926
                                                        : ""));
 
927
    for(l = m_list; l; l = l->next)
 
928
      if(imap_same_host(l->hosts, hostlist)
 
929
         && *user
 
930
         && !strcmp(user, l->user)
 
931
         && l->altflag == altflag){
 
932
          if(passwd){
 
933
              strncpy(passwd, l->passwd, NETMAXPASSWD);
 
934
              passwd[NETMAXPASSWD-1] = '\0';
 
935
          }
 
936
          dprint((9, "imap_get_passwd: match\n"));
 
937
          dprint((10, "imap_get_passwd: trying passwd=\"%s\"\n",
 
938
                      passwd ? passwd : "?"));
 
939
          return(TRUE);
 
940
      }
 
941
 
 
942
    dprint((9, "imap_get_passwd: no match\n"));
 
943
    return(FALSE);
 
944
}
 
945
 
 
946
 
 
947
 
 
948
void
 
949
imap_set_passwd(MMLOGIN_S **l, char *passwd, char *user, STRLIST_S *hostlist,
 
950
                int altflag, int ok_novalidate, int warned)
 
951
{
 
952
    STRLIST_S **listp;
 
953
    size_t      len;
 
954
 
 
955
    dprint((9, "imap_set_passwd\n"));
 
956
    for(; *l; l = &(*l)->next)
 
957
      if(imap_same_host((*l)->hosts, hostlist)
 
958
         && !strcmp(user, (*l)->user)
 
959
         && altflag == (*l)->altflag)
 
960
        if(strcmp(passwd, (*l)->passwd) ||
 
961
           (*l)->ok_novalidate != ok_novalidate ||
 
962
           (*l)->warned != warned)
 
963
          break;
 
964
        else
 
965
          return;
 
966
 
 
967
    if(!*l){
 
968
        *l = (MMLOGIN_S *)fs_get(sizeof(MMLOGIN_S));
 
969
        memset(*l, 0, sizeof(MMLOGIN_S));
 
970
    }
 
971
 
 
972
    len = strlen(passwd);
 
973
    if(!(*l)->passwd || strlen((*l)->passwd) < len)
 
974
      (*l)->passwd = ps_get(len+1);
 
975
 
 
976
    strncpy((*l)->passwd, passwd, len+1);
 
977
 
 
978
    (*l)->altflag = altflag;
 
979
    (*l)->ok_novalidate = ok_novalidate;
 
980
    (*l)->warned = warned;
 
981
 
 
982
    if(!(*l)->user)
 
983
      (*l)->user = cpystr(user);
 
984
 
 
985
    dprint((9, "imap_set_passwd: user=%s altflag=%d\n",
 
986
           (*l)->user ? (*l)->user : "?",
 
987
           (*l)->altflag));
 
988
 
 
989
    for( ; hostlist; hostlist = hostlist->next){
 
990
        for(listp = &(*l)->hosts;
 
991
            *listp && strucmp((*listp)->name, hostlist->name);
 
992
            listp = &(*listp)->next)
 
993
          ;
 
994
 
 
995
        if(!*listp){
 
996
            *listp = (STRLIST_S *)fs_get(sizeof(STRLIST_S));
 
997
            (*listp)->name = cpystr(hostlist->name);
 
998
            dprint((9, "imap_set_passwd: host=%s\n",
 
999
                       (*listp)->name ? (*listp)->name : "?"));
 
1000
            (*listp)->next = NULL;
 
1001
        }
 
1002
    }
 
1003
 
 
1004
    dprint((10, "imap_set_passwd: passwd=\"%s\"\n",
 
1005
           passwd ? passwd : "?"));
 
1006
}
 
1007
 
 
1008
 
 
1009
 
 
1010
void
 
1011
imap_flush_passwd_cache(int dumpcache)
 
1012
{
 
1013
    memset((void *)private_store, 0, sizeof(private_store));
 
1014
 
 
1015
    if(dumpcache){
 
1016
        MMLOGIN_S *l;
 
1017
 
 
1018
        while(l = mm_login_list){
 
1019
            mm_login_list = mm_login_list->next;
 
1020
            if(l->user)
 
1021
              fs_give((void **) &l->user);
 
1022
 
 
1023
            free_strlist(&l->hosts);
 
1024
 
 
1025
            fs_give((void **) &l);
 
1026
        }
 
1027
 
 
1028
        while(l = cert_failure_list){
 
1029
            cert_failure_list = cert_failure_list->next;
 
1030
            if(l->user)
 
1031
              fs_give((void **) &l->user);
 
1032
 
 
1033
            free_strlist(&l->hosts);
 
1034
 
 
1035
            fs_give((void **) &l);
 
1036
        }
 
1037
    }
 
1038
}
 
1039
 
 
1040
 
 
1041
/*
 
1042
 * Mimics fs_get except it only works for char * (no alignment hacks), it
 
1043
 * stores in a static array so it is easy to zero it out (that's the whole
 
1044
 * purpose), allocations always happen at the end (no free).
 
1045
 * If we go past array limit, we don't break, we just use free storage.
 
1046
 * Should be awfully rare, though.
 
1047
 */
 
1048
char *
 
1049
ps_get(size_t size)
 
1050
{
 
1051
    static char *last  = private_store;
 
1052
    char        *block = NULL;
 
1053
 
 
1054
    /* there is enough space */
 
1055
    if(size <= sizeof(private_store) - (last - private_store)){
 
1056
        block = last;
 
1057
        last += size;
 
1058
    }
 
1059
    else{
 
1060
        dprint((2,
 
1061
                   "Out of password caching space in private_store\n"));
 
1062
        dprint((2,
 
1063
                   "Using free storage instead\n"));
 
1064
        block = fs_get(size);
 
1065
    }
 
1066
 
 
1067
    return(block);
 
1068
}