~ubuntu-branches/ubuntu/karmic/alpine/karmic

« back to all changes in this revision

Viewing changes to web/src/alpined.d/alpined.c

  • Committer: Bazaar Package Importer
  • Author(s): Asheesh Laroia
  • Date: 2008-09-23 12:17:56 UTC
  • mfrom: (2.1.8 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080923121756-6u4x8bwq89qlzt32
Tags: 2.00+dfsg-2
Update to package description: note that Alpine is no longer in
alpha. (Closes: #499640)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#if !defined(lint) && !defined(DOS)
2
 
static char rcsid[] = "$Id: alpined.c 963 2008-03-14 21:51:18Z mikes@u.washington.edu $";
 
2
static char rcsid[] = "$Id: alpined.c 1166 2008-08-22 20:41:37Z mikes@u.washington.edu $";
3
3
#endif
4
4
 
5
5
/* ========================================================================
6
 
 * Copyright 2006-2007 University of Washington
 
6
 * Copyright 2006-2008 University of Washington
7
7
 *
8
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
9
 * you may not use this file except in compliance with the License.
79
79
#include "../../../pith/mimetype.h"
80
80
#include "../../../pith/mailcap.h"
81
81
#include "../../../pith/sequence.h"
 
82
#include "../../../pith/smime.h"
 
83
#include "../../../pith/url.h"
82
84
#include "../../../pith/charconv/utf8.h"
83
85
 
84
86
#include "alpined.h"
124
126
 
125
127
 
126
128
/*
127
 
 *
 
129
 * AUTH Response Tokens 
128
130
 */
129
131
#define AUTH_EMPTY_STRING       "NOPASSWD"
130
132
#define AUTH_FAILURE_STRING     "BADPASSWD"
131
133
 
 
134
/*
 
135
 * CERT Response Tokens 
 
136
 */
 
137
#define CERT_QUERY_STRING       "CERTQUERY"
 
138
#define CERT_FAILURE_STRING     "CERTFAIL"
 
139
 
132
140
 
133
141
/*
134
142
 * Globals referenced throughout pine...
144
152
long       peInputTimeout = PE_INPUT_TIMEOUT;
145
153
long       peAbandonTimeout = 0;
146
154
 
 
155
/*
 
156
 * Authorization issues 
 
157
 */
147
158
int        peNoPassword, peCredentialError;
148
 
char       peCredentialRequestor[WP_MAXAUTHREQ];
 
159
int        peCertFailure, peCertQuery;
 
160
char       peCredentialRequestor[CRED_REQ_SIZE];
149
161
 
150
162
char      *peSocketName;
151
163
 
153
165
 
154
166
CONTEXT_S *config_context_list;
155
167
 
 
168
STRLIST_S *peCertHosts;
 
169
 
156
170
bitmap_t changed_feature_list;
157
171
#define F_CH_ON(feature)        (bitnset((feature),changed_feature_list))
158
172
#define F_CH_OFF(feature)       (!F_CH_ON(feature))
211
225
        char      *fcc;
212
226
        int        fcc_colid;
213
227
        int        postop_fcc_no_attach;
214
 
        int        flowed;
215
 
        int        rich;
216
228
        char      *charset;
 
229
        char      *priority;
217
230
        int      (*postfunc)(METAENV *, BODY *, char *, CONTEXT_S **, char *);
 
231
        unsigned   flowed:1;
 
232
        unsigned   html:1;
 
233
        unsigned   qualified_addrs:1;
218
234
} MSG_COL_S;
219
235
 
220
236
 
240
256
} peED;
241
257
 
242
258
 
 
259
/*
 
260
 * RSS stream cache
 
261
 */
 
262
typedef struct _rss_cache_s {
 
263
        char       *link;
 
264
        time_t      stale;
 
265
        int         referenced;
 
266
        RSS_FEED_S *feed;
 
267
} RSS_CACHE_S;
 
268
 
 
269
#define RSS_NEWS_CACHE_SIZE     1
 
270
#define RSS_WEATHER_CACHE_SIZE  1
 
271
 
 
272
 
243
273
#ifdef ENABLE_LDAP
244
274
WPLDAP_S *wpldap_global;
245
275
#endif
253
283
#define PRS_MIXED_CASE  0x0004
254
284
 
255
285
/*
 
286
 * peSaveWork flag definitions
 
287
 */
 
288
#define PSW_NONE        0x00
 
289
#define PSW_COPY        0x01
 
290
#define PSW_MOVE        0x02
 
291
 
 
292
/*
 
293
 * Message Collector flags
 
294
 */
 
295
#define PMC_NONE        0x00
 
296
#define PMC_FORCE_QUAL  0x01
 
297
 
 
298
/*
256
299
 * length of thread info string
257
300
 */
258
301
#define WP_MAX_THRD_S   64
289
332
char        *peLoadConfig(struct pine *);
290
333
int          peCreateStream(Tcl_Interp *, CONTEXT_S *, char *, int);
291
334
void         peDestroyStream(struct pine *);
292
 
int          peSelect(Tcl_Interp *, int, Tcl_Obj **);
 
335
void         pePrepareForAuthException(void);
 
336
char        *peAuthException(void);
 
337
int          peSelect(Tcl_Interp *, int, Tcl_Obj **, int);
 
338
int          peSelectNumber(Tcl_Interp *, int, Tcl_Obj **, int);
 
339
int          peSelectDate(Tcl_Interp *, int, Tcl_Obj **, int);
 
340
int          peSelectText(Tcl_Interp *, int, Tcl_Obj **, int);
 
341
int          peSelectStatus(Tcl_Interp *, int, Tcl_Obj **, int);
293
342
char        *peSelValTense(Tcl_Obj *);
294
343
char        *peSelValYear(Tcl_Obj *);
295
344
char        *peSelValMonth(Tcl_Obj *);
297
346
int          peSelValCase(Tcl_Obj *);
298
347
int          peSelValField(Tcl_Obj *);
299
348
int          peSelValFlag(Tcl_Obj *);
 
349
int          peSelected(Tcl_Interp *, int, Tcl_Obj **, int);
300
350
int          peSelectError(Tcl_Interp *, char *);
301
351
int          peApply(Tcl_Interp *, int, Tcl_Obj **);
 
352
char        *peApplyFlag(MAILSTREAM *, MSGNO_S *, char, int, long *);
302
353
int          peApplyError(Tcl_Interp *, char *);
303
354
int          peIndexFormat(Tcl_Interp *);
304
355
int          peAppendIndexParts(Tcl_Interp *, imapuid_t, Tcl_Obj *, int *);
317
368
int          peMessageStatus(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
318
369
int          peMessageCharset(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
319
370
int          peMessageBounce(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
320
 
int          peMessageSpam(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
321
 
int          peMessageTrash(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
 
371
int          peMessageSpamNotice(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
 
372
char        *peSendSpamReport(long, char *, char *, char *);
322
373
int          peMsgnoFromUID(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
323
374
int          peMessageText(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
324
375
int          peMessageHeader(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
340
391
int          peMsgSelect(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
341
392
int          peReplyHeaders(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
342
393
int          peAppListF(Tcl_Interp *, Tcl_Obj *, char *, ...);
343
 
Tcl_Obj     *peNewUtf8Obj(void *, int);
344
394
void         pePatAppendID(Tcl_Interp *, Tcl_Obj *, PAT_S *);
345
395
void         pePatAppendPattern(Tcl_Interp *, Tcl_Obj *, PAT_S *);
346
396
char        *pePatStatStr(int);
351
401
int          peDetach(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
352
402
int          peAttachInfo(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
353
403
int          peSaveDefault(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
 
404
int          peSaveWork(Tcl_Interp *, imapuid_t, int, Tcl_Obj **, long);
354
405
int          peSave(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
 
406
int          peCopy(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
 
407
int          peMove(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
355
408
int          peGotoDefault(Tcl_Interp *, imapuid_t, Tcl_Obj **);
356
409
int          peTakeaddr(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
 
410
int          peTakeFrom(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
 
411
int          peAddSuggestedContactInfo(Tcl_Interp *, Tcl_Obj *, ADDRESS *);
357
412
int          peReplyQuote(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
358
413
long         peMessageNumber(imapuid_t);
359
414
long         peSequenceNumber(imapuid_t);
360
415
int          peMsgCollector(Tcl_Interp *, int, Tcl_Obj **,
361
 
                            int (*)(METAENV *, BODY *, char *, CONTEXT_S **, char *));
 
416
                            int (*)(METAENV *, BODY *, char *, CONTEXT_S **, char *), long);
362
417
int          peMsgCollected(Tcl_Interp  *, MSG_COL_S *, char *);
363
418
void         peMsgSetParm(PARAMETER **, char *, char *);
364
419
Tcl_Obj     *peMsgAttachCollector(Tcl_Interp *, BODY *);
406
461
void         ms_setpos(STRING *, unsigned long);
407
462
long         peAppendMsg(MAILSTREAM *, void *, char **, char **, STRING **);
408
463
int          remote_pinerc_failure(void);
 
464
char        *peWebAlpinePrefix(void);
 
465
int          peMessageNeedPassphrase(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
 
466
int          peRssReturnFeed(Tcl_Interp *, char *, char *);
 
467
int          peRssPackageFeed(Tcl_Interp *, RSS_FEED_S *);
 
468
RSS_FEED_S  *peRssFeed(Tcl_Interp *, char *, char *);
 
469
RSS_FEED_S  *peRssFetch(Tcl_Interp *, char *);
 
470
void         peRssComponentFree(char **,char **,char **,char **,char **,char **);
 
471
void         peRssClearCacheEntry(RSS_CACHE_S *);
409
472
 
410
473
 
411
474
/* Prototypes for Tcl-exported methods */
437
500
                   int objc, Tcl_Obj *CONST objv[]);
438
501
int     PELdapCmd(ClientData clientData, Tcl_Interp *interp,
439
502
                  int objc, Tcl_Obj *CONST objv[]);
 
503
int     PERssCmd(ClientData clientData, Tcl_Interp *interp,
 
504
                 int objc, Tcl_Obj *CONST objv[]);
440
505
 
441
506
/* Append package */
442
507
typedef struct append_pkg {
532
597
           Initialize pith library
533
598
      ----------------------------------------------------------------------*/
534
599
    pith_opt_remote_pinerc_failure = remote_pinerc_failure;
 
600
    pith_opt_user_agent_prefix = peWebAlpinePrefix;
 
601
 
535
602
    setup_for_index_index_screen();
536
603
 
537
604
 
576
643
                     * which introduces a timing race between the first client
577
644
                     * request arrival and our being prepared to accept it.
578
645
                     */
579
 
                    if(debug < 2){
 
646
                    if(debug < 10){
580
647
                        switch(fork()){
581
648
                          case -1 :             /* error */
582
649
                            perror("fork");
807
874
    Tcl_CreateObjCommand(interp, "PELdap", PELdapCmd,
808
875
                        (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
809
876
 
 
877
    Tcl_CreateObjCommand(interp, "PERss", PERssCmd,
 
878
                        (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
 
879
 
810
880
    Tcl_CreateExitHandler(PEExitCleanup, sname);
811
881
 
812
882
#ifdef ENABLE_LDAP
1159
1229
            else if(objc == 2){
1160
1230
                if(!strcmp(s1, "version")){
1161
1231
                    char buf[256];
1162
 
                    extern char compstamp[];
1163
1232
 
1164
1233
                    /*
1165
1234
                     * CMD: version
1167
1236
                     * Returns: string representing Pine version
1168
1237
                     * engine built on
1169
1238
                     */
1170
 
                    snprintf(buf, sizeof(buf), "%s.%s", ALPINE_VERSION, compstamp);
1171
 
                    Tcl_SetResult(interp, buf, TCL_VOLATILE);
 
1239
                    Tcl_SetResult(interp, ALPINE_VERSION, TCL_STATIC);
 
1240
                    return(TCL_OK);
 
1241
                }
 
1242
                else if(!strcmp(s1, "revision")){
 
1243
                    char buf[16];
 
1244
 
 
1245
                    /*
 
1246
                     * CMD: revision
 
1247
                     *
 
1248
                     * Returns: string representing Pine SVN revision
 
1249
                     * engine built on
 
1250
                     */
 
1251
                    
 
1252
                    Tcl_SetResult(interp, get_alpine_revision_number(buf, sizeof(buf)), TCL_VOLATILE);
1172
1253
                    return(TCL_OK);
1173
1254
                }
1174
1255
                else if(!strcmp(s1, "key")){
1383
1464
                    else if(!IS_REMOTE(ps_global->VAR_SIGNATURE_FILE))
1384
1465
                      snprintf(err = tmp_20k_buf, SIZEOF_20KBUF, "Non-Remote signature file: %s",
1385
1466
                              ps_global->VAR_SIGNATURE_FILE ? ps_global->VAR_SIGNATURE_FILE : "<null>");
1386
 
                    else if(!(sig = read_remote_sigfile(ps_global->VAR_SIGNATURE_FILE)))
 
1467
                    else if(!(sig = simple_read_remote_file(ps_global->VAR_SIGNATURE_FILE, REMOTE_SIG_SUBTYPE)))
1387
1468
                      err = "Can't read remote pinerc";
1388
1469
 
1389
1470
                    if(err){
2491
2572
                                                  ? vtmp->changed_val.p : "<null>")
2492
2573
                          : (ps_global->VAR_SIGNATURE_FILE
2493
2574
                             ? ps_global->VAR_SIGNATURE_FILE : "<null>"));
2494
 
                else if(!(peTSig || (sig = read_remote_sigfile(vtmp->is_changed_val
 
2575
                else if(!(peTSig || (sig = simple_read_remote_file(vtmp->is_changed_val
2495
2576
                                                    ? vtmp->changed_val.p
2496
 
                                                    : ps_global->VAR_SIGNATURE_FILE))))
 
2577
                                                    : ps_global->VAR_SIGNATURE_FILE, REMOTE_SIG_SUBTYPE))))
2497
2578
                  err = "Can't read remote pinerc";
2498
2579
 
2499
2580
                if(err){
3302
3383
 
3303
3384
                return(TCL_OK);
3304
3385
            }
 
3386
            else if(!strcmp(s1, "reset")){
 
3387
                char *p;
 
3388
 
 
3389
                if((p = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
 
3390
                    if(!strcmp(p,"pinerc")){
 
3391
                        struct variable *var;
 
3392
                        PINERC_S        *prc;
 
3393
 
 
3394
                        /* new pinerc structure, copy location pointers */
 
3395
                        prc = new_pinerc_s(ps_global->prc->name);
 
3396
                        prc->type = ps_global->prc->type;
 
3397
                        prc->rd = ps_global->prc->rd;
 
3398
                        prc->outstanding_pinerc_changes = 1;
 
3399
 
 
3400
                        /* tie off original pinerc struct and free it */
 
3401
                        ps_global->prc->rd = NULL;
 
3402
                        ps_global->prc->outstanding_pinerc_changes = 0;
 
3403
                        free_pinerc_s(&ps_global->prc);
 
3404
 
 
3405
                        /* set global->prc to new struct with no pinerc_lines
 
3406
                         * and fool write_pinerc into not writing changed vars
 
3407
                         */
 
3408
                        ps_global->prc = prc;
 
3409
 
 
3410
                        /*
 
3411
                         * write at least one var into nearly empty pinerc
 
3412
                         * and clear user's var settings. clear global cause
 
3413
                         * they'll get reset in init_vars
 
3414
                         */
 
3415
                        for(var = ps_global->vars; var->name != NULL; var++){
 
3416
                            var->been_written = ((var - ps_global->vars) != V_LAST_VERS_USED);
 
3417
                            if(var->is_list){
 
3418
                                free_list_array(&var->main_user_val.l);
 
3419
                                free_list_array(&var->global_val.l);
 
3420
                            }
 
3421
                            else{
 
3422
                                fs_give((void **)&var->main_user_val.p);
 
3423
                                fs_give((void **)&var->global_val.p);
 
3424
                            }
 
3425
                        }
 
3426
 
 
3427
                        write_pinerc(ps_global, Main, WRP_NOUSER | WRP_PRESERV_WRITTEN);
 
3428
 
 
3429
                        init_vars(ps_global, NULL);
 
3430
                        return(TCL_OK);
 
3431
                    }
 
3432
                }
 
3433
            }
3305
3434
        }
3306
3435
        else if(objc == 4){
3307
3436
            if(!strcmp(s1, "varset")){
4171
4300
            else
4172
4301
              err = "creds: failure to acquire folder and collection ID";
4173
4302
        }
 
4303
        else if(!strcmp(op, "acceptcert")){
 
4304
            char       *certhost;
 
4305
            STRLIST_S **p;
 
4306
 
 
4307
            if((certhost = Tcl_GetStringFromObj(objv[2], NULL))){
 
4308
                for(p = &peCertHosts; *p; p = &(*p)->next)
 
4309
                  ;
 
4310
 
 
4311
                *p = new_strlist(certhost);
 
4312
            }
 
4313
 
 
4314
            err = "PESession: no server name";
 
4315
        }
4174
4316
        else if(!strcmp(op, "random")){
4175
4317
            if(objc != 3){
4176
4318
                err = "PESession: random <length>";
4272
4414
                  err = "Can't read on/off state";
4273
4415
            }
4274
4416
        }
 
4417
        else if(!strcmp(op, "setpassphrase")){
 
4418
#ifdef SMIME
 
4419
            char *passphrase;
 
4420
 
 
4421
            if(objc != 3){
 
4422
                err = "PESession: setpassphrase <state>";
 
4423
            }
 
4424
            else if((passphrase = Tcl_GetStringFromObj(objv[2], NULL))){
 
4425
              if(ps_global && ps_global->smime){
 
4426
                strncpy((char *) ps_global->smime->passphrase, passphrase,
 
4427
                        sizeof(ps_global->smime->passphrase));
 
4428
                ps_global->smime->passphrase[sizeof(ps_global->smime->passphrase)-1] = '\0';
 
4429
                ps_global->smime->entered_passphrase = 1;
 
4430
                ps_global->smime->need_passphrase = 0;
 
4431
                peED.uid = 0;
 
4432
                return(TCL_OK);
 
4433
              }
 
4434
            }
 
4435
#else
 
4436
            err = "S/MIME not configured for this server";
 
4437
#endif /* SMIME */
 
4438
        }
4275
4439
    }
4276
4440
 
4277
4441
    Tcl_SetResult(interp, err, TCL_STATIC);
4281
4445
 
4282
4446
 
4283
4447
/*
4284
 
 * PEFolderChange:
4285
 
 *    call reset_context_folders(cp) to clean up data structures this creates
4286
 
 * PEMakeFolderString:
 
4448
 * PEFolderChange - create context's directory chain
 
4449
 *                  corresponding to list of given obj's
 
4450
 *
 
4451
 *    NOTE: caller should call reset_context_folders(cp) to
 
4452
 *          clean up data structures this creates before returning
4287
4453
 */
4288
4454
int
4289
4455
PEFolderChange(Tcl_Interp *interp, CONTEXT_S *cp, int objc, Tcl_Obj *CONST objv[])
4300
4466
      return(TCL_ERROR);
4301
4467
    }
4302
4468
 
4303
 
    fp = next_folder_dir(cp, folder, FALSE, NULL); /* BUG: mail_stream? */
 
4469
    fp = next_folder_dir(cp, folder, 0, NULL); /* BUG: mail_stream? */
4304
4470
    fp->desc    = folder_lister_desc(cp, fp);
4305
4471
    fp->delim   = cp->dir->delim;
4306
4472
    fp->prev    = cp->dir;
4311
4477
  return(TCL_OK);
4312
4478
}
4313
4479
 
4314
 
 
 
4480
/*
 
4481
 * PEMakeFolderString:
 
4482
 */
4315
4483
int
4316
4484
PEMakeFolderString(Tcl_Interp *interp, CONTEXT_S *cp, int objc, Tcl_Obj *CONST objv[], char **ppath)
4317
4485
{
4404
4572
 
4405
4573
                    return(TCL_OK);
4406
4574
                }
 
4575
                else if(!strcmp(op, "defaultcollection")){
 
4576
                    int        i;
 
4577
                    CONTEXT_S *cp;
 
4578
 
 
4579
                    for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next)
 
4580
                      if(cp->use & CNTXT_SAVEDFLT){
 
4581
                          Tcl_SetResult(interp, int2string(i), TCL_STATIC);
 
4582
                          return(TCL_OK);
 
4583
                      }
 
4584
 
 
4585
                    err = "PEFolder: isincoming: Invalid collection ID";
 
4586
                }
4407
4587
                else if(!strcmp(op, "clextended")){
4408
4588
                    CONTEXT_S *cp;
4409
4589
                    int        i;
4537
4717
 
4538
4718
                                    our_stream = 1;
4539
4719
                                    mstream = context_open(cp, NULL, folder,
4540
 
                                                           OP_READONLY | OP_SHORTCACHE,
 
4720
                                                           SP_USEPOOL | SP_TEMPUSE| OP_READONLY | OP_SHORTCACHE,
4541
4721
                                                           &retflags);
4542
4722
                                }
4543
4723
 
4557
4737
                else
4558
4738
                  err = "PEFolder: unread: Can't read collection ID";
4559
4739
            }
 
4740
            else if(objc == 5 && !strcmp(op, "empty")){
 
4741
                /*
 
4742
                 * CMD: empty
 
4743
                 *
 
4744
                 * Returns: number of expunge messages
 
4745
                 *
 
4746
                 * Arguments: <colnum> <folder> <what>
 
4747
                 *   where <what> is either <uid>, 'selected', or 'all'
 
4748
                 */
 
4749
                CONTEXT_S    *cp;
 
4750
                MAILSTREAM   *stream = NULL;
 
4751
                MESSAGECACHE *mc;
 
4752
                MSGNO_S      *msgmap;
 
4753
                int           colid, i, our_stream = 0;
 
4754
                long          uid, raw, count = 0L;
 
4755
                char         *errstr = NULL, *what, *folder, *p, tmp[MAILTMPLEN];
 
4756
 
 
4757
                if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){
 
4758
                    for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next)
 
4759
                      if(i == colid) break;
 
4760
                }
 
4761
 
 
4762
                if(cp){
 
4763
                    if((folder = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){
 
4764
                        if((what = Tcl_GetStringFromObj(objv[4], NULL)) != NULL){
 
4765
                            /* need to open? */
 
4766
                            if(!((context_allowed(context_apply(tmp, cp, folder, sizeof(tmp)))
 
4767
                                  && (stream = same_stream_and_mailbox(tmp, ps_global->mail_stream)))
 
4768
                                     || (stream = same_stream_and_mailbox(tmp, sp_inbox_stream())))){
 
4769
                                long retflags = 0;
 
4770
 
 
4771
                                our_stream = 1;
 
4772
                                stream = context_open(cp, NULL, folder, SP_USEPOOL | SP_TEMPUSE | OP_SHORTCACHE, &retflags);
 
4773
                            }
 
4774
 
 
4775
                            if(stream){
 
4776
                                msgmap = sp_msgmap(stream);
 
4777
 
 
4778
                                if(!strucmp(what, "all")){
 
4779
                                    if(mn_get_total(msgmap)){
 
4780
                                        agg_select_all(stream, msgmap, NULL, 1);
 
4781
                                        errstr = peApplyFlag(stream, msgmap, 'd', 0, &count);
 
4782
                                        if(!errstr)
 
4783
                                          (void) cmd_expunge_work(stream, msgmap);
 
4784
                                    }
 
4785
                                }
 
4786
                                else{
 
4787
                                    /* little complicated since we don't display deleted state and
 
4788
                                     * don't want to expunge what's not intended.
 
4789
                                     * remember what's deleted and restore state on the ones left
 
4790
                                     * when we're done. shouldn't happen much.
 
4791
                                     * NOTE: "uid" is NOT a UID in this loop
 
4792
                                     */
 
4793
                                    for(uid = 1L; uid <= mn_get_total(msgmap); uid++){
 
4794
                                        raw = mn_m2raw(msgmap, uid);
 
4795
                                        if(!get_lflag(stream, msgmap, uid, MN_EXLD)
 
4796
                                           && (mc = mail_elt(stream, raw)) != NULL
 
4797
                                           && mc->deleted){
 
4798
                                            set_lflag(stream, msgmap, uid, MN_STMP, 1);
 
4799
                                            mail_flag(stream, long2string(raw), "\\DELETED", 0L);
 
4800
                                        }
 
4801
                                        else
 
4802
                                          set_lflag(stream, msgmap, uid, MN_STMP, 0);
 
4803
                                    }
 
4804
 
 
4805
                                    if(!strucmp(what,"selected")){
 
4806
                                        if(any_lflagged(msgmap, MN_SLCT)){
 
4807
                                            if(!(errstr = peApplyFlag(stream, msgmap, 'd', 0, &count)))
 
4808
                                              (void) cmd_expunge_work(stream, msgmap);
 
4809
                                        }
 
4810
                                        else
 
4811
                                          count = 0L;
 
4812
                                    }
 
4813
                                    else{
 
4814
                                        uid = 0;
 
4815
                                        for(p = what; *p; p++)
 
4816
                                          if(isdigit((unsigned char) *p)){
 
4817
                                              uid = (uid * 10) + (*p - '0');
 
4818
                                          }
 
4819
                                          else{
 
4820
                                              errstr = "Invalid uid value";
 
4821
                                              break;
 
4822
                                          }
 
4823
 
 
4824
                                        if(!errstr && uid){
 
4825
                                            /* uid is a UID here */
 
4826
                                            mail_flag(stream, long2string(uid), "\\DELETED", ST_SET | ST_UID);
 
4827
                                            (void) cmd_expunge_work(stream, msgmap);
 
4828
                                            count = 1L;
 
4829
                                        }
 
4830
                                    }
 
4831
 
 
4832
                                    /* restore deleted on what didn't get expunged */
 
4833
                                    for(uid = 1L; uid <= mn_get_total(msgmap); uid++){
 
4834
                                        raw = mn_m2raw(msgmap, uid);
 
4835
                                        if(get_lflag(stream, msgmap, uid, MN_STMP)){
 
4836
                                            set_lflag(stream, msgmap, uid, MN_STMP, 0);
 
4837
                                            mail_flag(stream, long2string(raw), "\\DELETED", ST_SET);
 
4838
                                        }
 
4839
                                    }
 
4840
                                }
 
4841
 
 
4842
                                if(our_stream)
 
4843
                                  pine_mail_close(stream);
 
4844
                            }
 
4845
                            else
 
4846
                              errstr = "no stream";
 
4847
                        }
 
4848
                        else
 
4849
                          errstr = "Cannot get which ";
 
4850
                    }
 
4851
                    else
 
4852
                      errstr = "Cannot get folder";
 
4853
                }
 
4854
                else
 
4855
                  errstr = "Invalid collection";
 
4856
 
 
4857
                if(errstr){
 
4858
                    Tcl_SetResult(interp, errstr, TCL_VOLATILE);
 
4859
                    return(TCL_ERROR);
 
4860
                }
 
4861
 
 
4862
                Tcl_SetResult(interp, long2string(count), TCL_VOLATILE);
 
4863
                return(TCL_OK);
 
4864
            }
4560
4865
            else if(!strcmp(op, "export")){
4561
4866
                /*
4562
4867
                 * CMD: export
4610
4915
 
4611
4916
                                                our_stream = 1;
4612
4917
                                                src = context_open(cp, NULL, folder,
4613
 
                                                                   OP_READONLY | OP_SHORTCACHE,
 
4918
                                                                   SP_USEPOOL | SP_TEMPUSE | OP_READONLY | OP_SHORTCACHE,
4614
4919
                                                                   &retflags);
4615
4920
                                            }
4616
4921
 
4708
5013
                                            long retflags = 0;
4709
5014
 
4710
5015
                                            if(context_create(cp, NULL, folder)
4711
 
                                               && (dst = context_open(cp, NULL, folder, 0L, &retflags))){
 
5016
                                               && (dst = context_open(cp, NULL, folder, SP_USEPOOL | SP_TEMPUSE, &retflags))){
4712
5017
 
4713
5018
                                                if(src->nmsgs){
4714
5019
                                                    /* Go to work...*/
4770
5075
                  err = "PEFolder: import <file> <colid> <folder>";
4771
5076
            }
4772
5077
            else {
4773
 
              int i, colid;
4774
 
              char *colstr;
 
5078
              int        i, colid;
 
5079
              char      *aes, *colstr;
4775
5080
              CONTEXT_S *cp;
4776
5081
              
4777
5082
              /*
4795
5100
              if(cp){
4796
5101
                if(!strcmp(op, "list")){
4797
5102
                  int i, fcount, bflags = BFL_NONE;
4798
 
                  
4799
 
                  ps_global->c_client_error[0] = ps_global->last_error[0] = '\0';
 
5103
 
4800
5104
                  if(PEFolderChange(interp, cp, objc - 3, objv + 3) == TCL_ERROR)
4801
5105
                    return TCL_ERROR;
4802
 
                  
4803
 
                  peNoPassword = 0;
 
5106
 
4804
5107
                  if(cp->use & CNTXT_NEWS)
4805
5108
                    bflags |= BFL_LSUB;
4806
5109
 
 
5110
                  ps_global->c_client_error[0] = ps_global->last_error[0] = '\0';
 
5111
 
 
5112
                  pePrepareForAuthException();
 
5113
 
4807
5114
                  build_folder_list(NULL, cp, "*", NULL, bflags);
4808
5115
 
4809
 
                  if(peNoPassword){
4810
 
                    Tcl_SetResult(interp, AUTH_FAILURE_STRING, TCL_VOLATILE);
4811
 
                    reset_context_folders(cp);
4812
 
                    return(TCL_ERROR);
 
5116
                  if((aes = peAuthException()) != NULL){
 
5117
                      Tcl_SetResult(interp, aes, TCL_VOLATILE);
 
5118
                      reset_context_folders(cp);
 
5119
                      return(TCL_ERROR);
4813
5120
                  }
4814
 
                  
 
5121
 
4815
5122
                  if((fcount = folder_total(FOLDERS(cp))) != 0){
4816
5123
                    for(i = 0; i < fcount; i++){
4817
5124
                      char type[3], *p;
4858
5165
                    return TCL_ERROR;
4859
5166
 
4860
5167
                  ps_global->c_client_error[0] = '\0';
4861
 
                  peNoPassword = peCredentialError = 0;
 
5168
                  pePrepareForAuthException();
4862
5169
 
4863
5170
                  rv = folder_name_exists(cp, folder, NULL);
4864
5171
 
4865
5172
                  if(rv & FEX_ERROR){
4866
 
                      if(peNoPassword || peCredentialError)
4867
 
                        errstr = AUTH_FAILURE_STRING;
4868
 
                      else if(ps_global->c_client_error[0])
4869
 
                        errstr = ps_global->c_client_error;
4870
 
                      else
4871
 
                        errstr = "Indeterminate Error";
 
5173
                      if((errstr = peAuthException()) == NULL){
 
5174
                          if(ps_global->c_client_error[0])
 
5175
                            errstr = ps_global->c_client_error;
 
5176
                          else
 
5177
                            errstr = "Indeterminate Error";
 
5178
                      }
4872
5179
                  }
4873
5180
 
4874
5181
                  Tcl_SetResult(interp, errstr ? errstr : int2string((int)(rv & FEX_ISFILE)), TCL_VOLATILE);
4905
5212
                  return(TCL_OK);
4906
5213
                }
4907
5214
                else if(!strucmp(op, "create")){
4908
 
                  char *folder;
4909
 
                  
4910
 
                  folder = Tcl_GetStringFromObj(objv[objc - 1], NULL);
4911
 
                  if(!folder) {
4912
 
                    Tcl_SetResult(interp, "PEFolder create: Can't read folder", TCL_VOLATILE);
4913
 
                    return(TCL_ERROR);
4914
 
                  }
4915
 
                  
4916
 
                  if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR)
4917
 
                    return TCL_ERROR;
4918
 
                  
4919
 
                  ps_global->c_client_error[0] = ps_global->last_error[0] = '\0';
4920
 
                  peNoPassword = 0;
4921
 
                  
4922
 
                  if(!context_create(cp, NULL, folder)){
4923
 
                    if(peNoPassword){
4924
 
                      Tcl_SetResult(interp, AUTH_FAILURE_STRING, TCL_VOLATILE);
4925
 
                    }
4926
 
                    else{
4927
 
                      Tcl_SetResult(interp,
4928
 
                                    (ps_global->last_error[0])
4929
 
                                     ? ps_global->last_error
4930
 
                                     : (ps_global->c_client_error[0])
4931
 
                                        ? ps_global->c_client_error
4932
 
                                        : "Unable to create folder",
4933
 
                                    TCL_VOLATILE);
4934
 
                    }
 
5215
                    char *aes, *folder;
 
5216
 
 
5217
                    folder = Tcl_GetStringFromObj(objv[objc - 1], NULL);
 
5218
                    if(!folder) {
 
5219
                        Tcl_SetResult(interp, "PEFolder create: Can't read folder", TCL_VOLATILE);
 
5220
                        return(TCL_ERROR);
 
5221
                    }
 
5222
 
 
5223
                    if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR)
 
5224
                      return TCL_ERROR;
 
5225
 
 
5226
                    ps_global->c_client_error[0] = ps_global->last_error[0] = '\0';
 
5227
                    pePrepareForAuthException();
 
5228
 
 
5229
                    if(!context_create(cp, NULL, folder)){
 
5230
                        if((aes = peAuthException()) != NULL){
 
5231
                            Tcl_SetResult(interp, aes, TCL_VOLATILE);
 
5232
                        }
 
5233
                        else{
 
5234
                            Tcl_SetResult(interp,
 
5235
                                          (ps_global->last_error[0])
 
5236
                                            ? ps_global->last_error
 
5237
                                            : (ps_global->c_client_error[0])
 
5238
                                                ? ps_global->c_client_error
 
5239
                                                : "Unable to create folder",
 
5240
                                          TCL_VOLATILE);
 
5241
                        }
 
5242
 
 
5243
                        reset_context_folders(cp);
 
5244
                        return(TCL_ERROR);
 
5245
                    }
 
5246
 
 
5247
                    Tcl_SetResult(interp, "OK", TCL_STATIC);
4935
5248
                    reset_context_folders(cp);
4936
 
                    return(TCL_ERROR);
4937
 
                  }
4938
 
                  Tcl_SetResult(interp, "OK", TCL_STATIC);
4939
 
                  reset_context_folders(cp);
4940
 
                  return(TCL_OK);
 
5249
                    return(TCL_OK);
4941
5250
                }
4942
5251
                else if(!strucmp(op, "delete")){
4943
 
                  char       *folder;
4944
 
                  MAILSTREAM *strm = NULL;
4945
 
 
4946
 
                  folder = Tcl_GetStringFromObj(objv[objc - 1], NULL);
4947
 
                  if(!folder) {
4948
 
                    Tcl_SetResult(interp, "PEFolder delete: Can't read folder", TCL_VOLATILE);
4949
 
                    return(TCL_ERROR);
4950
 
                  }
4951
 
                  
4952
 
                  if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR)
4953
 
                    return TCL_ERROR;
4954
 
                  
4955
 
                  ps_global->c_client_error[0] = ps_global->last_error[0] = '\0';
4956
 
 
4957
 
                  peNoPassword = 0;
4958
 
 
4959
 
                  /* close open folder, then delete */
4960
 
                  if((strm = context_already_open_stream(cp,folder,AOS_NONE)) != NULL
4961
 
                     && strm == ps_global->mail_stream){
4962
 
                      do_broach_folder(ps_global->inbox_name,
4963
 
                                       ps_global->context_list, NULL, DB_INBOXWOCNTXT);
4964
 
                  }
4965
 
 
4966
 
                  if(!context_delete(cp, NULL, folder)){
4967
 
                    if(peNoPassword){
4968
 
                      Tcl_SetResult(interp, AUTH_FAILURE_STRING, TCL_VOLATILE);
4969
 
                    }
 
5252
                    int         fi, readonly, close_opened = 0;
 
5253
                    char       *folder, *fnamep, *target = NULL, *aes;
 
5254
                    MAILSTREAM *del_stream = NULL, *strm = NULL;
 
5255
                    EditWhich   ew;
 
5256
                    PINERC_S   *prc = NULL;
 
5257
                    FOLDER_S   *fp;
 
5258
 
 
5259
                    folder = Tcl_GetStringFromObj(objv[objc - 1], NULL);
 
5260
                    if(!folder) {
 
5261
                        Tcl_SetResult(interp, "PEFolder delete: Can't read folder", TCL_VOLATILE);
 
5262
                        return(TCL_ERROR);
 
5263
                    }
 
5264
                  
 
5265
                    if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR)
 
5266
                      return TCL_ERROR;
 
5267
 
 
5268
                    /* so we can check for folder's various properties */
 
5269
                    build_folder_list(NULL, cp, folder, NULL, BFL_NONE);
 
5270
 
 
5271
                    ps_global->c_client_error[0] = ps_global->last_error[0] = '\0';
 
5272
 
 
5273
                    pePrepareForAuthException();
 
5274
 
 
5275
                    /* close open folder, then delete */
 
5276
 
 
5277
                    if((fi = folder_index(folder, cp, FI_FOLDER)) < 0
 
5278
                       || (fp = folder_entry(fi, FOLDERS(cp))) == NULL){
 
5279
                        Tcl_SetResult(interp, "Cannot find folder to delete", TCL_STATIC);
 
5280
                        reset_context_folders(cp);
 
5281
                        return(TCL_ERROR);
 
5282
                    }
 
5283
 
 
5284
                    if(!((cp->use & CNTXT_INCMNG) && fp->name
 
5285
                         && check_for_move_mbox(fp->name, NULL, 0, &target))){
 
5286
                        target = NULL;
 
5287
                    }
 
5288
                    
 
5289
                    dprint((4, "=== delete_folder(%s) ===\n", folder ? folder : "?"));
 
5290
 
 
5291
                    ew = config_containing_inc_fldr(fp);
 
5292
                    if(ps_global->restricted)
 
5293
                      readonly = 1;
4970
5294
                    else{
4971
 
                      Tcl_SetResult(interp,
4972
 
                                    (ps_global->last_error[0])
4973
 
                                     ? ps_global->last_error
4974
 
                                     : (ps_global->c_client_error[0])
4975
 
                                        ? ps_global->c_client_error
4976
 
                                        : "Unable to delete folder",
4977
 
                                    TCL_VOLATILE);
4978
 
                    }
 
5295
                        switch(ew){
 
5296
                          case Main:
 
5297
                            prc = ps_global->prc;
 
5298
                            break;
 
5299
                          case Post:
 
5300
                            prc = ps_global->post_prc;
 
5301
                            break;
 
5302
                          case None:
 
5303
                            break;
 
5304
                        }
 
5305
 
 
5306
                        readonly = prc ? prc->readonly : 1;
 
5307
                    }
 
5308
 
 
5309
                    if(prc && prc->quit_to_edit && (cp->use & CNTXT_INCMNG)){
 
5310
                        Tcl_SetResult(interp, "Must Exit Alpine to Change Configuration", TCL_STATIC);
 
5311
                        reset_context_folders(cp);
 
5312
                        return(TCL_ERROR);
 
5313
                    }
 
5314
 
 
5315
                    if(cp == ps_global->context_list
 
5316
                       && !(cp->dir && cp->dir->ref)
 
5317
                       && strucmp(folder, ps_global->inbox_name) == 0){
 
5318
                        Tcl_SetResult(interp, "Cannot delete special folder", TCL_STATIC);
 
5319
                        reset_context_folders(cp);
 
5320
                        return(TCL_ERROR);
 
5321
                    }
 
5322
                    else if(readonly && (cp->use & CNTXT_INCMNG)){
 
5323
                        Tcl_SetResult(interp, "Folder not in editable config file", TCL_STATIC);
 
5324
                        reset_context_folders(cp);
 
5325
                        return(TCL_ERROR);
 
5326
                    }
 
5327
                    else if((fp->name
 
5328
                             && (strm=context_already_open_stream(cp,fp->name,AOS_NONE)))
 
5329
                            ||
 
5330
                            (target
 
5331
                             && (strm=context_already_open_stream(NULL,target,AOS_NONE)))){
 
5332
                        if(strm == ps_global->mail_stream)
 
5333
                          close_opened++;
 
5334
                    }
 
5335
                    else if(fp->isdir || fp->isdual){   /* NO DELETE if directory isn't EMPTY */
 
5336
                        FDIR_S *fdirp = next_folder_dir(cp,folder,TRUE,NULL);
 
5337
                        int     ret;
 
5338
 
 
5339
                        if(fp->haschildren)
 
5340
                          ret = 1;
 
5341
                        else if(fp->hasnochildren)
 
5342
                          ret = 0;
 
5343
                        else{
 
5344
                            ret = folder_total(fdirp->folders) > 0;
 
5345
                            free_fdir(&fdirp, 1);
 
5346
                        }
 
5347
 
 
5348
                        if(ret){
 
5349
                            Tcl_SetResult(interp, "Cannot delete non-empty directory", TCL_STATIC);
 
5350
                            reset_context_folders(cp);
 
5351
                            return(TCL_ERROR);
 
5352
                        }
 
5353
 
 
5354
                        /*
 
5355
                         * Folder by the same name exist, so delete both...
 
5356
                        if(fp->isdual){
 
5357
                            Tcl_SetResult(interp, "Cannot delete: folder is also a directory", TCL_STATIC);
 
5358
                            reset_context_folders(cp);
 
5359
                            return(TCL_ERROR);
 
5360
                        }
 
5361
                        */
 
5362
                    }
 
5363
 
 
5364
                    if(cp->use & CNTXT_INCMNG){
 
5365
                        Tcl_SetResult(interp, "Cannot delete incoming folder", TCL_STATIC);
 
5366
                        reset_context_folders(cp);
 
5367
                        return(TCL_ERROR);
 
5368
                    }
 
5369
 
 
5370
                    dprint((2,"deleting \"%s\" (%s) in context \"%s\"\n",
 
5371
                            fp->name ? fp->name : "?",
 
5372
                            fp->nickname ? fp->nickname : "",
 
5373
                            cp->context ? cp->context : "?"));
 
5374
                    if(strm){
 
5375
                        /*
 
5376
                         * Close it, NULL the pointer, and let do_broach_folder fixup
 
5377
                         * the rest...
 
5378
                         */
 
5379
                        pine_mail_actually_close(strm);
 
5380
                        if(close_opened){
 
5381
                            do_broach_folder(ps_global->inbox_name,
 
5382
                                             ps_global->context_list,
 
5383
                                             NULL, DB_INBOXWOCNTXT);
 
5384
                        }
 
5385
                    }
 
5386
 
 
5387
                    /*
 
5388
                     * Use fp->name since "folder" may be a nickname...
 
5389
                     */
 
5390
                    if(ps_global->mail_stream
 
5391
                       && context_same_stream(cp, fp->name, ps_global->mail_stream))
 
5392
                      del_stream = ps_global->mail_stream;
 
5393
                    
 
5394
                    fnamep = fp->name;
 
5395
 
 
5396
                    if(!context_delete(cp, del_stream, fnamep)){
 
5397
                        if((aes = peAuthException()) != NULL){
 
5398
                            Tcl_SetResult(interp, aes, TCL_VOLATILE);
 
5399
                        }
 
5400
                        else{
 
5401
                            Tcl_SetResult(interp,
 
5402
                                          (ps_global->last_error[0])
 
5403
                                            ? ps_global->last_error
 
5404
                                            : (ps_global->c_client_error[0])
 
5405
                                              ? ps_global->c_client_error
 
5406
                                              : "Unable to delete folder",
 
5407
                                          TCL_VOLATILE);
 
5408
                        }
 
5409
 
 
5410
                        reset_context_folders(cp);
 
5411
                        return(TCL_ERROR);
 
5412
                    }
 
5413
 
 
5414
 
 
5415
                    Tcl_SetResult(interp, "OK", TCL_STATIC);
4979
5416
                    reset_context_folders(cp);
4980
 
                    return(TCL_ERROR);
4981
 
                  }
4982
 
                  Tcl_SetResult(interp, "OK", TCL_STATIC);
4983
 
                  reset_context_folders(cp);
4984
 
                  return(TCL_OK);
 
5417
                    return(TCL_OK);
4985
5418
                }
4986
5419
                /*
4987
5420
                 * must be at least 5 arguments for the next set of commands
4991
5424
                  return(TCL_ERROR);
4992
5425
                }
4993
5426
                else if(!strucmp(op, "rename")){
4994
 
                  char *folder,*newfolder;
 
5427
                    char *folder,*newfolder, *aes;
4995
5428
                  
4996
5429
                  folder = Tcl_GetStringFromObj(objv[objc - 2], NULL);
4997
5430
                  if(!folder) {
5009
5442
                    return TCL_ERROR;
5010
5443
                  
5011
5444
                  ps_global->c_client_error[0] = ps_global->last_error[0] = '\0';
5012
 
                  peNoPassword = 0;
 
5445
                  pePrepareForAuthException();
5013
5446
                  
5014
5447
                  if(!context_rename(cp, NULL, folder, newfolder)){
5015
 
                    if(peNoPassword){
5016
 
                      Tcl_SetResult(interp, AUTH_FAILURE_STRING, TCL_VOLATILE);
 
5448
                      if((aes = peAuthException()) != NULL){
 
5449
                      Tcl_SetResult(interp, aes, TCL_VOLATILE);
5017
5450
                    }
5018
5451
                    else{
5019
5452
                      Tcl_SetResult(interp,
5061
5494
    else if((op = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){
5062
5495
        if(ps_global && ps_global->mail_stream){
5063
5496
            if(!strcmp(op, "select")){
5064
 
                return(peSelect(interp, objc - 2, &((Tcl_Obj **) objv)[2]));
 
5497
                return(peSelect(interp, objc - 2, &((Tcl_Obj **) objv)[2], MN_SLCT));
 
5498
            }
 
5499
            else if(!strcmp(op, "search")){
 
5500
                return(peSelect(interp, objc - 2, &((Tcl_Obj **) objv)[2], MN_SRCH));
5065
5501
            }
5066
5502
            else if(!strucmp(op, "apply")){
5067
5503
                return(peApply(interp, objc - 2, &((Tcl_Obj **) objv)[2]));
5147
5583
                Tcl_SetResult(interp, ps_global->last_error, TCL_VOLATILE);
5148
5584
                return(TCL_OK);
5149
5585
            }
 
5586
            else if(!strcmp(op, "trashdeleted")){
 
5587
                /*
 
5588
                 * CMD: trashdeleted
 
5589
                 *
 
5590
                 * Returns: OK after moving deleted messages to Trash and expunging
 
5591
                 */
 
5592
                MAILSTREAM   *stream;
 
5593
                MESSAGECACHE *mc;
 
5594
                CONTEXT_S    *cp;
 
5595
                MSGNO_S      *msgmap;
 
5596
                char         *streamstr = NULL, tmp[MAILTMPLEN];
 
5597
                long          n, tomove = 0L;
 
5598
 
 
5599
                if(objc == 3) streamstr = Tcl_GetStringFromObj(objv[2], NULL);
 
5600
                if(!streamstr
 
5601
                   || (streamstr && (strcmp(streamstr, "current") == 0))){
 
5602
                    stream = ps_global->mail_stream;
 
5603
                    msgmap = sp_msgmap(stream);
 
5604
                }
 
5605
                else if(streamstr && (strcmp(streamstr, "inbox") == 0)){
 
5606
                    stream = sp_inbox_stream();
 
5607
                    msgmap = sp_msgmap(stream);
 
5608
                }
 
5609
                else return(TCL_ERROR);
 
5610
 
 
5611
                ps_global->last_error[0] = '\0';
 
5612
                if(IS_NEWS(stream) && stream->rdonly){
 
5613
                    msgno_exclude_deleted(stream, msgmap);
 
5614
                    clear_index_cache(sp_inbox_stream(), 0);
 
5615
 
 
5616
                    /*
 
5617
                     * This is kind of surprising at first. For most sort
 
5618
                     * orders, if the whole set is sorted, then any subset
 
5619
                     * is also sorted. Not so for OrderedSubject sort.
 
5620
                     * If you exclude the first message of a subject group
 
5621
                     * then you change the date that group is to be sorted on.
 
5622
                     */
 
5623
                    if(mn_get_sort(msgmap) == SortSubject2)
 
5624
                      refresh_sort(ps_global->mail_stream, msgmap, FALSE);
 
5625
                }
 
5626
                else{
 
5627
                    if(!(cp = default_save_context(ps_global->context_list)))
 
5628
                      cp = ps_global->context_list;
 
5629
 
 
5630
                    /* copy to trash if we're not in trash */
 
5631
                    if(ps_global->VAR_TRASH_FOLDER
 
5632
                       && ps_global->VAR_TRASH_FOLDER[0]
 
5633
                       && context_allowed(context_apply(tmp, cp, ps_global->VAR_TRASH_FOLDER, sizeof(tmp)))
 
5634
                       && !same_stream_and_mailbox(tmp, stream)){
 
5635
 
 
5636
                        /* save real selected set, and  */
 
5637
                        for(n = 1L; n <= mn_get_total(msgmap); n++){
 
5638
                            set_lflag(stream, msgmap, n, MN_STMP, get_lflag(stream, msgmap, n, MN_SLCT));
 
5639
                            /* select deleted */
 
5640
                            if(!get_lflag(stream, msgmap, n, MN_EXLD)
 
5641
                               && (mc = mail_elt(stream, mn_m2raw(msgmap,n))) != NULL && mc->deleted){
 
5642
                                tomove++;
 
5643
                                set_lflag(stream, msgmap, n, MN_SLCT, 1);
 
5644
                            }
 
5645
                            else
 
5646
                              set_lflag(stream, msgmap, n, MN_SLCT, 0);
 
5647
                        }
 
5648
 
 
5649
                        if(tomove && pseudo_selected(stream, msgmap)){
 
5650
 
 
5651
                            /* save delted to Trash */
 
5652
                            n = save(ps_global, stream,
 
5653
                                     cp, ps_global->VAR_TRASH_FOLDER,
 
5654
                                     msgmap, SV_FOR_FILT | SV_FIX_DELS);
 
5655
 
 
5656
                            /* then remove them */
 
5657
                            if(n == tomove){
 
5658
                                (void) cmd_expunge_work(stream, msgmap);
 
5659
                            }
 
5660
 
 
5661
                            restore_selected(msgmap);
 
5662
                        }
 
5663
 
 
5664
                        /* restore selected set */
 
5665
                        for(n = 1L; n <= mn_get_total(msgmap); n++)
 
5666
                          set_lflag(stream, msgmap, n, MN_SLCT,
 
5667
                                    get_lflag(stream, msgmap, n, MN_STMP));
 
5668
                    }
 
5669
                }
 
5670
 
 
5671
                Tcl_SetResult(interp, ps_global->last_error, TCL_VOLATILE);
 
5672
                return(TCL_OK);
 
5673
            }
5150
5674
            else if(!strcmp(op, "nextvector")){
5151
5675
                long     msgno, count, countdown;
5152
5676
                int      i, aObjN = 0;
5176
5700
 
5177
5701
                                if((rvObj = Tcl_NewListObj(0, NULL)) != NULL && count > 0
5178
5702
                                   && !(msgno < 1L || msgno > mn_get_total(sp_msgmap(ps_global->mail_stream)))){
5179
 
                                    mn_set_cur(ps_global->msgmap, msgno);
 
5703
                                    mn_set_cur(sp_msgmap(ps_global->mail_stream), msgno);
5180
5704
 
5181
5705
                                    for(countdown = count; countdown > 0; countdown--){
5182
 
                                        long    n = mn_get_cur(ps_global->msgmap);
5183
 
                                        imapuid_t  uid = mail_uid(ps_global->mail_stream, mn_m2raw(ps_global->msgmap, n));
5184
 
                                        int   fetched = 0;
 
5706
                                        imapuid_t  uid = mail_uid(ps_global->mail_stream, mn_m2raw(sp_msgmap(ps_global->mail_stream), msgno));
 
5707
                                        int        fetched = 0;
5185
5708
 
5186
5709
                                        if((vObj = Tcl_NewListObj(0, NULL)) != NULL){
5187
 
                                            Tcl_ListObjAppendElement(interp, vObj, Tcl_NewLongObj(n));
 
5710
                                            Tcl_ListObjAppendElement(interp, vObj, Tcl_NewLongObj(msgno));
5188
5711
                                            peAppListF(interp, vObj, "%lu", uid);
5189
5712
 
5190
5713
                                            if(aObjN){
5193
5716
                                                        if((s = Tcl_GetStringFromObj(aObj[i], NULL)) != NULL){
5194
5717
                                                            if(!strcmp(s, "statusbits")){
5195
5718
                                                                char *s = peMsgStatBitString(ps_global, ps_global->mail_stream,
5196
 
                                                                                             ps_global->msgmap, peMessageNumber(uid),
 
5719
                                                                                             sp_msgmap(ps_global->mail_stream), peMessageNumber(uid),
5197
5720
                                                                                             peITop, peICount, &fetched);
5198
5721
                                                                Tcl_ListObjAppendElement(interp, avObj, Tcl_NewStringObj(s, -1));
5199
5722
                                                            }
5200
5723
                                                            else if(!strcmp(s, "statuslist")){
5201
5724
                                                                Tcl_Obj *nObj = peMsgStatNameList(interp, ps_global, ps_global->mail_stream,
5202
 
                                                                                                  ps_global->msgmap, peMessageNumber(uid),
 
5725
                                                                                                  sp_msgmap(ps_global->mail_stream), peMessageNumber(uid),
5203
5726
                                                                                                  peITop, peICount, &fetched);
5204
5727
                                                                Tcl_ListObjAppendElement(interp, avObj, nObj);
5205
5728
                                                            }
5258
5781
 
5259
5782
                                        Tcl_ListObjAppendElement(interp, rvObj, vObj);
5260
5783
 
5261
 
                                        mn_inc_cur(ps_global->mail_stream, ps_global->msgmap, MH_NONE);
 
5784
                                        for(++msgno; msgno <= mn_get_total(sp_msgmap(ps_global->mail_stream)) && msgline_hidden(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), msgno, MN_NONE); msgno++)
 
5785
                                          ;
5262
5786
 
5263
 
                                        if(n == mn_get_cur(ps_global->msgmap))
 
5787
                                        if(msgno > mn_get_total(sp_msgmap(ps_global->mail_stream)))
5264
5788
                                          break;
5265
5789
                                    }
5266
5790
                                }
5314
5838
                     *          changed otherwise (expunged screw us?)
5315
5839
                     */
5316
5840
                    Tcl_SetResult(interp,
5317
 
                                  long2string(mn_get_cur(ps_global->msgmap)),
 
5841
                                  long2string(mn_get_cur(sp_msgmap(ps_global->mail_stream))),
5318
5842
                                  TCL_VOLATILE);
5319
5843
                    return(TCL_OK);
5320
5844
                }
5326
5850
                     */
5327
5851
 
5328
5852
                    Tcl_SetResult(interp,
5329
 
                                  long2string(any_lflagged(ps_global->msgmap, MN_SLCT)),
 
5853
                                  long2string(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SLCT)),
 
5854
                                  TCL_VOLATILE);
 
5855
                    return(TCL_OK);
 
5856
                }
 
5857
                else if(!strcmp(op, "searched")){
 
5858
                    /*
 
5859
                     * CMD: searched
 
5860
                     *
 
5861
                     * Returns: count of searched messsages in open mailbox
 
5862
                     */
 
5863
 
 
5864
                    Tcl_SetResult(interp,
 
5865
                                  long2string(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SRCH)),
5330
5866
                                  TCL_VOLATILE);
5331
5867
                    return(TCL_OK);
5332
5868
                }
5411
5947
                }
5412
5948
                else if(!strcmp(op, "zoom")){
5413
5949
                    Tcl_SetResult(interp,
5414
 
                                  long2string((any_lflagged(ps_global->msgmap, MN_HIDE) > 0L)
5415
 
                                                ? any_lflagged(ps_global->msgmap, MN_SLCT) : 0L),
 
5950
                                  long2string((any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE) > 0L)
 
5951
                                                ? any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SLCT) : 0L),
 
5952
                                  TCL_VOLATILE);
 
5953
                    return(TCL_OK);
 
5954
                }
 
5955
                else if(!strcmp(op, "focus")){
 
5956
                    Tcl_SetResult(interp,
 
5957
                                  long2string((any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE) > 0L)
 
5958
                                                ? any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SRCH) : 0L),
5416
5959
                                  TCL_VOLATILE);
5417
5960
                    return(TCL_OK);
5418
5961
                }
5419
5962
                else if(!strcmp(op, "first")){
5420
 
                    if(any_lflagged(ps_global->msgmap, MN_HIDE)){
 
5963
                    if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE)){
5421
5964
                        long n;
5422
5965
 
5423
5966
                        for(n = 1L; n <= mn_get_total(sp_msgmap(ps_global->mail_stream)); n++)
5424
 
                          if(!get_lflag(ps_global->mail_stream, ps_global->msgmap, n, MN_HIDE)){
 
5967
                          if(!get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_HIDE)){
5425
5968
                              Tcl_SetResult(interp, long2string(n), TCL_VOLATILE);
5426
5969
                              return(TCL_OK);
5427
5970
                          }
5428
5971
 
5429
 
                        unzoom_index(ps_global, ps_global->mail_stream, ps_global->msgmap);
 
5972
                        unzoom_index(ps_global, ps_global->mail_stream, sp_msgmap(ps_global->mail_stream));
5430
5973
                        
5431
5974
                    }
5432
5975
 
5433
5976
                    Tcl_SetResult(interp, int2string(1), TCL_VOLATILE);
5434
5977
                    return(TCL_OK);
5435
5978
                }
 
5979
                else if(!strucmp(op, "current")){
 
5980
                    long          n = 0;
 
5981
                    unsigned long u = 0;
 
5982
 
 
5983
                    /*
 
5984
                     * CMD: current
 
5985
                     *
 
5986
                     * ARGS:
 
5987
                     *
 
5988
                     * Returns: list of current msg {<sequence> <uid>}
 
5989
                     */
 
5990
 
 
5991
                    if(mn_total_cur(sp_msgmap(ps_global->mail_stream)) <= 0
 
5992
                       || ((n = mn_get_cur(sp_msgmap(ps_global->mail_stream))) > 0
 
5993
                           && (u = mail_uid(ps_global->mail_stream, mn_m2raw(sp_msgmap(ps_global->mail_stream), n))) > 0)){
 
5994
                        Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(long2string(n), -1));
 
5995
                        Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(ulong2string(u), -1));
 
5996
                        return(TCL_OK);
 
5997
                    }
 
5998
                    else
 
5999
                      err = "Cannot get current";
 
6000
                }
5436
6001
                else if(!strcmp(op, "last")){
5437
 
                    if(any_lflagged(ps_global->msgmap, MN_HIDE)){
 
6002
                    if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE)){
5438
6003
                        long n;
5439
6004
 
5440
6005
                        for(n = mn_get_total(sp_msgmap(ps_global->mail_stream)); n > 0L; n--)
5441
 
                          if(!get_lflag(ps_global->mail_stream, ps_global->msgmap, n, MN_HIDE)){
 
6006
                          if(!get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_HIDE)){
5442
6007
                              Tcl_SetResult(interp, long2string(n), TCL_VOLATILE);
5443
6008
                              return(TCL_OK);
5444
6009
                          }
5481
6046
                    return(TCL_OK);
5482
6047
                }
5483
6048
                else if(!strucmp(op, "excludedeleted")){
5484
 
                    msgno_exclude_deleted(ps_global->mail_stream, ps_global->msgmap);
 
6049
                    msgno_exclude_deleted(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream));
5485
6050
                    return(TCL_OK);
5486
6051
                }
5487
6052
            }
5498
6063
                    if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_OK)
5499
6064
                      return(TCL_ERROR); /* conversion problem? */
5500
6065
 
5501
 
                    if((raw = mn_m2raw(ps_global->msgmap, msgno)) > 0L){
 
6066
                    if((raw = mn_m2raw(sp_msgmap(ps_global->mail_stream), msgno)) > 0L){
5502
6067
                        raw = mail_uid(ps_global->mail_stream, raw);
5503
6068
                        Tcl_SetResult(interp, long2string(raw), TCL_VOLATILE);
5504
6069
                        return(TCL_OK);
5616
6181
 
5617
6182
                    if(Tcl_GetIntFromObj(interp, objv[2], &newstate) != TCL_ERROR){
5618
6183
                        if(newstate > 0){
5619
 
                            if(any_lflagged(ps_global->msgmap, MN_HIDE) != (mn_get_total(sp_msgmap(ps_global->mail_stream)) - (n = any_lflagged(ps_global->msgmap, MN_SLCT)))){
5620
 
                                zoom_index(ps_global, ps_global->mail_stream, ps_global->msgmap);
 
6184
                            if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE) != (mn_get_total(sp_msgmap(ps_global->mail_stream)) - (n = any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SLCT)))){
 
6185
                                zoom_index(ps_global, ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MN_SLCT);
5621
6186
                                zoomed = n;
5622
6187
                            }
5623
6188
                        }
5624
6189
                        else{
5625
 
                            if(any_lflagged(ps_global->msgmap, MN_HIDE))
5626
 
                              unzoom_index(ps_global, ps_global->mail_stream, ps_global->msgmap);
 
6190
                            if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE))
 
6191
                              unzoom_index(ps_global, ps_global->mail_stream, sp_msgmap(ps_global->mail_stream));
 
6192
                        }
 
6193
                    }
 
6194
 
 
6195
                    Tcl_SetResult(interp, long2string(zoomed), TCL_VOLATILE);
 
6196
                    return(TCL_OK);
 
6197
                }
 
6198
                else if(!strcmp(op, "focus")){
 
6199
                    int  newstate;
 
6200
                    long n, zoomed = 0L;
 
6201
 
 
6202
                    /*
 
6203
                     * CMD: focus
 
6204
                     *
 
6205
                     *    Set/clear HID bits of non MN_SRCH messages as requested.
 
6206
                     *    PEMailbox [first | last | next] are senstive to MN_HIDE flag
 
6207
                     *
 
6208
                     * ARGS: newstate - 1 or 0
 
6209
                     *
 
6210
                     * Returns: count of zoomed messages
 
6211
                     */
 
6212
 
 
6213
                    if(Tcl_GetIntFromObj(interp, objv[2], &newstate) != TCL_ERROR){
 
6214
                        if(newstate > 0){
 
6215
                            if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE) != (mn_get_total(sp_msgmap(ps_global->mail_stream)) - (n = any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SRCH))))
 
6216
                              zoom_index(ps_global, ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MN_SRCH);
 
6217
 
 
6218
                            zoomed = n;
 
6219
                        }
 
6220
                        else{
 
6221
                            if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE))
 
6222
                              unzoom_index(ps_global, ps_global->mail_stream, sp_msgmap(ps_global->mail_stream));
5627
6223
                        }
5628
6224
                    }
5629
6225
 
5634
6230
                    long  msgno;
5635
6231
 
5636
6232
                    /*
5637
 
                     * CMD: next
 
6233
                     * CMD: next <msgno>
5638
6234
                     *
5639
6235
                     * ARGS: msgno - message number "next" is relative to
5640
6236
                     *
5642
6238
                     */
5643
6239
 
5644
6240
                    if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR){
5645
 
                        mn_set_cur(ps_global->msgmap, msgno);
5646
 
                        mn_inc_cur(ps_global->mail_stream, ps_global->msgmap, MH_NONE);
5647
 
                        Tcl_SetResult(interp, long2string(mn_get_cur(ps_global->msgmap)), TCL_VOLATILE);
 
6241
                        mn_set_cur(sp_msgmap(ps_global->mail_stream), msgno);
 
6242
                        mn_inc_cur(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MH_NONE);
 
6243
                        Tcl_SetResult(interp, long2string(mn_get_cur(sp_msgmap(ps_global->mail_stream))), TCL_VOLATILE);
5648
6244
                        return(TCL_OK);
5649
6245
                    }
5650
6246
 
5671
6267
                        for(i = 0; ps_global->sort_types[i] != EndofList; i++)
5672
6268
                          if(strucmp(sort_name(ps_global->sort_types[i]), sort) == 0){
5673
6269
                              if(sp_unsorted_newmail(ps_global->mail_stream)
5674
 
                                 || !(ps_global->sort_types[i] == mn_get_sort(ps_global->msgmap)
5675
 
                                      && mn_get_revsort(ps_global->msgmap) == reversed))
5676
 
                                sort_folder(ps_global->mail_stream, ps_global->msgmap,
 
6270
                                 || !(ps_global->sort_types[i] == mn_get_sort(sp_msgmap(ps_global->mail_stream))
 
6271
                                      && mn_get_revsort(sp_msgmap(ps_global->mail_stream)) == reversed))
 
6272
                                sort_folder(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream),
5677
6273
                                            ps_global->sort_types[i], 
5678
6274
                                            reversed, 0);
5679
6275
 
5684
6280
                    return(peAppendCurrentSort(interp));
5685
6281
                }
5686
6282
                else if(!strucmp(op, "selected")){
5687
 
                    int   rv = 0;
5688
 
                    long  i, n;
5689
 
                    char *range;
5690
 
 
5691
 
                    /*
5692
 
                     * CMD: selected [before | after] #
5693
 
                     *
5694
 
                     * Returns: 1 if criteria is true, 0 otherwise
5695
 
                     */
5696
 
 
5697
 
                    if((range = Tcl_GetStringFromObj(objv[2], NULL))
5698
 
                       && Tcl_GetLongFromObj(interp, objv[3], &n) != TCL_ERROR){
5699
 
                        if(!strucmp(range, "before")){
5700
 
                            for(i = 1L; i < n && i <= mn_get_total(sp_msgmap(ps_global->mail_stream)); i++)
5701
 
                              if(get_lflag(ps_global->mail_stream, ps_global->msgmap, i, MN_SLCT)){
5702
 
                                  rv = 1;
5703
 
                                  break;
5704
 
                              }
5705
 
 
5706
 
                            Tcl_SetResult(interp, int2string(rv), TCL_STATIC);
5707
 
                            return(TCL_OK);
5708
 
                        }
5709
 
                        else if(!strucmp(range, "after")){
5710
 
                            for(i = n + 1L; i <= mn_get_total(sp_msgmap(ps_global->mail_stream)); i++)
5711
 
                              if(get_lflag(ps_global->mail_stream, ps_global->msgmap, i, MN_SLCT)){
5712
 
                                  rv = 1;
5713
 
                                  break;
5714
 
                              }
5715
 
 
5716
 
                            Tcl_SetResult(interp, int2string(rv), TCL_STATIC);
5717
 
                            return(TCL_OK);
5718
 
                        }
5719
 
                    }
5720
 
 
5721
 
                    Tcl_SetResult(interp, "selected test failed", TCL_STATIC);
5722
 
                    return(TCL_ERROR);
 
6283
                    return(peSelected(interp, objc - 2, &((Tcl_Obj **) objv)[2], MN_SLCT));
 
6284
                }
 
6285
                else if(!strucmp(op, "searched")){
 
6286
                    return(peSelected(interp, objc - 2, &((Tcl_Obj **) objv)[2], MN_SRCH));
5723
6287
                }
5724
6288
                else if(!strcmp(op, "next")){
5725
6289
                    long  msgno, count;
5735
6299
 
5736
6300
                    if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR
5737
6301
                       && Tcl_GetLongFromObj(interp, objv[3], &count) != TCL_ERROR){
5738
 
                        mn_set_cur(ps_global->msgmap, msgno);
 
6302
                        mn_set_cur(sp_msgmap(ps_global->mail_stream), msgno);
5739
6303
                        while(count)
5740
6304
                          if(count > 0){
5741
 
                              mn_inc_cur(ps_global->mail_stream, ps_global->msgmap, MH_NONE);
 
6305
                              mn_inc_cur(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MH_NONE);
5742
6306
                              count--;
5743
6307
                          }
5744
6308
                          else{
5745
 
                              mn_dec_cur(ps_global->mail_stream, ps_global->msgmap, MH_NONE);
 
6309
                              mn_dec_cur(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MH_NONE);
5746
6310
                              count++;
5747
6311
                          }
5748
6312
 
5749
 
                        Tcl_SetResult(interp, long2string(mn_get_cur(ps_global->msgmap)), TCL_VOLATILE);
 
6313
                        Tcl_SetResult(interp, long2string(mn_get_cur(sp_msgmap(ps_global->mail_stream))), TCL_VOLATILE);
5750
6314
                        return(TCL_OK);
5751
6315
                    }
5752
6316
 
5768
6332
                    if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR
5769
6333
                       && Tcl_GetLongFromObj(interp, objv[3], &count) != TCL_ERROR){
5770
6334
                        if(count > 0 && !(msgno < 1L || msgno > mn_get_total(sp_msgmap(ps_global->mail_stream)))){
5771
 
                            mn_set_cur(ps_global->msgmap, msgno);
 
6335
                            mn_set_cur(sp_msgmap(ps_global->mail_stream), msgno);
5772
6336
 
5773
6337
                            while(count--){
5774
 
                                long n = mn_get_cur(ps_global->msgmap);
 
6338
                                long n = mn_get_cur(sp_msgmap(ps_global->mail_stream));
5775
6339
 
5776
6340
                                if(peAppListF(interp, Tcl_GetObjResult(interp),
5777
6341
                                              "%l%l", n, mail_uid(ps_global->mail_stream,
5778
 
                                                              mn_m2raw(ps_global->msgmap, n))) != TCL_OK)
 
6342
                                                              mn_m2raw(sp_msgmap(ps_global->mail_stream), n))) != TCL_OK)
5779
6343
                                  return(TCL_ERROR);
5780
6344
 
5781
 
                                mn_inc_cur(ps_global->mail_stream, ps_global->msgmap, MH_NONE);
 
6345
                                mn_inc_cur(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MH_NONE);
5782
6346
 
5783
 
                                if(n == mn_get_cur(ps_global->msgmap))
 
6347
                                if(n == mn_get_cur(sp_msgmap(ps_global->mail_stream)))
5784
6348
                                  break;
5785
6349
                            }
5786
6350
                        }
5813
6377
 
5814
6378
                        if(!strucmp(relative, "before")){
5815
6379
                            for(n = msgno - 1; n > 0L; n--)
5816
 
                              if(!get_lflag(ps_global->mail_stream, ps_global->msgmap, n, MN_HIDE))
 
6380
                              if(!get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_HIDE))
5817
6381
                                count++;
5818
6382
 
5819
6383
                            Tcl_SetResult(interp, long2string(count), TCL_VOLATILE);
5821
6385
                        }
5822
6386
                        else if(!strucmp(relative, "after")){
5823
6387
                            for(n = msgno + 1; n <= mn_get_total(sp_msgmap(ps_global->mail_stream)); n++)
5824
 
                              if(!get_lflag(ps_global->mail_stream, ps_global->msgmap, n, MN_HIDE))
 
6388
                              if(!get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_HIDE))
5825
6389
                                count++;
5826
6390
 
5827
6391
                            Tcl_SetResult(interp, long2string(count), TCL_VOLATILE);
5847
6411
                    if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR
5848
6412
                       && Tcl_GetLongFromObj(interp, objv[3], &count) != TCL_ERROR){
5849
6413
                        if(msgno > 0L){
5850
 
                            mn_set_cur(ps_global->msgmap, msgno);
 
6414
                            mn_set_cur(sp_msgmap(ps_global->mail_stream), msgno);
5851
6415
                            while(count--){
5852
 
                                msgno = mn_get_cur(ps_global->msgmap);
 
6416
                                msgno = mn_get_cur(sp_msgmap(ps_global->mail_stream));
5853
6417
 
5854
 
                                if(get_lflag(ps_global->mail_stream, ps_global->msgmap, msgno, MN_SLCT))
 
6418
                                if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), msgno, MN_SLCT))
5855
6419
                                  if(Tcl_ListObjAppendElement(interp,
5856
6420
                                                              Tcl_GetObjResult(interp),
5857
6421
                                                              Tcl_NewLongObj((long) mail_uid(ps_global->mail_stream, msgno))) != TCL_OK)
5858
6422
                                    return(TCL_ERROR);
5859
6423
 
5860
 
                                mn_inc_cur(ps_global->mail_stream, ps_global->msgmap, MH_NONE);
 
6424
                                mn_inc_cur(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MH_NONE);
5861
6425
 
5862
 
                                if(msgno == mn_get_cur(ps_global->msgmap))
 
6426
                                if(msgno == mn_get_cur(sp_msgmap(ps_global->mail_stream)))
5863
6427
                                  break;
5864
6428
                            }
5865
6429
                        }
5870
6434
                    Tcl_SetResult(interp, "selectvector: no message number", TCL_STATIC);
5871
6435
                    return(TCL_ERROR);
5872
6436
                }
 
6437
                else if(!strucmp(op, "current")){
 
6438
                    char          *which;
 
6439
                    long           x, n = 0, u = 0;
 
6440
 
 
6441
                    /*
 
6442
                     * CMD: current
 
6443
                     *
 
6444
                     * ARGS: (number|uid) <msgno>
 
6445
                     *
 
6446
                     * Returns: list of current msg {<sequence> <uid>}
 
6447
                     */
 
6448
                    if((which = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
 
6449
                        if(Tcl_GetLongFromObj(interp, objv[3], &x) == TCL_OK){
 
6450
                            if(!strucmp(which,"uid")){
 
6451
                                u = x;
 
6452
                                n = peMessageNumber(u);
 
6453
                            }
 
6454
                            else if(!strucmp(which,"number")){
 
6455
                                n = x;
 
6456
                                u = mail_uid(ps_global->mail_stream, mn_m2raw(sp_msgmap(ps_global->mail_stream), n));
 
6457
                            }
 
6458
 
 
6459
                            if(n && u){
 
6460
                                mn_set_cur(sp_msgmap(ps_global->mail_stream), n);
 
6461
                                Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(long2string(n), -1));
 
6462
                                Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(long2string(u), -1));
 
6463
                                return(TCL_OK);
 
6464
                            }
 
6465
                            else
 
6466
                              err = "PEMailbox current: invalid number/uid";
 
6467
                        }
 
6468
                        else
 
6469
                          err = "PEMailbox current: cannot get number";
 
6470
                    }
 
6471
                    else
 
6472
                      err = "PEMailbox current: cannot get which";
 
6473
                }
5873
6474
            }
5874
6475
            else
5875
6476
              err = "PEMailbox: Too many arguments";
5893
6494
{
5894
6495
    return((Tcl_ListObjAppendElement(interp,
5895
6496
                                     Tcl_GetObjResult(interp),
5896
 
                                     Tcl_NewStringObj(sort_name(mn_get_sort(ps_global->msgmap)), -1)) == TCL_OK
 
6497
                                     Tcl_NewStringObj(sort_name(mn_get_sort(sp_msgmap(ps_global->mail_stream))), -1)) == TCL_OK
5897
6498
            && Tcl_ListObjAppendElement(interp,
5898
6499
                                        Tcl_GetObjResult(interp),
5899
 
                                        Tcl_NewStringObj(mn_get_revsort(ps_global->msgmap) ? "1" : "0", 1)) == TCL_OK)
 
6500
                                        Tcl_NewStringObj(mn_get_revsort(sp_msgmap(ps_global->mail_stream)) ? "1" : "0", 1)) == TCL_OK)
5900
6501
             ? TCL_OK : TCL_ERROR);
5901
6502
}
5902
6503
 
5915
6516
 
5916
6517
 
5917
6518
int
5918
 
peSelect(Tcl_Interp *interp, int objc, Tcl_Obj **objv)
 
6519
peSelect(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag)
5919
6520
{
5920
 
    char *subcmd;
5921
 
    long  n, i, diff, msgno;
5922
 
    int   narrow, hidden;
 
6521
    char         *subcmd;
 
6522
    long          n, i, diff, msgno;
 
6523
    int           narrow, hidden;
 
6524
    MESSAGECACHE *mc;
5923
6525
    extern     MAILSTREAM *mm_search_stream;
5924
6526
    extern     long        mm_search_count;
5925
6527
 
5926
 
    hidden           = any_lflagged(ps_global->msgmap, MN_HIDE) > 0L;
 
6528
    hidden           = any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE) > 0L;
5927
6529
    mm_search_stream = ps_global->mail_stream;
5928
6530
    mm_search_count  = 0L;
5929
6531
 
5930
6532
    for(n = 1L; n <= ps_global->mail_stream->nmsgs; n++)
5931
 
      mail_elt(ps_global->mail_stream, n)->searched = 0;
 
6533
      if((mc = mail_elt(ps_global->mail_stream, n)) != NULL){
 
6534
          mc->searched = 0;
 
6535
          mc->spare7 = 1;
 
6536
      }
5932
6537
 
5933
6538
    /*
5934
6539
     * CMD: select
5935
6540
     *
5936
6541
     * ARGS: subcmd subcmdargs
5937
6542
     *
5938
 
     * Returns: flip SLCT private bit on all or none
 
6543
     * Returns: flip "matchflag" private bit on all or none
5939
6544
     *          of the messages in the mailbox
5940
6545
     */
5941
6546
    if((subcmd = Tcl_GetStringFromObj(objv[0], NULL)) != NULL){
5943
6548
            /*
5944
6549
             * Args: <none>
5945
6550
             */
5946
 
 
5947
 
            if(objc != 1)
5948
 
              return(peSelectError(interp, subcmd));
5949
 
 
5950
 
            agg_select_all(ps_global->mail_stream, ps_global->msgmap, NULL, 1);
 
6551
            if(matchflag & MN_SLCT){
 
6552
                if(objc != 1)
 
6553
                  return(peSelectError(interp, subcmd));
 
6554
 
 
6555
                agg_select_all(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), NULL, 1);
 
6556
            }
 
6557
            else if(matchflag & MN_SRCH){
 
6558
                for(n = 1L; n <= ps_global->mail_stream->nmsgs; n++)
 
6559
                  set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, matchflag, 1);
 
6560
            }
 
6561
 
5951
6562
            Tcl_SetResult(interp, "All", TCL_VOLATILE);
5952
6563
        }
5953
6564
        else if(!strucmp(subcmd, "none")){
5954
6565
            /*
5955
6566
             * Args: <none>
5956
6567
             */
5957
 
            long n = 0L;
5958
 
 
5959
 
            if(objc != 1)
5960
 
              return(peSelectError(interp, subcmd));
5961
 
 
5962
 
            agg_select_all(ps_global->mail_stream, ps_global->msgmap, &n, 0);
 
6568
            n = 0L;
 
6569
 
 
6570
            if(matchflag & MN_SLCT){
 
6571
                if(objc != 1)
 
6572
                  return(peSelectError(interp, subcmd));
 
6573
 
 
6574
                agg_select_all(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), &n, 0);
 
6575
            }
 
6576
            else if(matchflag & MN_SRCH){
 
6577
                for(n = 1L; n <= ps_global->mail_stream->nmsgs; n++)
 
6578
                  set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, matchflag, 0);
 
6579
            }
 
6580
 
5963
6581
            Tcl_SetResult(interp, long2string(n), TCL_VOLATILE);
5964
6582
        }
 
6583
        else if(!strucmp(subcmd, "searched")){
 
6584
            /*
 
6585
             * Args: <none>
 
6586
             */
 
6587
            for(n = 1L, i = 0; n <= ps_global->mail_stream->nmsgs; n++)
 
6588
              if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_SRCH)){
 
6589
                  i++;
 
6590
                  set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_SLCT, 1);
 
6591
              }
 
6592
 
 
6593
            Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
 
6594
        }
 
6595
        else if(!strucmp(subcmd, "unsearched")){
 
6596
            /*
 
6597
             * Args: <none>
 
6598
             */
 
6599
            for(n = 1L, i = 0; n <= ps_global->mail_stream->nmsgs; n++)
 
6600
              if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_SRCH)){
 
6601
                  i++;
 
6602
                  set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_SLCT, 0);
 
6603
              }
 
6604
 
 
6605
            Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
 
6606
        }
5965
6607
        else{
5966
6608
            if(!strucmp(subcmd, "narrow"))
5967
6609
              narrow = 1;
5974
6616
              return(peSelectError(interp, "missing subcommand"));
5975
6617
 
5976
6618
            if(!strucmp(subcmd, "num")){
5977
 
                /*
5978
 
                 * Args: [broad | narrow] firstnumber lastnumber
5979
 
                 */
5980
 
 
5981
 
                long first = 0L, last = 0L, n;
5982
 
 
5983
 
                if(objc == 4){
5984
 
                    if(Tcl_GetLongFromObj(interp, objv[2], &first) == TCL_OK
5985
 
                       && Tcl_GetLongFromObj(interp, objv[3], &last) == TCL_OK){
5986
 
                        if(last && last < first){
5987
 
                            n = last;
5988
 
                            last = first;
5989
 
                            first = n;
5990
 
                        }
5991
 
 
5992
 
                        if(first >= 1L && first <= mn_get_total(sp_msgmap(ps_global->mail_stream))){
5993
 
                            if(last){
5994
 
                                if(last >= 1L && last <= mn_get_total(sp_msgmap(ps_global->mail_stream))){
5995
 
                                    for(n = first; n <= last; n++)
5996
 
                                      mm_searched(ps_global->mail_stream,
5997
 
                                                  mn_m2raw(ps_global->msgmap, n));
5998
 
                                }
5999
 
                                else
6000
 
                                  return(peSelectError(interp, "last out of range"));
6001
 
                            }
6002
 
                            else{
6003
 
                                mm_searched(ps_global->mail_stream,
6004
 
                                            mn_m2raw(ps_global->msgmap, first));
6005
 
                            }
6006
 
                        }
6007
 
                        else
6008
 
                          return(peSelectError(interp, "first out of range"));
6009
 
                    }
6010
 
                    else
6011
 
                      return(peSelectError(interp, "can't read first/last"));
6012
 
                }
6013
 
                else
6014
 
                  return(peSelectError(interp, "num first last"));
 
6619
                if((i = peSelectNumber(interp, objc - 2, &objv[2], matchflag)) != TCL_OK)
 
6620
                  return(i);
6015
6621
            }
6016
6622
            else if(!strucmp(subcmd, "date")){
6017
 
                /*
6018
 
                 * Args: [broad | narrow] 
6019
 
                 *       tense - "on", "since", "before"
6020
 
                 *       year - 4 digit year
6021
 
                 *       month - abbreviated month "jan", "feb"...
6022
 
                 *       day - day number
6023
 
                 */
6024
 
 
6025
 
                char *tense, *year, *month, *day, buf[256];
6026
 
 
6027
 
                if(objc == 6){
6028
 
                    if((tense = peSelValTense(objv[2])) != NULL){
6029
 
                        if((year = peSelValYear(objv[3])) != NULL){
6030
 
                            if((month = peSelValMonth(objv[4])) != NULL){
6031
 
                                if((day = peSelValDay(objv[5])) != NULL){
6032
 
                                    snprintf(buf, sizeof(buf), "%s %s-%s-%s",
6033
 
                                            tense, day, month, year);
6034
 
                                    mail_search_full(ps_global->mail_stream, NULL,
6035
 
                                                     mail_criteria(buf),
6036
 
                                                     SE_NOPREFETCH | SE_FREE);
6037
 
                                }
6038
 
                                else
6039
 
                                  return(peSelectError(interp, "<with valid day>"));
6040
 
                            }
6041
 
                            else
6042
 
                              return(peSelectError(interp, "<with valid month>"));
6043
 
                        }
6044
 
                        else
6045
 
                          return(peSelectError(interp, "<with valid year>"));
6046
 
                    }
6047
 
                    else
6048
 
                      return(peSelectError(interp, "<with valid tense>"));
6049
 
                }
6050
 
                else
6051
 
                  return(peSelectError(interp, "date tense year monthabbrev daynum"));
 
6623
                if((i = peSelectDate(interp, objc - 2, &objv[2], matchflag)) != TCL_OK)
 
6624
                  return(i);
6052
6625
            }
6053
6626
            else if(!strucmp(subcmd, "text")){
6054
 
                /*
6055
 
                 * Args: [broad | narrow] 
6056
 
                 *       case - in not
6057
 
                 *       field - to from cc recip partic subj any
6058
 
                 *       text - free text search string
6059
 
                 */
6060
 
                int  not;
6061
 
                char field, *text;
6062
 
 
6063
 
                if(objc == 5){
6064
 
                    if((not = peSelValCase(objv[2])) >= 0){
6065
 
                        if((field = peSelValField(objv[3])) != '\0'){
6066
 
                            if((text = Tcl_GetStringFromObj(objv[4], NULL))
6067
 
                               && strlen(text) < 1024){
6068
 
                                /* BUG: fix charset not to be NULL below */
6069
 
                                if(agg_text_select(ps_global->mail_stream,
6070
 
                                                   ps_global->msgmap,
6071
 
                                                   field, not, 0, text, NULL, NULL))
6072
 
                                  /* BUG: plug in "charset" above? */
6073
 
                                  return(peSelectError(interp, "programmer botch"));
6074
 
                            }
6075
 
                            else
6076
 
                              return(peSelectError(interp, "<with search string < 1024>"));
6077
 
                        }
6078
 
                        else
6079
 
                          return(peSelectError(interp, "<with valid field>"));
6080
 
                    }
6081
 
                    else
6082
 
                      return(peSelectError(interp, "<with valid case>"));
6083
 
                }
6084
 
                else
6085
 
                  return(peSelectError(interp, "text case field text"));
 
6627
                if((i = peSelectText(interp, objc - 2, &objv[2], matchflag)) != TCL_OK)
 
6628
                  return(i);
6086
6629
            }
6087
6630
            else if(!strucmp(subcmd, "status")){
6088
 
                /*
6089
 
                 * Args: [broad | narrow] 
6090
 
                 *       case - on not
6091
 
                 *       status - imp new ans del
6092
 
                 */
6093
 
 
6094
 
                int  not;
6095
 
                char flag;
6096
 
 
6097
 
                if(objc == 4){
6098
 
                    if((not = peSelValCase(objv[2])) >= 0){
6099
 
                        if((flag = peSelValFlag(objv[3])) != '\0'){
6100
 
                            if(agg_flag_select(ps_global->mail_stream, not, flag, NULL))
6101
 
                              return(peSelectError(interp, "programmer botch"));
 
6631
                if((i = peSelectStatus(interp, objc - 2, &objv[2], matchflag)) != TCL_OK)
 
6632
                  return(i);
 
6633
            }
 
6634
            else if(!strucmp(subcmd, "compound")){
 
6635
                char     *s;
 
6636
                int       nSearchList, nSearch;
 
6637
                Tcl_Obj **oSearchList, **oSearch;
 
6638
 
 
6639
                /* BUG: should set up one SEARCHPGM to fit criteria and issue single search */
 
6640
 
 
6641
                if(Tcl_ListObjGetElements(interp, objv[2], &nSearchList, &oSearchList) == TCL_OK){
 
6642
                    for(i = 0; i < nSearchList; i++){
 
6643
                        if(Tcl_ListObjGetElements(interp, oSearchList[i], &nSearch, &oSearch) == TCL_OK){
 
6644
                            if((s = Tcl_GetStringFromObj(oSearch[0], NULL)) != NULL){
 
6645
                                if(!strucmp(s,"date")){
 
6646
                                    if((n = peSelectDate(interp, nSearch - 1, &oSearch[1], matchflag)) != TCL_OK)
 
6647
                                      return(n);
 
6648
                                }
 
6649
                                else if(!strucmp(s,"text")){
 
6650
                                    if((n = peSelectText(interp, nSearch - 1, &oSearch[1], matchflag)) != TCL_OK)
 
6651
                                      return(n);
 
6652
                                }
 
6653
                                else if(!strucmp(s,"status")){
 
6654
                                    if((n = peSelectStatus(interp, nSearch - 1, &oSearch[1], matchflag)) != TCL_OK)
 
6655
                                      return(n);
 
6656
                                }
 
6657
                                else
 
6658
                                  return(peSelectError(interp, "unknown compound search"));
 
6659
 
 
6660
                                /* logical AND the results */
 
6661
                                mm_search_count = 0L;
 
6662
                                for(n = 1L; n <= ps_global->mail_stream->nmsgs; n++)
 
6663
                                  if((mc = mail_elt(ps_global->mail_stream, n)) != NULL){
 
6664
                                      if(mc->searched && mc->spare7)
 
6665
                                        mm_search_count++;
 
6666
                                      else
 
6667
                                        mc->searched = mc->spare7 = 0;
 
6668
                                  }
 
6669
                            }
 
6670
                            else
 
6671
                              return(peSelectError(interp, "malformed compound search"));
6102
6672
                        }
6103
6673
                        else
6104
 
                          return(peSelectError(interp, "<with valid flag>"));
 
6674
                          return(peSelectError(interp, "malformed compound search"));
6105
6675
                    }
6106
 
                    else
6107
 
                      return(peSelectError(interp, "<with valid case>"));
6108
 
                }
6109
 
                else
6110
 
                  return(peSelectError(interp, "status focus case flag"));
 
6676
                  }
 
6677
                  else
 
6678
                    return(peSelectError(interp, "malformed compound search"));
6111
6679
            }
6112
6680
            else
6113
6681
              return(peSelectError(interp, "cmd cmdargs"));
6120
6688
            if(narrow)                          /* make sure something was selected */
6121
6689
              for(i = 1L; i <= mn_get_total(sp_msgmap(ps_global->mail_stream)); i++)
6122
6690
                if(mail_elt(ps_global->mail_stream,
6123
 
                            mn_m2raw(ps_global->msgmap, i))->searched){
6124
 
                    if(get_lflag(ps_global->mail_stream, ps_global->msgmap, i, MN_SLCT))
 
6691
                            mn_m2raw(sp_msgmap(ps_global->mail_stream), i))->searched){
 
6692
                    if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag))
6125
6693
                      break;
6126
6694
                    else
6127
6695
                      mm_search_count--;
6136
6704
                for(i = 1L, msgno = 0L; i <= mn_get_total(sp_msgmap(ps_global->mail_stream)); i++)
6137
6705
                  if(narrow){
6138
6706
                      /* turning OFF selectedness if the "searched" bit isn't lit. */
6139
 
                      if(get_lflag(ps_global->mail_stream, ps_global->msgmap, i, MN_SLCT)){
 
6707
                      if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag)){
6140
6708
                          if(!mail_elt(ps_global->mail_stream,
6141
 
                                       mn_m2raw(ps_global->msgmap, i))->searched){
 
6709
                                       mn_m2raw(sp_msgmap(ps_global->mail_stream), i))->searched){
6142
6710
                              diff--;
6143
 
                              set_lflag(ps_global->mail_stream, ps_global->msgmap, i, MN_SLCT, 0);
 
6711
                              set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag, 0);
6144
6712
                              if(hidden)
6145
 
                                set_lflag(ps_global->mail_stream, ps_global->msgmap, i, MN_HIDE, 1);
 
6713
                                set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, MN_HIDE, 1);
6146
6714
                          }
6147
 
                          else if(msgno < mn_get_cur(ps_global->msgmap))
 
6715
                          else if(msgno < mn_get_cur(sp_msgmap(ps_global->mail_stream)))
6148
6716
                            msgno = i;
6149
6717
                      }
6150
6718
                  }
6151
 
                  else if(mail_elt(ps_global->mail_stream,mn_m2raw(ps_global->msgmap,i))->searched){
 
6719
                  else if(mail_elt(ps_global->mail_stream,mn_m2raw(sp_msgmap(ps_global->mail_stream),i))->searched){
6152
6720
                      /* turn ON selectedness if "searched" bit is lit. */
6153
 
                      if(!get_lflag(ps_global->mail_stream, ps_global->msgmap, i, MN_SLCT)){
 
6721
                      if(!get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag)){
6154
6722
                          diff++;
6155
 
                          set_lflag(ps_global->mail_stream, ps_global->msgmap, i, MN_SLCT, 1);
 
6723
                          set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag, 1);
6156
6724
                          if(hidden)
6157
 
                            set_lflag(ps_global->mail_stream, ps_global->msgmap, i, MN_HIDE, 0);
 
6725
                            set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, MN_HIDE, 0);
6158
6726
                      }
6159
6727
                  }
6160
6728
 
6161
6729
                /* if we're zoomed and the current message was unselected */
6162
6730
                if(narrow && msgno
6163
 
                   && get_lflag(ps_global->mail_stream,ps_global->msgmap,mn_get_cur(ps_global->msgmap),MN_HIDE))
6164
 
                  mn_reset_cur(ps_global->msgmap, msgno);
 
6731
                   && get_lflag(ps_global->mail_stream,sp_msgmap(ps_global->mail_stream),mn_get_cur(sp_msgmap(ps_global->mail_stream)),MN_HIDE))
 
6732
                  mn_reset_cur(sp_msgmap(ps_global->mail_stream), msgno);
6165
6733
            }
6166
6734
 
6167
6735
            Tcl_SetResult(interp, long2string(diff), TCL_VOLATILE);
6174
6742
    return(TCL_ERROR);
6175
6743
}
6176
6744
 
 
6745
int
 
6746
peSelectNumber(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag)
 
6747
{
 
6748
    /*
 
6749
     * Args: [broad | narrow] firstnumber lastnumber
 
6750
     */
 
6751
 
 
6752
    long first = 0L, last = 0L, n;
 
6753
 
 
6754
    if(objc == 2){
 
6755
        if(Tcl_GetLongFromObj(interp, objv[0], &first) == TCL_OK
 
6756
           && Tcl_GetLongFromObj(interp, objv[1], &last) == TCL_OK){
 
6757
            if(last && last < first){
 
6758
                n = last;
 
6759
                last = first;
 
6760
                first = n;
 
6761
            }
 
6762
 
 
6763
            if(first >= 1L && first <= mn_get_total(sp_msgmap(ps_global->mail_stream))){
 
6764
                if(last){
 
6765
                    if(last >= 1L && last <= mn_get_total(sp_msgmap(ps_global->mail_stream))){
 
6766
                        for(n = first; n <= last; n++)
 
6767
                          mm_searched(ps_global->mail_stream,
 
6768
                                      mn_m2raw(sp_msgmap(ps_global->mail_stream), n));
 
6769
                    }
 
6770
                    else
 
6771
                      return(peSelectError(interp, "last out of range"));
 
6772
                }
 
6773
                else{
 
6774
                    mm_searched(ps_global->mail_stream,
 
6775
                                mn_m2raw(sp_msgmap(ps_global->mail_stream), first));
 
6776
                }
 
6777
            }
 
6778
            else
 
6779
              return(peSelectError(interp, "first out of range"));
 
6780
        }
 
6781
        else
 
6782
          return(peSelectError(interp, "can't read first/last"));
 
6783
    }
 
6784
    else
 
6785
      return(peSelectError(interp, "num first last"));
 
6786
 
 
6787
    return(TCL_OK);
 
6788
}
 
6789
 
 
6790
int
 
6791
peSelectDate(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag)
 
6792
{
 
6793
    /*
 
6794
     * Args: [broad | narrow] 
 
6795
     *   tense - "on", "since", "before"
 
6796
     *   year - 4 digit year
 
6797
     *   month - abbreviated month "jan", "feb"...
 
6798
     *   day - day number
 
6799
     */
 
6800
 
 
6801
    char *tense, *year, *month, *day, buf[256];
 
6802
 
 
6803
    if(objc == 4){
 
6804
        if((tense = peSelValTense(objv[0])) != NULL){
 
6805
            if((year = peSelValYear(objv[1])) != NULL){
 
6806
                if((month = peSelValMonth(objv[2])) != NULL){
 
6807
                    if((day = peSelValDay(objv[3])) != NULL){
 
6808
                        snprintf(buf, sizeof(buf), "%s %s-%s-%s", tense, day, month, year);
 
6809
                        pine_mail_search_full(ps_global->mail_stream, NULL,
 
6810
                                              mail_criteria(buf),
 
6811
                                              SE_NOPREFETCH | SE_FREE);
 
6812
                    }
 
6813
                    else
 
6814
                      return(peSelectError(interp, "<with valid day>"));
 
6815
                }
 
6816
                else
 
6817
                  return(peSelectError(interp, "<with valid month>"));
 
6818
            }
 
6819
            else
 
6820
              return(peSelectError(interp, "<with valid year>"));
 
6821
        }
 
6822
        else
 
6823
          return(peSelectError(interp, "<with valid tense>"));
 
6824
    }
 
6825
    else
 
6826
      return(peSelectError(interp, "date tense year monthabbrev daynum"));
 
6827
 
 
6828
    return(TCL_OK);
 
6829
}
 
6830
 
 
6831
int
 
6832
peSelectText(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag)
 
6833
{
 
6834
    /*
 
6835
     * Args: [broad | narrow] 
 
6836
     *   case - in not
 
6837
     *   field - to from cc recip partic subj any
 
6838
     *   text - free text search string
 
6839
     */
 
6840
    int  not;
 
6841
    char field, *text;
 
6842
 
 
6843
    if(objc == 3){
 
6844
        if((not = peSelValCase(objv[0])) >= 0){
 
6845
            if((field = peSelValField(objv[1])) != '\0'){
 
6846
                if((text = Tcl_GetStringFromObj(objv[2], NULL))
 
6847
                   && strlen(text) < 1024){
 
6848
                    /* BUG: fix charset not to be NULL below */
 
6849
                    if(agg_text_select(ps_global->mail_stream,
 
6850
                                       sp_msgmap(ps_global->mail_stream),
 
6851
                                       field, not, 0, text, NULL, NULL))
 
6852
                      /* BUG: plug in "charset" above? */
 
6853
                      return(peSelectError(interp, "programmer botch"));
 
6854
                }
 
6855
                else
 
6856
                  return(peSelectError(interp, "<with search string < 1024>"));
 
6857
            }
 
6858
            else
 
6859
              return(peSelectError(interp, "<with valid field>"));
 
6860
        }
 
6861
        else
 
6862
          return(peSelectError(interp, "<with valid case>"));
 
6863
    }
 
6864
    else
 
6865
      return(peSelectError(interp, "text case field text"));
 
6866
 
 
6867
    return(TCL_OK);
 
6868
}
 
6869
 
 
6870
int
 
6871
peSelectStatus(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag)
 
6872
{
 
6873
    /*
 
6874
     * Args: [broad | narrow] 
 
6875
     *   case - on not
 
6876
     *   status - imp new ans del
 
6877
     */
 
6878
    int  not;
 
6879
    char flag;
 
6880
 
 
6881
    if(objc == 2){
 
6882
        if((not = peSelValCase(objv[0])) >= 0){
 
6883
            if((flag = peSelValFlag(objv[1])) != '\0'){
 
6884
                if(agg_flag_select(ps_global->mail_stream, not, flag, NULL))
 
6885
                  return(peSelectError(interp, "programmer botch"));
 
6886
            }
 
6887
            else
 
6888
              return(peSelectError(interp, "<with valid flag>"));
 
6889
        }
 
6890
        else
 
6891
          return(peSelectError(interp, "<with valid case>"));
 
6892
    }
 
6893
    else
 
6894
      return(peSelectError(interp, "status focus case flag"));
 
6895
 
 
6896
    return(TCL_OK);
 
6897
}
6177
6898
 
6178
6899
char *
6179
6900
peSelValTense(Tcl_Obj *objp)
6270
6991
                  {"any",    'a'},
6271
6992
                  {"recip",  'r'},
6272
6993
                  {"partic", 'p'},
 
6994
                  {"body",   'b'},
6273
6995
                  {NULL,0}};
6274
6996
 
6275
6997
    if((field = Tcl_GetStringFromObj(objp, NULL)) != NULL)
6303
7025
    return(0);
6304
7026
}
6305
7027
 
 
7028
int
 
7029
peSelected(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag)
 
7030
{
 
7031
    int   rv = 0;
 
7032
    long  i, n;
 
7033
    char *range;
 
7034
 
 
7035
    /*
 
7036
     * CMD: searched [before | after] #
 
7037
     *
 
7038
     * Returns: 1 if criteria is true, 0 otherwise
 
7039
     */
 
7040
 
 
7041
    if((range = Tcl_GetStringFromObj(objv[0], NULL))
 
7042
       && Tcl_GetLongFromObj(interp, objv[1], &n) != TCL_ERROR){
 
7043
        if(!strucmp(range, "before")){
 
7044
            for(i = 1L; i < n && i <= mn_get_total(sp_msgmap(ps_global->mail_stream)); i++)
 
7045
              if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag)){
 
7046
                  rv = 1;
 
7047
                  break;
 
7048
              }
 
7049
 
 
7050
            Tcl_SetResult(interp, int2string(rv), TCL_STATIC);
 
7051
            return(TCL_OK);
 
7052
        }
 
7053
        else if(!strucmp(range, "after")){
 
7054
            for(i = n + 1L; i <= mn_get_total(sp_msgmap(ps_global->mail_stream)); i++)
 
7055
              if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag)){
 
7056
                  rv = 1;
 
7057
                  break;
 
7058
              }
 
7059
 
 
7060
            Tcl_SetResult(interp, int2string(rv), TCL_STATIC);
 
7061
            return(TCL_OK);
 
7062
        }
 
7063
    }
 
7064
 
 
7065
    Tcl_SetResult(interp, "searched test failed", TCL_STATIC);
 
7066
    return(TCL_ERROR);
 
7067
}
 
7068
 
6306
7069
 
6307
7070
int
6308
7071
peSelectError(Tcl_Interp *interp, char *usage)
6321
7084
    char *subcmd;
6322
7085
    long  n;
6323
7086
 
6324
 
    if(!(n = any_lflagged(ps_global->msgmap, MN_SLCT))){
 
7087
    if(!(n = any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SLCT))){
6325
7088
        Tcl_SetResult(interp, "No messages selected", TCL_STATIC);
6326
7089
        return(TCL_ERROR);
6327
7090
    }
6329
7092
        if(objc == 1){
6330
7093
            if(!strucmp(subcmd, "delete")){
6331
7094
                /* BUG: is CmdWhere arg always right? */
6332
 
                (void) cmd_delete(ps_global, ps_global->msgmap, MCMD_AGG | MCMD_SILENT, NULL);
 
7095
                (void) cmd_delete(ps_global, sp_msgmap(ps_global->mail_stream), MCMD_AGG | MCMD_SILENT, NULL);
6333
7096
                Tcl_SetResult(interp, long2string(n), TCL_STATIC);
6334
7097
                return(TCL_OK);
6335
7098
            }
6336
7099
            else if(!strucmp(subcmd, "undelete")){
6337
 
                (void) cmd_undelete(ps_global, ps_global->msgmap, MCMD_AGG | MCMD_SILENT);
 
7100
                (void) cmd_undelete(ps_global, sp_msgmap(ps_global->mail_stream), MCMD_AGG | MCMD_SILENT);
6338
7101
                Tcl_SetResult(interp, long2string(n), TCL_STATIC);
6339
7102
                return(TCL_OK);
6340
7103
            }
6347
7110
                 * Args: case - on not
6348
7111
                 *       flag - imp new ans del
6349
7112
                 */
6350
 
 
 
7113
                char flag, *result;
6351
7114
                int  not;
6352
 
                char flag, *seq, *flagstr;
6353
 
                long flags, flagged, flagid;
 
7115
                long flagged;
6354
7116
 
6355
7117
                if((not = peSelValCase(objv[1])) >= 0){
6356
7118
                    if((flag = peSelValFlag(objv[2])) != '\0'){
6357
 
                        switch (flag) {
6358
 
                          case '*' :
6359
 
                            flagstr = "\\FLAGGED";
6360
 
                            flags = not ? 0L : ST_SET;
6361
 
                            flagid = not ? F_FLAG : F_UNFLAG;
6362
 
                            break;
6363
 
                          case 'n' :
6364
 
                            flagstr = "\\SEEN";
6365
 
                            flags = not ? ST_SET : 0L;
6366
 
                            flagid = not ? F_UNSEEN : F_SEEN;
6367
 
                            break;
6368
 
                          case 'a' :
6369
 
                            flagstr = "\\ANSWERED";
6370
 
                            flags = not ? 0L : ST_SET;
6371
 
                            flagid = not ? F_ANS : F_UNANS;
6372
 
                            break;
6373
 
                          case 'd':
6374
 
                            flagstr = "\\DELETED";
6375
 
                            flags = not ? 0L : ST_SET;
6376
 
                            flagid = not ? F_DEL : F_UNDEL;
6377
 
                            break;
6378
 
                          default :
6379
 
                            return(peApplyError(interp, "known flag"));
6380
 
                            break;
6381
 
                        }
6382
 
 
6383
 
                        if(pseudo_selected(ps_global->msgmap)){
6384
 
                            if((seq = currentf_sequence(ps_global->mail_stream,
6385
 
                                                        ps_global->msgmap,
6386
 
                                                        flagid, &flagged, 1,
6387
 
                                                        NULL, NULL)) != NULL){
6388
 
                                mail_flag(ps_global->mail_stream, seq, flagstr, flags);
6389
 
                                fs_give((void **) &seq);
6390
 
                            }
6391
 
 
6392
 
                            restore_selected(ps_global->msgmap);
 
7119
                        result = peApplyFlag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), flag, not, &flagged);
 
7120
                        if(!result){
6393
7121
                            Tcl_SetResult(interp, int2string(flagged), TCL_VOLATILE);
6394
7122
                            return(TCL_OK);
6395
7123
                        }
6396
7124
                        else
6397
 
                          return(peApplyError(interp, "can't select"));
 
7125
                          return(peApplyError(interp, result));
6398
7126
                    }
6399
7127
                    else
6400
7128
                      return(peApplyError(interp, "invalid flag"));
6408
7136
                 *       folder - imp new ans del
6409
7137
                 */
6410
7138
 
6411
 
                int        colid, del, i;
6412
 
                char      *folder, *err;
6413
 
                CONTEXT_S *cp;
6414
 
 
6415
 
                if(Tcl_GetIntFromObj(interp, objv[1], &colid) != TCL_ERROR){
6416
 
 
6417
 
                    for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next)
6418
 
                      if(i == colid){
6419
 
                          if((folder = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
6420
 
                              if(pseudo_selected(ps_global->msgmap)){
6421
 
 
6422
 
                                  del = (!READONLY_FOLDER(ps_global->mail_stream)
6423
 
                                         && F_OFF(F_SAVE_WONT_DELETE, ps_global));
6424
 
                                  i = save(ps_global, ps_global->mail_stream,
6425
 
                                           cp, folder, ps_global->msgmap, del);
6426
 
 
6427
 
                                  err = (i == mn_total_cur(ps_global->msgmap)) ? NULL : "problem saving";
6428
 
 
6429
 
                                  restore_selected(ps_global->msgmap);
6430
 
                                  if(err)
6431
 
                                    return(peApplyError(interp, err));
6432
 
 
6433
 
                                  Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
6434
 
                                  return(TCL_OK);
6435
 
                              }
6436
 
                              else
6437
 
                                return(peApplyError(interp, "can't select"));
6438
 
                          }
6439
 
                          else
6440
 
                            return(peApplyError(interp, "no folder name"));
6441
 
                      }
6442
 
 
6443
 
                      return(peApplyError(interp, "bad colid"));
6444
 
                }
6445
 
                else
6446
 
                  return(peApplyError(interp, "invalid case"));
 
7139
                int        colid, flgs = 0, i;
 
7140
                char      *folder, *err;
 
7141
                CONTEXT_S *cp;
 
7142
 
 
7143
                if(Tcl_GetIntFromObj(interp, objv[1], &colid) != TCL_ERROR){
 
7144
 
 
7145
                    for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next)
 
7146
                      if(i == colid){
 
7147
                          if((folder = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
 
7148
                              if(pseudo_selected(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream))){
 
7149
 
 
7150
                                  if(!READONLY_FOLDER(ps_global->mail_stream)
 
7151
                                     && F_OFF(F_SAVE_WONT_DELETE, ps_global))
 
7152
                                    flgs |= SV_DELETE;
 
7153
 
 
7154
                                  if(colid == 0 && !strucmp(folder, "inbox"))
 
7155
                                    flgs |= SV_INBOXWOCNTXT;
 
7156
 
 
7157
                                  i = save(ps_global, ps_global->mail_stream,
 
7158
                                           cp, folder, sp_msgmap(ps_global->mail_stream), flgs);
 
7159
 
 
7160
                                  err = (i == mn_total_cur(sp_msgmap(ps_global->mail_stream))) ? NULL : "problem saving";
 
7161
 
 
7162
                                  restore_selected(sp_msgmap(ps_global->mail_stream));
 
7163
                                  if(err)
 
7164
                                    return(peApplyError(interp, err));
 
7165
 
 
7166
                                  Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
 
7167
                                  return(TCL_OK);
 
7168
                              }
 
7169
                              else
 
7170
                                return(peApplyError(interp, "can't select"));
 
7171
                          }
 
7172
                          else
 
7173
                            return(peApplyError(interp, "no folder name"));
 
7174
                      }
 
7175
 
 
7176
                      return(peApplyError(interp, "bad colid"));
 
7177
                }
 
7178
                else
 
7179
                  return(peApplyError(interp, "invalid case"));
 
7180
            }
 
7181
            else if(!strucmp(subcmd, "copy")){
 
7182
                /*
 
7183
                 * Args: colid - 
 
7184
                 *       folder - imp new ans del
 
7185
                 */
 
7186
 
 
7187
                int        colid, flgs = 0, i;
 
7188
                char      *folder, *err;
 
7189
                CONTEXT_S *cp;
 
7190
 
 
7191
                if(Tcl_GetIntFromObj(interp, objv[1], &colid) != TCL_ERROR){
 
7192
 
 
7193
                    for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next)
 
7194
                      if(i == colid){
 
7195
                          if((folder = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
 
7196
                              if(pseudo_selected(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream))){
 
7197
 
 
7198
                                  if(colid == 0 && !strucmp(folder, "inbox"))
 
7199
                                    flgs |= SV_INBOXWOCNTXT;
 
7200
 
 
7201
                                  i = save(ps_global, ps_global->mail_stream,
 
7202
                                           cp, folder, sp_msgmap(ps_global->mail_stream), flgs);
 
7203
 
 
7204
                                  err = (i == mn_total_cur(sp_msgmap(ps_global->mail_stream))) ? NULL : "problem copying";
 
7205
 
 
7206
                                  restore_selected(sp_msgmap(ps_global->mail_stream));
 
7207
                                  if(err)
 
7208
                                    return(peApplyError(interp, err));
 
7209
 
 
7210
                                  Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
 
7211
                                  return(TCL_OK);
 
7212
                              }
 
7213
                              else
 
7214
                                return(peApplyError(interp, "can't select"));
 
7215
                          }
 
7216
                          else
 
7217
                            return(peApplyError(interp, "no folder name"));
 
7218
                      }
 
7219
 
 
7220
                      return(peApplyError(interp, "bad colid"));
 
7221
                }
 
7222
                else
 
7223
                  return(peApplyError(interp, "invalid case"));
 
7224
            }
 
7225
            else if(!strucmp(subcmd, "move")){
 
7226
                /*
 
7227
                 * Args: colid - 
 
7228
                 *       folder - imp new ans del
 
7229
                 */
 
7230
 
 
7231
                int        colid, flgs = 0, i;
 
7232
                char      *folder, *err;
 
7233
                CONTEXT_S *cp;
 
7234
 
 
7235
                if(Tcl_GetIntFromObj(interp, objv[1], &colid) != TCL_ERROR){
 
7236
 
 
7237
                    for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next)
 
7238
                      if(i == colid){
 
7239
                          if((folder = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
 
7240
                              if(pseudo_selected(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream))){
 
7241
 
 
7242
                                  flgs = SV_DELETE;
 
7243
 
 
7244
                                  if(colid == 0 && !strucmp(folder, "inbox"))
 
7245
                                    flgs |= SV_INBOXWOCNTXT;
 
7246
 
 
7247
                                  i = save(ps_global, ps_global->mail_stream,
 
7248
                                           cp, folder, sp_msgmap(ps_global->mail_stream), flgs);
 
7249
 
 
7250
                                  err = (i == mn_total_cur(sp_msgmap(ps_global->mail_stream))) ? NULL : "problem moving";
 
7251
 
 
7252
                                  restore_selected(sp_msgmap(ps_global->mail_stream));
 
7253
                                  if(err)
 
7254
                                    return(peApplyError(interp, err));
 
7255
 
 
7256
                                  Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
 
7257
                                  return(TCL_OK);
 
7258
                              }
 
7259
                              else
 
7260
                                return(peApplyError(interp, "can't select"));
 
7261
                          }
 
7262
                          else
 
7263
                            return(peApplyError(interp, "no folder name"));
 
7264
                      }
 
7265
 
 
7266
                      return(peApplyError(interp, "bad colid"));
 
7267
                }
 
7268
                else
 
7269
                  return(peApplyError(interp, "invalid case"));
 
7270
            }
 
7271
            else if(!strucmp(subcmd, "spam")){
 
7272
                /*
 
7273
                 * Args: spamaddr - 
 
7274
                 *       spamsubj - 
 
7275
                 */
 
7276
                char *spamaddr, *spamsubj = NULL;
 
7277
                long  n, rawno;
 
7278
 
 
7279
                if((spamaddr = Tcl_GetStringFromObj(objv[1], NULL))
 
7280
                   && (spamsubj = Tcl_GetStringFromObj(objv[2], NULL))){
 
7281
                    for(n = 1L; n <= mn_get_total(sp_msgmap(ps_global->mail_stream)); n++){
 
7282
                        rawno = mn_m2raw(sp_msgmap(ps_global->mail_stream), n);
 
7283
                        if(get_lflag(ps_global->mail_stream, NULL, rawno, MN_SLCT)){
 
7284
                            char errbuf[WP_MAX_POST_ERROR + 1], *rs = NULL;
 
7285
 
 
7286
                            if((rs = peSendSpamReport(rawno, spamaddr, spamsubj, errbuf)) != NULL){
 
7287
                                Tcl_SetResult(interp, rs, TCL_VOLATILE);
 
7288
                                return(TCL_ERROR);
 
7289
                            }
 
7290
                        }
 
7291
                    }
 
7292
                }
 
7293
 
 
7294
                Tcl_SetResult(interp, "OK", TCL_VOLATILE);
 
7295
                return(TCL_OK);
6447
7296
            }
6448
7297
        }
6449
7298
    }
6452
7301
}
6453
7302
 
6454
7303
 
 
7304
char *
 
7305
peApplyFlag(MAILSTREAM *stream, MSGNO_S *msgmap, char flag, int not, long *flagged)
 
7306
{
 
7307
    char *seq, *flagstr;
 
7308
    long  flags, flagid;
 
7309
 
 
7310
    switch (flag) {
 
7311
      case '*' :
 
7312
        flagstr = "\\FLAGGED";
 
7313
        flags = not ? 0L : ST_SET;
 
7314
        flagid = not ? F_FLAG : F_UNFLAG;
 
7315
        break;
 
7316
      case 'n' :
 
7317
        flagstr = "\\SEEN";
 
7318
        flags = not ? ST_SET : 0L;
 
7319
        flagid = not ? F_UNSEEN : F_SEEN;
 
7320
        break;
 
7321
      case 'a' :
 
7322
        flagstr = "\\ANSWERED";
 
7323
        flags = not ? 0L : ST_SET;
 
7324
        flagid = not ? F_ANS : F_UNANS;
 
7325
        break;
 
7326
      case 'd':
 
7327
        flagstr = "\\DELETED";
 
7328
        flags = not ? 0L : ST_SET;
 
7329
        flagid = not ? F_DEL : F_UNDEL;
 
7330
        break;
 
7331
      default :
 
7332
        return("unknown flag");
 
7333
        break;
 
7334
    }
 
7335
 
 
7336
    if(pseudo_selected(stream, msgmap)){
 
7337
        if((seq = currentf_sequence(stream, msgmap, flagid, flagged, 1, NULL, NULL)) != NULL){
 
7338
            mail_flag(stream, seq, flagstr, flags);
 
7339
            fs_give((void **) &seq);
 
7340
        }
 
7341
 
 
7342
        restore_selected(msgmap);
 
7343
        return(NULL);
 
7344
    }
 
7345
    else
 
7346
      return("can't select");
 
7347
}
 
7348
 
 
7349
 
6455
7350
int
6456
7351
peApplyError(Tcl_Interp *interp, char *usage)
6457
7352
{
6491
7386
            name = "Number";
6492
7387
            break;
6493
7388
 
 
7389
          case iPrio:
 
7390
          case iPrioAlpha:
 
7391
          case iPrioBang:
 
7392
            name = "Priority";
 
7393
            break;
 
7394
 
6494
7395
          case iDate:     case iSDate:      case iSTime:     case iLDate:
6495
7396
          case iS1Date:   case iS2Date:     case iS3Date:    case iS4Date:    case iDateIso:
6496
7397
          case iDateIsoS: 
6505
7406
          case iSDateTimeIso24:             case iSDateTimeIsoS24:
6506
7407
          case iSDateTimeS124:              case iSDateTimeS224:
6507
7408
          case iSDateTimeS324:              case iSDateTimeS424:
 
7409
          case iCurDate:  case iCurDateIso: case iCurDateIsoS:
 
7410
          case iCurTime24:                  case iCurTime12:
 
7411
          case iCurPrefDate:
6508
7412
            name = "Date";
6509
7413
            break;
6510
7414
 
 
7415
          case iCurDay:                     case iCurDay2Digit:
 
7416
          case iCurDayOfWeek:               case iCurDayOfWeekAbb:
 
7417
            name = "Day";
 
7418
            break;
 
7419
 
 
7420
          case iCurMon:                     case iCurMon2Digit:
 
7421
          case iCurMonLong:                 case iCurMonAbb:
 
7422
            name= "Month";
 
7423
            break;
 
7424
 
6511
7425
          case iTime24:     case iTime12:    case iTimezone:  
 
7426
          case iCurPrefTime:
6512
7427
            name = "Time";
6513
7428
            break;
6514
7429
 
6515
 
          case iDay2Digit:  case iDayOfWeekAbb:
 
7430
          case iDay2Digit:  case iDayOfWeek:  case iDayOfWeekAbb:
6516
7431
            name = "Day";
6517
7432
            break;
6518
7433
 
6521
7436
            break;
6522
7437
 
6523
7438
          case iYear: case iYear2Digit:
 
7439
          case iCurYear: case iCurYear2Digit:
6524
7440
            name = "Year";
6525
7441
            break;
6526
7442
 
6529
7445
            break;
6530
7446
 
6531
7447
          case iFromTo:
 
7448
          case iFromToNotNews:
6532
7449
          case iFrom:
6533
7450
            name = "From";
6534
7451
            break;
6562
7479
            name = "Attachments";
6563
7480
            break;
6564
7481
 
 
7482
          case iAddress :
 
7483
            name = "Address";
 
7484
            break;
 
7485
 
 
7486
          case iMailbox :
 
7487
            name = "Mailbox";
 
7488
            break;
 
7489
 
6565
7490
          case iSubject :
6566
7491
          case iSubjKey :
6567
7492
          case iSubjKeyInit :
6726
7651
            }
6727
7652
 
6728
7653
        }
6729
 
        else if(objc == 4){
6730
 
            if(!strucmp(cmd,"flag")){
6731
 
                if((op = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){
6732
 
                    if(!strucmp(op,"deleted")){
6733
 
                    }
6734
 
                }
6735
 
            }
6736
 
        }
6737
7654
        else if(objc == 5){
6738
7655
            if(!strucmp(cmd,"flag")){
6739
7656
                if((op = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){
6809
7726
    {"text",            1,  {{3, peMessageText}}},
6810
7727
    {"header",          1,  {{3, peMessageHeader}}},
6811
7728
    {"attachments",     1,  {{3, peMessageAttachments}}},
6812
 
    {"body",            3,  {{3, peMessageBody}, {4, peMessageBody}, {5, peMessageBody}}},
 
7729
    {"body",            3,  {{3, peMessageBody}, {4, peMessageBody}}},
6813
7730
    {"cid",             1,  {{4, peMessagePartFromCID}}},
6814
7731
    {"flag",            2,  {{4, peGetFlag}, {5, peSetFlag}}},
6815
7732
    {"replyheaders",    2,  {{3, peReplyHeaders},{4, peReplyHeaders}}},
6822
7739
    {"attachinfo",      1,  {{4, peAttachInfo}}},
6823
7740
    {"savedefault",     1,  {{3, peSaveDefault}}},
6824
7741
    {"save",            1,  {{5, peSave}}},
 
7742
    {"copy",            1,  {{5, peCopy}}},
 
7743
    {"move",            1,  {{5, peMove}}},
6825
7744
    {"takeaddr",        1,  {{3, peTakeaddr}}},
 
7745
    {"takefrom",        1,  {{3, peTakeFrom}}},
6826
7746
    {"replyquote",      1,  {{3, peReplyQuote}}},
6827
7747
    {"bounce",          2,  {{4, peMessageBounce},{5, peMessageBounce}}},
6828
 
    {"spam",            2,  {{4, peMessageSpam}, {5, peMessageSpam}}},
6829
 
    {"trash",           2,  {{4, peMessageTrash}, {5, peMessageTrash}}},
 
7748
    {"spam",            1,  {{5, peMessageSpamNotice}}},
 
7749
    {"needpasswd",      1,  {{3, peMessageNeedPassphrase}}},
6830
7750
    {NULL, 0}
6831
7751
};
6832
7752
 
6885
7805
}
6886
7806
 
6887
7807
 
 
7808
/*
 
7809
 * return the uid's ordinal number within the CURRENT SORT
 
7810
 */
6888
7811
long
6889
7812
peMessageNumber(imapuid_t uid)
6890
7813
{
6891
 
    return(mn_raw2m(ps_global->msgmap, peSequenceNumber(uid)));
 
7814
    return(mn_raw2m(sp_msgmap(ps_global->mail_stream), peSequenceNumber(uid)));
6892
7815
}
6893
7816
 
6894
 
 
 
7817
/*
 
7818
 * return the uid's RAW message number (for c-client reference, primarily)
 
7819
 */
6895
7820
long
6896
7821
peSequenceNumber(imapuid_t uid)
6897
7822
{
7087
8012
 
7088
8013
 
7089
8014
int
 
8015
peMessageNeedPassphrase(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
 
8016
{
 
8017
#ifdef SMIME
 
8018
    return((ps_global && ps_global->smime && ps_global->smime->need_passphrase) ? TCL_OK : TCL_ERROR);
 
8019
#else
 
8020
    return(TCL_ERROR);
 
8021
#endif /* SMIME */
 
8022
}
 
8023
 
 
8024
 
 
8025
int
7090
8026
peMsgnoFromUID(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
7091
8027
{
7092
8028
    Tcl_SetResult(interp, long2string(peMessageNumber(uid)), TCL_VOLATILE);
7437
8373
    HEADER_S      h;
7438
8374
    int           flags, rv = TCL_OK;
7439
8375
    long          raw;
 
8376
#if     0
7440
8377
    char         *color;
 
8378
#endif
7441
8379
 
7442
8380
    /*
7443
8381
     * ONLY full header mode (raw) output should get written to the 
7489
8427
                     ps_global->last_error[0] ? ps_global->last_error : "Indeterminate");
7490
8428
 
7491
8429
            dprint((1, "ERROR fetching %s of msg %ld: %s",
7492
 
                    peED.env ? "elt" : "env", mn_get_cur(ps_global->msgmap),
 
8430
                    peED.env ? "elt" : "env", mn_get_cur(sp_msgmap(ps_global->mail_stream)),
7493
8431
                    ps_global->last_error[0] ? ps_global->last_error : "Indeterminate"));
7494
8432
 
7495
8433
            Tcl_SetResult(interp, buf, TCL_VOLATILE);
7497
8435
        }
7498
8436
        else{
7499
8437
            zero_atmts(ps_global->atmts);
 
8438
#ifdef SMIME
 
8439
            if(ps_global && ps_global->smime && ps_global->smime->need_passphrase)
 
8440
              ps_global->smime->need_passphrase = 0;
 
8441
 
 
8442
            fiddle_smime_message(peED.body, raw);
 
8443
#endif
7500
8444
            describe_mime(peED.body, "", 1, 1, 0, flags);
7501
8445
        }
7502
8446
    }
7833
8777
                     ps_global->last_error[0] ? ps_global->last_error : "Indeterminate");
7834
8778
 
7835
8779
            dprint((1, "ERROR fetching %s of msg %ld: %s",
7836
 
                    peED.env ? "elt" : "env", mn_get_cur(ps_global->msgmap),
 
8780
                    peED.env ? "elt" : "env", mn_get_cur(sp_msgmap(ps_global->mail_stream)),
7837
8781
                    ps_global->last_error[0] ? ps_global->last_error : "Indeterminate"));
7838
8782
 
7839
8783
            Tcl_SetResult(interp, buf, TCL_VOLATILE);
7841
8785
        }
7842
8786
        else{
7843
8787
            zero_atmts(ps_global->atmts);
 
8788
#ifdef SMIME
 
8789
            if(ps_global && ps_global->smime && ps_global->smime->need_passphrase)
 
8790
              ps_global->smime->need_passphrase = 0;
 
8791
 
 
8792
            fiddle_smime_message(peED.body, raw);
 
8793
#endif
7844
8794
            describe_mime(peED.body, "", 1, 1, 0, flags);
7845
8795
        }
7846
8796
    }
7873
8823
    MESSAGECACHE *mc;
7874
8824
    int           flags, rv = TCL_OK;
7875
8825
    long          raw;
7876
 
    char         *color, *fmt, *imgs;
 
8826
    char         *color;
7877
8827
 
7878
8828
    peED.interp = interp;
7879
8829
    peED.obj    = Tcl_GetObjResult(interp);
7885
8835
 
7886
8836
    flags = FM_DISPLAY | FM_NEW_MESS | FM_NOEDITORIAL | FM_NOHTMLREL | FM_HTMLRELATED;
7887
8837
 
7888
 
    if(objc >= 1 && objv[0]
7889
 
       && (fmt = Tcl_GetStringFromObj(objv[0], NULL)) != NULL
7890
 
       && !strucmp(fmt, "html")){
7891
 
        flags |= (FM_HTML | FM_HIDESERVER);
7892
 
    }
7893
 
 
7894
 
    if(objc == 2 && (flags & FM_HTML) != 0 && objv[1]
7895
 
       && (imgs = Tcl_GetStringFromObj(objv[1], NULL)) != NULL
7896
 
       && !strucmp(imgs, "images")){
7897
 
        flags |= (FM_HTMLIMAGES);
 
8838
    if(objc == 1 && objv[0]){                   /* flags */
 
8839
        int       i, nFlags;
 
8840
        Tcl_Obj **objFlags;
 
8841
        char     *flagstr;
 
8842
 
 
8843
        Tcl_ListObjGetElements(interp, objv[0], &nFlags, &objFlags);
 
8844
        for(i = 0; i < nFlags; i++){
 
8845
            if((flagstr = Tcl_GetStringFromObj(objFlags[i], NULL)) == NULL){
 
8846
                rv = TCL_ERROR;
 
8847
            }
 
8848
 
 
8849
            if(!strucmp(flagstr, "html"))
 
8850
              flags |= (FM_HTML | FM_HIDESERVER);
 
8851
            else if(!strucmp(flagstr, "images"))
 
8852
              flags |= (FM_HTMLIMAGES);
 
8853
        }
7898
8854
    }
7899
8855
 
7900
8856
    peED.color.fg[0] = '\0';
7932
8888
                     ps_global->last_error[0] ? ps_global->last_error : "Indeterminate");
7933
8889
 
7934
8890
            dprint((1, "ERROR fetching %s of msg %ld: %s",
7935
 
                    peED.env ? "elt" : "env", mn_get_cur(ps_global->msgmap),
 
8891
                    peED.env ? "elt" : "env", mn_get_cur(sp_msgmap(ps_global->mail_stream)),
7936
8892
                    ps_global->last_error[0] ? ps_global->last_error : "Indeterminate"));
7937
8893
 
7938
8894
            Tcl_SetResult(interp, buf, TCL_VOLATILE);
7940
8896
        }
7941
8897
        else{
7942
8898
            zero_atmts(ps_global->atmts);
 
8899
#ifdef SMIME
 
8900
            if(ps_global && ps_global->smime && ps_global->smime->need_passphrase)
 
8901
              ps_global->smime->need_passphrase = 0;
 
8902
 
 
8903
            fiddle_smime_message(peED.body, raw);
 
8904
#endif
7943
8905
            describe_mime(peED.body, "", 1, 1, 0, flags);
7944
8906
        }
7945
8907
    }
7950
8912
        char     *errstr;
7951
8913
 
7952
8914
        HD_INIT(&h, ps_global->VAR_VIEW_HEADERS, ps_global->view_all_except, FE_DEFAULT);
 
8915
#ifdef SMIME
 
8916
        /* kind of a hack, the description maybe shouldn't be in the editorial stuff */
 
8917
        if(ps_global->smime && ps_global->smime->need_passphrase)
 
8918
          flags &= ~FM_NOEDITORIAL;
 
8919
#endif
7953
8920
        if((errstr = format_body(raw, peED.body, &peED.handles, &h, flags, FAKE_SCREEN_WIDTH, peInterpWritec)) != NULL){
7954
8921
            gf_puts(errstr, peInterpWritec);
7955
8922
            rv = TCL_ERROR;
8006
8973
                ps_global->last_error[0] ? ps_global->last_error : "Indeterminate");
8007
8974
 
8008
8975
        dprint((1, "ERROR fetching %s of msg %ld: %s",
8009
 
                   env ? "elt" : "env", mn_get_cur(ps_global->msgmap),
 
8976
                   env ? "elt" : "env", mn_get_cur(sp_msgmap(ps_global->mail_stream)),
8010
8977
                   ps_global->last_error[0] ? ps_global->last_error : "Indeterminate"));
8011
8978
 
8012
8979
        Tcl_SetResult(interp, buf, TCL_VOLATILE);
8178
9145
                      ulong2string(uid),
8179
9146
                      flagstr, (value ? ST_SET : 0L) | ST_UID);
8180
9147
            if(ps_global->c_client_error[0] != '\0'){
8181
 
                snprintf(tmp_20k_buf, SIZEOF_20KBUF, "peFlag: %.40s",
 
9148
                snprintf(tmp_20k_buf, SIZEOF_20KBUF, "peSetFlag: %.40s",
8182
9149
                         ps_global->c_client_error);
8183
9150
                Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE);
8184
9151
                return(TCL_ERROR);
8204
9171
    if(objc == 1 && objv[0]){
8205
9172
        if(Tcl_GetIntFromObj(interp, objv[0], &value) != TCL_ERROR){
8206
9173
            if(value){
8207
 
                set_lflag(ps_global->mail_stream, ps_global->msgmap,
 
9174
                set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream),
8208
9175
                          peMessageNumber(uid), MN_SLCT, 1);
8209
 
                set_lflag(ps_global->mail_stream, ps_global->msgmap,
 
9176
                set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream),
8210
9177
                          peMessageNumber(uid), MN_HIDE, 0);
8211
9178
            } else {
8212
 
                set_lflag(ps_global->mail_stream, ps_global->msgmap,
 
9179
                set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream),
8213
9180
                          peMessageNumber(uid), MN_SLCT, 0);
8214
9181
                /* if zoomed, lite hidden bit */
8215
 
                if(any_lflagged(ps_global->msgmap, MN_HIDE))
8216
 
                  set_lflag(ps_global->mail_stream, ps_global->msgmap,
 
9182
                if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE))
 
9183
                  set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream),
8217
9184
                            peMessageNumber(uid), MN_HIDE, 1);
8218
9185
            
8219
9186
            }
8250
9217
 
8251
9218
 
8252
9219
    if((h = build_header_work(ps_global, ps_global->mail_stream,
8253
 
                              ps_global->msgmap, peMessageNumber(uid),
 
9220
                              sp_msgmap(ps_global->mail_stream), peMessageNumber(uid),
8254
9221
                              peITop, peICount, fetched)) != NULL){
8255
9222
        for(f = h->ifield; f; f = f->next){
8256
9223
 
8273
9240
                    /* and other stuff to pack trunc'd element into a new object */
8274
9241
#endif
8275
9242
 
8276
 
                    objp = peNewUtf8Obj(ie->data, ie->datalen);
 
9243
                    objp = Tcl_NewStringObj(ie->data, ie->datalen);
8277
9244
                }
8278
9245
                else
8279
9246
                  objp = Tcl_NewStringObj("", -1);
8353
9320
    ICE_S       *h;
8354
9321
 
8355
9322
    if((h = build_header_work(ps_global, ps_global->mail_stream,
8356
 
                              ps_global->msgmap, peMessageNumber(uid),
 
9323
                              sp_msgmap(ps_global->mail_stream), peMessageNumber(uid),
8357
9324
                              peITop, peICount, fetched))
8358
9325
       && h->color_lookup_done
8359
9326
       && h->linecolor){
8385
9352
{
8386
9353
    Tcl_SetResult(interp,
8387
9354
                  peMsgStatBitString(ps_global, ps_global->mail_stream,
8388
 
                                     ps_global->msgmap, peMessageNumber(uid),
 
9355
                                     sp_msgmap(ps_global->mail_stream), peMessageNumber(uid),
8389
9356
                                     peITop, peICount, NULL),
8390
9357
                  TCL_STATIC);
8391
9358
    return(TCL_OK);
8487
9454
        if(user_flag_is_set(stream, raw, FORWARDED_FLAG))
8488
9455
          Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("forwarded", -1));
8489
9456
 
8490
 
        if(get_lflag(ps_global->mail_stream, ps_global->msgmap, msgno, MN_SLCT))
 
9457
        if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), msgno, MN_SLCT))
8491
9458
          Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("selected", -1));
8492
9459
    }
8493
9460
 
8707
9674
        while(*ep && *ep != '\n')
8708
9675
          ep++;
8709
9676
 
8710
 
        objp = peNewUtf8Obj(sp, ep - sp);
 
9677
        objp = Tcl_NewStringObj(sp, ep - sp);
8711
9678
 
8712
9679
        if(Tcl_ListObjAppendElement(interp, obj, objp) != TCL_OK)
8713
9680
          return(FALSE);
8872
9839
            while(*p && *p != '\n')
8873
9840
              p++;
8874
9841
 
8875
 
            objp = peNewUtf8Obj(bodtext, p - bodtext);
 
9842
            objp = Tcl_NewStringObj(bodtext, p - bodtext);
8876
9843
 
8877
9844
            Tcl_ListObjAppendElement(interp, objBody, objp);
8878
9845
        }
8957
9924
        if(tfn)
8958
9925
          unlink(tfn);
8959
9926
 
8960
 
        snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Detach: %s", err);
 
9927
        dprint((1, "PEDetach FAIL: %d: %s", errno, err));
 
9928
        snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Detach (%d): %s", errno, err);
8961
9929
        Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE);
8962
9930
        return(TCL_ERROR);
8963
9931
    }
9109
10077
 
9110
10078
 
9111
10079
/*
9112
 
 * peSave - Save message with given UID in current folder to
9113
 
 *          specified collection/folder
 
10080
 * peSaveWork - Save message with given UID in current folder to
 
10081
 *              specified collection/folder
9114
10082
 *
9115
10083
 * Params: argv[0] == destination context number
9116
10084
 *         argv[1] == testination foldername
9118
10086
 *
9119
10087
 */
9120
10088
int
9121
 
peSave(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
 
10089
peSaveWork(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv, long sflags)
9122
10090
{
9123
 
    int        flgs, i, colid;
 
10091
    int        flgs = 0, i, colid;
9124
10092
    char      *folder, *err = NULL;
9125
10093
    CONTEXT_S *cp;
9126
10094
 
9127
10095
    if(Tcl_GetIntFromObj(interp, objv[0], &colid) != TCL_ERROR){
9128
10096
        if((folder = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){
9129
 
            mn_set_cur(ps_global->msgmap, peMessageNumber(uid));
 
10097
            mn_set_cur(sp_msgmap(ps_global->mail_stream), peMessageNumber(uid));
9130
10098
            for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next)
9131
 
              if(i == colid){
9132
 
                  if(!READONLY_FOLDER(ps_global->mail_stream)
9133
 
                     && F_OFF(F_SAVE_WONT_DELETE, ps_global))
9134
 
                    flgs |= SV_DELETE;
9135
 
 
9136
 
                  i = save(ps_global, ps_global->mail_stream,
9137
 
                           cp, folder, ps_global->msgmap, flgs);
9138
 
 
9139
 
                  if(i == mn_total_cur(ps_global->msgmap)){
9140
 
                      if(mn_total_cur(ps_global->msgmap) <= 1L){
9141
 
                          if(ps_global->context_list->next
9142
 
                             && context_isambig(folder)){
9143
 
                              char *tag = (cp->nickname && strlen(cp->nickname)) ? cp->nickname : (cp->label && strlen(cp->label)) ? cp->label : "Folders";
9144
 
                              snprintf(tmp_20k_buf, SIZEOF_20KBUF, 
9145
 
                                      "Message %s copied to \"%.15s%s\" in <%.15s%s>",
9146
 
                                      long2string(mn_get_cur(ps_global->msgmap)), folder,
9147
 
                                      (strlen(folder) > 15) ? "..." : "",
9148
 
                                      tag,
9149
 
                                      (strlen(tag) > 15) ? "..." : "");
9150
 
                          }
9151
 
                          else
9152
 
                            snprintf(tmp_20k_buf, SIZEOF_20KBUF,
9153
 
                                    "Message %s copied to folder \"%.27s%s\"",
9154
 
                                    long2string(mn_get_cur(ps_global->msgmap)), folder,
9155
 
                                    (strlen(folder) > 27) ? "..." : "");
9156
 
                      }
9157
 
                      else
9158
 
                        snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s messages saved",
9159
 
                                comatose(mn_total_cur(ps_global->msgmap)));
9160
 
 
9161
 
                      if(flgs & SV_DELETE){
9162
 
                          strncat(tmp_20k_buf, " and deleted", SIZEOF_20KBUF-strlen(tmp_20k_buf)-1);
9163
 
                          tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
9164
 
                      }
9165
 
 
9166
 
                      q_status_message(SM_ORDER, 0, 3, tmp_20k_buf);
9167
 
                      return(TCL_OK);
9168
 
                  }
9169
 
 
9170
 
                  err = ps_global->last_error;
9171
 
              }
9172
 
 
9173
 
            if(!err)
 
10099
              if(i == colid)
 
10100
                break;
 
10101
 
 
10102
            if(cp){
 
10103
                if(!READONLY_FOLDER(ps_global->mail_stream)
 
10104
                   && (sflags & PSW_COPY) != PSW_COPY
 
10105
                   && ((sflags & PSW_MOVE) == PSW_MOVE || F_OFF(F_SAVE_WONT_DELETE, ps_global)))
 
10106
                  flgs |= SV_DELETE;
 
10107
 
 
10108
                if(colid == 0 && !strucmp(folder, "inbox"))
 
10109
                  flgs |= SV_INBOXWOCNTXT;
 
10110
 
 
10111
                if(sflags & (PSW_COPY | PSW_MOVE))
 
10112
                  flgs |= SV_FIX_DELS;
 
10113
 
 
10114
                i = save(ps_global, ps_global->mail_stream,
 
10115
                         cp, folder, sp_msgmap(ps_global->mail_stream), flgs);
 
10116
 
 
10117
                if(i == mn_total_cur(sp_msgmap(ps_global->mail_stream))){
 
10118
                    if(mn_total_cur(sp_msgmap(ps_global->mail_stream)) <= 1L){
 
10119
                        if(ps_global->context_list->next
 
10120
                           && context_isambig(folder)){
 
10121
                            char *tag = (cp->nickname && strlen(cp->nickname)) ? cp->nickname : (cp->label && strlen(cp->label)) ? cp->label : "Folders";
 
10122
                            snprintf(tmp_20k_buf, SIZEOF_20KBUF, 
 
10123
                                     "Message %s %s to \"%.15s%s\" in <%.15s%s>",
 
10124
                                     long2string(mn_get_cur(sp_msgmap(ps_global->mail_stream))),
 
10125
                                     (sflags & PSW_MOVE) ? "moved" : "copied",
 
10126
                                     folder,
 
10127
                                     (strlen(folder) > 15) ? "..." : "",
 
10128
                                     tag,
 
10129
                                     (strlen(tag) > 15) ? "..." : "");
 
10130
                        }
 
10131
                        else
 
10132
                          snprintf(tmp_20k_buf, SIZEOF_20KBUF,
 
10133
                                   "Message %s %s to folder \"%.27s%s\"",
 
10134
                                   long2string(mn_get_cur(sp_msgmap(ps_global->mail_stream))),
 
10135
                                   (sflags & PSW_MOVE) ? "moved" : "copied",
 
10136
                                   folder,
 
10137
                                   (strlen(folder) > 27) ? "..." : "");
 
10138
                    }
 
10139
                    else{
 
10140
                        /* with mn_set_cur above, this *should not* happen */
 
10141
                        Tcl_SetResult(interp, "TOO MANY MESSAGES COPIED", TCL_VOLATILE);
 
10142
                        return(TCL_ERROR);
 
10143
                    }
 
10144
 
 
10145
                    if(sflags == PSW_NONE && (flgs & SV_DELETE)){
 
10146
                        strncat(tmp_20k_buf, " and deleted", SIZEOF_20KBUF-strlen(tmp_20k_buf)-1);
 
10147
                        tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
 
10148
                    }
 
10149
 
 
10150
                    q_status_message(SM_ORDER, 0, 3, tmp_20k_buf);
 
10151
                    return(TCL_OK);
 
10152
                }
 
10153
 
 
10154
                err = ps_global->last_error;
 
10155
            }
 
10156
            else
9174
10157
              err = "open: Unrecognized collection ID";
9175
10158
        }
9176
10159
        else
9183
10166
    return(TCL_ERROR);
9184
10167
}
9185
10168
 
 
10169
/*
 
10170
 * peSave - Save message with given UID in current folder to
 
10171
 *          specified collection/folder
 
10172
 *
 
10173
 * Params: argv[0] == destination context number
 
10174
 *         argv[1] == testination foldername
 
10175
 *
 
10176
 * NOTE: just a wrapper around peSaveWork
 
10177
 */
 
10178
int
 
10179
peSave(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
 
10180
{
 
10181
    return(peSaveWork(interp, uid, objc, objv, PSW_NONE));
 
10182
}
 
10183
 
 
10184
 
 
10185
/*
 
10186
 * peCopy - Copy message with given UID in current folder to
 
10187
 *          specified collection/folder
 
10188
 *
 
10189
 * Params: argv[0] == destination context number
 
10190
 *         argv[1] == testination foldername
 
10191
 *
 
10192
 * NOTE: just a wrapper around peSaveWork that makes sure
 
10193
 *       delete-on-save is NOT set
 
10194
 */
 
10195
int
 
10196
peCopy(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
 
10197
{
 
10198
    return(peSaveWork(interp, uid, objc, objv, PSW_COPY));
 
10199
}
 
10200
 
 
10201
 
 
10202
/*
 
10203
 * peMove - Move message with given UID in current folder to
 
10204
 *          specified collection/folder
 
10205
 *
 
10206
 * Params: argv[0] == destination context number
 
10207
 *         argv[1] == testination foldername
 
10208
 *
 
10209
 * NOTE: just a wrapper around peSaveWork that makes sure
 
10210
 *       delete-on-save IS set so it can be expunged
 
10211
 */
 
10212
int
 
10213
peMove(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
 
10214
{
 
10215
    return(peSaveWork(interp, uid, objc, objv, PSW_MOVE));
 
10216
}
 
10217
 
9186
10218
 
9187
10219
/*
9188
10220
 * peGotoDefault - Default Goto command file name for the given message
9251
10283
void
9252
10284
peGetMimeTyping(BODY *body, Tcl_Obj **tObjp, Tcl_Obj **stObjp, Tcl_Obj **fnObjp, Tcl_Obj **extObjp)
9253
10285
{
9254
 
    char *p, *ptype = NULL, *psubtype = NULL, *pfile = NULL, *att_name;
 
10286
    char *ptype = NULL, *psubtype = NULL, *pfile = NULL;
9255
10287
 
9256
10288
    /*-------  Figure out suggested file name ----*/
9257
 
    att_name = "filename";
9258
 
 
9259
10289
    if(body){
9260
 
        if((body->disposition.type
9261
 
            && (p = rfc2231_get_param(body->disposition.parameter,
9262
 
                                      att_name, NULL, NULL)))
9263
 
           || (p = rfc2231_get_param(body->parameter,
9264
 
                                     att_name + 4, NULL, NULL))){
9265
 
            pfile = p;
9266
 
 
 
10290
        if((pfile = get_filename_parameter(NULL, 0, body, NULL)) != NULL){
9267
10291
            /*
9268
10292
             * if part is generic, see if we can get anything
9269
10293
             * more from the suggested filename's extension...
9410
10434
 
9411
10435
                case 's' :      /* string value */
9412
10436
                  sval = va_arg(args, char *);
9413
 
                  sObj = peNewUtf8Obj(sval ? sval : "", -1);
 
10437
                  sObj = Tcl_NewStringObj(sval ? sval : "", -1);
9414
10438
                  if(sObj == NULL)
9415
10439
                    err++;
9416
10440
 
9434
10458
                      rfc822_output_address_list(&rbuf, aval, 0L, NULL);
9435
10459
                      *rbuf.cur = '\0';
9436
10460
                      p    = (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, SIZEOF_20KBUF, tmp);
9437
 
                      sObj = peNewUtf8Obj(p, strlen(p));
 
10461
                      sObj = Tcl_NewStringObj(p, strlen(p));
9438
10462
                      fs_give((void **) &tmp);
9439
10463
                  }
9440
10464
                  else
9445
10469
                case 'p':       /* PATTERN_S * */
9446
10470
                  pval = va_arg(args, PATTERN_S *);
9447
10471
                  sval = pattern_to_string(pval);
9448
 
                  sObj = peNewUtf8Obj(sval ? sval : "", -1);
 
10472
                  sObj = Tcl_NewStringObj(sval ? sval : "", -1);
9449
10473
                  break;
9450
10474
 
9451
10475
                case 'v':       /* INTVL_S * */
9475
10499
    return(lObj ? Tcl_ListObjAppendElement(interp, lobjp, lObj) : TCL_ERROR);
9476
10500
}
9477
10501
 
9478
 
 
9479
 
Tcl_Obj *
9480
 
peNewUtf8Obj(void *sval, int l)
9481
 
{
9482
 
#if     (TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION > 0)
9483
 
    /*
9484
 
     * Tcl versions > 8.0 are internal Unicode, and have routines
9485
 
     * to map in and out of UTF-8, but since text in and out of here is
9486
 
     * exclusively UTF-8, we'll just deal with byte arrays
9487
 
     */
9488
 
    if(l < 0)
9489
 
      l = (sval) ? strlen(sval) : 0;
9490
 
 
9491
 
    return(Tcl_NewByteArrayObj((unsigned char *) (sval ? sval : ""), l));
9492
 
#else
9493
 
    return(Tcl_NewStringObj((char *) sval, l));
9494
 
#endif
9495
 
}
9496
 
 
9497
 
 
9498
 
unsigned char *
9499
 
peGetUtf8FromObj(Tcl_Obj *sObj, int *sl)
9500
 
{
9501
 
#if     (TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION > 0)
9502
 
    return(Tcl_GetByteArrayFromObj(sObj, sl));
9503
 
#else
9504
 
    return((unsigned char *) Tcl_GetStringFromObj(sObj, sl));
9505
 
#endif
9506
 
}
9507
 
 
9508
10502
/*
9509
10503
 * pePatAppendID - append list of pattern identity variables to given object
9510
10504
 */
9694
10688
 
9695
10689
    pico_endcolor();
9696
10690
 
 
10691
    free_strlist(&peCertHosts);
 
10692
 
9697
10693
    free_pine_struct(pps);
9698
10694
}
9699
10695
 
9702
10698
peLoadConfig(struct pine *pine_state)
9703
10699
{
9704
10700
    int   rv;
9705
 
    char *db = NULL;
 
10701
    char *s, *db = NULL;
9706
10702
    extern void init_signals(void);     /* in signal.c */
9707
10703
 
9708
10704
    if(!pine_state)
9730
10726
    ps_global->s_pool.max_remstream  = 2;
9731
10727
 
9732
10728
    ps_global->c_client_error[0] = '\0';
9733
 
    peCredentialError = 0;
 
10729
 
 
10730
    pePrepareForAuthException();
9734
10731
 
9735
10732
    init_vars(pine_state, NULL);
9736
10733
 
9737
 
    if(peCredentialError)
9738
 
      return("Invalid Login Name or Password");
 
10734
    if(s = peAuthException())
 
10735
      return(s);
9739
10736
    else if(ps_global->c_client_error[0])
9740
10737
      return(ps_global->c_client_error);
9741
10738
 
9859
10856
peCreateStream(Tcl_Interp *interp, CONTEXT_S *context, char *mailbox, int do_inbox)
9860
10857
{
9861
10858
    unsigned long  flgs = 0L;
 
10859
    char          *s;
9862
10860
 
9863
10861
    ps_global->c_client_error[0] = ps_global->last_error[0] = '\0';
9864
 
    peCredentialError = peNoPassword = 0;
 
10862
 
 
10863
    pePrepareForAuthException();
9865
10864
 
9866
10865
    if(do_inbox)
9867
10866
      flgs |= DB_INBOXWOCNTXT;
9873
10872
    }
9874
10873
 
9875
10874
    Tcl_SetResult(interp,
9876
 
                  (peNoPassword || peCredentialError)
9877
 
                    ? AUTH_FAILURE_STRING
 
10875
                  (s = peAuthException())
 
10876
                    ? s
9878
10877
                    : (*ps_global->last_error)
9879
10878
                       ? ps_global->last_error
9880
10879
                       : "Login Error",
9912
10911
}
9913
10912
 
9914
10913
 
 
10914
/*
 
10915
 * pePrepareForAuthException - set globals to get feedback from bowels of c-client
 
10916
 */
 
10917
void
 
10918
pePrepareForAuthException(void)
 
10919
{
 
10920
    peNoPassword = peCredentialError = peCertFailure = peCertQuery = 0;
 
10921
}
 
10922
 
 
10923
/*
 
10924
 * pePrepareForAuthException - check globals getting feedback from bowels of c-client
 
10925
 */
 
10926
char *
 
10927
peAuthException()
 
10928
{
 
10929
    static char buf[CRED_REQ_SIZE];
 
10930
 
 
10931
    if(peCertQuery){
 
10932
        snprintf(buf, CRED_REQ_SIZE, "%s %s", CERT_QUERY_STRING, peCredentialRequestor);
 
10933
        return(buf);
 
10934
    }
 
10935
 
 
10936
    if(peCertFailure){
 
10937
        snprintf(buf, CRED_REQ_SIZE, "%s %s", CERT_FAILURE_STRING, peCredentialRequestor);
 
10938
        return(buf);
 
10939
    }
 
10940
 
 
10941
    if(peNoPassword){
 
10942
        snprintf(buf, CRED_REQ_SIZE, "%s %s", AUTH_EMPTY_STRING, peCredentialRequestor);
 
10943
        return(buf);
 
10944
    }
 
10945
 
 
10946
    if(peCredentialError){
 
10947
        snprintf(buf, CRED_REQ_SIZE, "%s %s", AUTH_FAILURE_STRING, peCredentialRequestor);
 
10948
        return(buf);
 
10949
    }
 
10950
 
 
10951
    return(NULL);
 
10952
}
 
10953
 
9915
10954
 
9916
10955
int
9917
10956
peMessageBounce(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9980
11019
 
9981
11020
 
9982
11021
int
9983
 
peMessageSpam(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9984
 
{
9985
 
    char        *errstr = NULL, *to, *subj = NULL, errbuf[WP_MAX_POST_ERROR + 1], *tmp_a_string;
9986
 
    long         rawno;
 
11022
peMessageSpamNotice(interp, uid, objc, objv)
 
11023
    Tcl_Interp  *interp;
 
11024
    imapuid_t    uid;
 
11025
    int          objc;
 
11026
    Tcl_Obj    **objv;
 
11027
{
 
11028
    char *to, *subj = NULL, errbuf[WP_MAX_POST_ERROR + 1], *rs = NULL;
 
11029
    long  rawno;
 
11030
 
 
11031
    if(uid){
 
11032
        rawno = peSequenceNumber(uid);
 
11033
 
 
11034
        if(objv[0] && (to = Tcl_GetStringFromObj(objv[0], NULL)) && strlen(to)){
 
11035
 
 
11036
            if(objv[1])
 
11037
              subj = Tcl_GetStringFromObj(objv[1], NULL);
 
11038
 
 
11039
            rs = peSendSpamReport(rawno, to, subj, errbuf);
 
11040
        }
 
11041
    }
 
11042
 
 
11043
    Tcl_SetResult(interp, (rs) ? rs : "OK", TCL_VOLATILE);
 
11044
    return(rs ? TCL_ERROR : TCL_OK);
 
11045
}
 
11046
 
 
11047
 
 
11048
char *
 
11049
peSendSpamReport(long rawno, char *to, char *subj, char *errbuf)
 
11050
{
 
11051
    char        *errstr = NULL, *tmp_a_string;
9987
11052
    ENVELOPE    *env, *outgoing;
9988
11053
    METAENV     *metaenv;
9989
11054
    PINEFIELD   *custom;
9991
11056
    static char *fakedomain = "@";
9992
11057
    void        *msgtext;
9993
11058
 
9994
 
    if(uid){
9995
 
        rawno = peSequenceNumber(uid);
9996
 
 
9997
 
        if(objc > 0 && objv[0] && (to = Tcl_GetStringFromObj(objv[0], NULL)) && strlen(to)){
9998
 
            if((env = mail_fetchstructure(ps_global->mail_stream, rawno, NULL)) == NULL){
9999
 
                Tcl_SetResult(interp, ps_global->last_error, TCL_VOLATILE);
10000
 
                return(TCL_ERROR);
10001
 
            }
10002
 
 
10003
 
            /* empty subject gets "spam" subject */
10004
 
            if(!(objc == 2 && objv[1]
10005
 
                 && (subj = Tcl_GetStringFromObj(objv[1], NULL)) != NULL
10006
 
                 && *subj))
10007
 
              subj = env->subject;
10008
 
 
10009
 
            /*---- New Body to start with ----*/
10010
 
            body       = mail_newbody();
10011
 
            body->type = TYPEMULTIPART;
10012
 
 
10013
 
            /*---- The TEXT part/body ----*/
10014
 
            body->nested.part            = mail_newbody_part();
10015
 
            body->nested.part->body.type = TYPETEXT;
10016
 
 
10017
 
            if((msgtext = (void *)so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){
10018
 
                pine_free_body(&body);
10019
 
                Tcl_SetResult(interp, "peMessageSpam: Can't allocate text", TCL_VOLATILE);
10020
 
                return(TCL_ERROR);
10021
 
            }
10022
 
            else{
10023
 
                sprintf(tmp_20k_buf,
10024
 
                        "The attached message is being reported to <%s> as Spam\n",
10025
 
                        to);
10026
 
                so_puts((STORE_S *) msgtext, tmp_20k_buf);
10027
 
                body->nested.part->body.contents.text.data = msgtext;
10028
 
            }
10029
 
 
10030
 
            /*---- Attach the raw message ----*/
10031
 
            if(forward_mime_msg(ps_global->mail_stream, rawno, NULL, env,
10032
 
                                &(body->nested.part->next), msgtext)){
10033
 
                outgoing = mail_newenvelope();
10034
 
                metaenv = pine_new_env(outgoing, NULL, NULL, custom = peCustomHdrs());
10035
 
            }
10036
 
            else{
10037
 
                pine_free_body(&body);
10038
 
                Tcl_SetResult(interp, "peMessageSpam: Can't generate forwarded message", TCL_VOLATILE);
10039
 
                return(TCL_ERROR);
10040
 
            }
10041
 
 
10042
 
            /* rfc822_parse_adrlist feels free to destroy input so copy */
10043
 
            tmp_a_string = cpystr(to);
10044
 
            rfc822_parse_adrlist(&outgoing->to, tmp_a_string,
10045
 
                                 (F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global))
10046
 
                                   ? fakedomain : ps_global->maildomain);
10047
 
            fs_give((void **) &tmp_a_string);
10048
 
 
10049
 
            outgoing->from        = generate_from();
10050
 
            outgoing->subject     = cpystr(subj);
10051
 
            outgoing->return_path = rfc822_cpy_adr(outgoing->from);
10052
 
            outgoing->message_id  = generate_message_id();
10053
 
 
10054
 
            rfc822_date(tmp_20k_buf);
10055
 
            outgoing->date = (unsigned char *) cpystr(tmp_20k_buf);
10056
 
 
10057
 
            /* NO FCC for Spam Reporting  */
10058
 
 
10059
 
            if(peDoPost(metaenv, body, NULL, NULL, errbuf) != TCL_OK)
10060
 
              errstr = errbuf;
10061
 
 
10062
 
            pine_free_body(&body);
10063
 
 
10064
 
            pine_free_env(&metaenv);
10065
 
 
10066
 
            if(custom)
10067
 
              free_customs(custom);
10068
 
 
10069
 
            mail_free_envelope(&outgoing);
10070
 
            pine_free_body(&body);
10071
 
 
10072
 
        }
10073
 
    }
10074
 
 
10075
 
    Tcl_SetResult(interp, (errstr) ? errstr : "OK", TCL_VOLATILE);
10076
 
    return(errstr ? TCL_ERROR : TCL_OK);
10077
 
}
10078
 
 
10079
 
 
10080
 
int
10081
 
peMessageTrash(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
10082
 
{
10083
 
    Tcl_SetResult(interp, "OK", TCL_VOLATILE);
10084
 
    return(TCL_OK);
 
11059
 
 
11060
    if((env = mail_fetchstructure(ps_global->mail_stream, rawno, NULL)) == NULL){
 
11061
        return(ps_global->last_error);
 
11062
    }
 
11063
 
 
11064
    /* empty subject gets "spam" subject */
 
11065
    if(!(subj && *subj))
 
11066
      subj = env->subject;
 
11067
 
 
11068
    /*---- New Body to start with ----*/
 
11069
    body       = mail_newbody();
 
11070
    body->type = TYPEMULTIPART;
 
11071
 
 
11072
    /*---- The TEXT part/body ----*/
 
11073
    body->nested.part            = mail_newbody_part();
 
11074
    body->nested.part->body.type = TYPETEXT;
 
11075
 
 
11076
    if((msgtext = (void *)so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){
 
11077
        pine_free_body(&body);
 
11078
        return("peSendSpamReport: Can't allocate text");
 
11079
    }
 
11080
    else{
 
11081
        sprintf(tmp_20k_buf,
 
11082
                "The attached message is being reported to <%s> as Spam\n",
 
11083
                to);
 
11084
        so_puts((STORE_S *) msgtext, tmp_20k_buf);
 
11085
        body->nested.part->body.contents.text.data = msgtext;
 
11086
    }
 
11087
 
 
11088
    /*---- Attach the raw message ----*/
 
11089
    if(forward_mime_msg(ps_global->mail_stream, rawno, NULL, env,
 
11090
                        &(body->nested.part->next), msgtext)){
 
11091
        outgoing = mail_newenvelope();
 
11092
        metaenv = pine_new_env(outgoing, NULL, NULL, custom = peCustomHdrs());
 
11093
    }
 
11094
    else{
 
11095
        pine_free_body(&body);
 
11096
        return("peSendSpamReport: Can't generate forwarded message");
 
11097
    }
 
11098
 
 
11099
    /* rfc822_parse_adrlist feels free to destroy input so copy */
 
11100
    tmp_a_string = cpystr(to);
 
11101
    rfc822_parse_adrlist(&outgoing->to, tmp_a_string,
 
11102
                         (F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global))
 
11103
                         ? fakedomain : ps_global->maildomain);
 
11104
    fs_give((void **) &tmp_a_string);
 
11105
 
 
11106
    outgoing->from        = generate_from();
 
11107
    outgoing->subject     = cpystr(subj);
 
11108
    outgoing->return_path = rfc822_cpy_adr(outgoing->from);
 
11109
    outgoing->message_id  = generate_message_id();
 
11110
 
 
11111
    rfc822_date(tmp_20k_buf);
 
11112
    outgoing->date = (unsigned char *) cpystr(tmp_20k_buf);
 
11113
 
 
11114
    /* NO FCC for Spam Reporting  */
 
11115
 
 
11116
    if(peDoPost(metaenv, body, NULL, NULL, errbuf) != TCL_OK)
 
11117
      errstr = errbuf;
 
11118
 
 
11119
    pine_free_body(&body);
 
11120
 
 
11121
    pine_free_env(&metaenv);
 
11122
 
 
11123
    if(custom)
 
11124
      free_customs(custom);
 
11125
 
 
11126
    mail_free_envelope(&outgoing);
 
11127
    pine_free_body(&body);
 
11128
 
 
11129
    return(errstr);
10085
11130
}
10086
11131
 
10087
11132
 
10110
11155
 
10111
11156
        if(s1){
10112
11157
            if(!strcmp(s1, "post")){
10113
 
                return(peMsgCollector(interp, objc - 2, (Tcl_Obj **) &objv[2], peDoPost));
 
11158
                long flags = PMC_NONE;
 
11159
                if(F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global))
 
11160
                  flags |= PMC_FORCE_QUAL;
 
11161
 
 
11162
                return(peMsgCollector(interp, objc - 2, (Tcl_Obj **) &objv[2], peDoPost, flags));
10114
11163
            }
10115
11164
            else if(objc == 2){
10116
11165
                if(!strcmp(s1, "userhdrs")){
10233
11282
                    Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE);
10234
11283
                    return(TCL_OK);
10235
11284
                }
 
11285
                else if(!strcmp(s1, "attachments")){
 
11286
                    COMPATT_S *p;
 
11287
                    Tcl_Obj *objAttach;
 
11288
 
 
11289
                    for(p = peCompAttach; p; p = p->next)
 
11290
                      if(p->file){
 
11291
                          objAttach = Tcl_NewListObj(0, NULL);
 
11292
 
 
11293
                          /* id */
 
11294
                          Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(p->id,-1));
 
11295
 
 
11296
                          /* file name */
 
11297
                          Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(p->l.f.remote,-1));
 
11298
 
 
11299
                          /* file size */
 
11300
                          Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewLongObj(p->l.f.size));
 
11301
 
 
11302
                          /* type/subtype */
 
11303
                          snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s/%s", p->l.f.type, p->l.f.subtype);
 
11304
                          Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(tmp_20k_buf,-1));
 
11305
 
 
11306
                          /* append to list */
 
11307
                          Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach);
 
11308
                      }
 
11309
                      else if(p->body){
 
11310
                          char *name;
 
11311
 
 
11312
                          objAttach = Tcl_NewListObj(0, NULL);
 
11313
 
 
11314
                          /* id */
 
11315
                          Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(p->id,-1));
 
11316
 
 
11317
                          /* file name */
 
11318
                          if((name = get_filename_parameter(NULL, 0, p->l.b.body, NULL)) != NULL){
 
11319
                              Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(name, -1));
 
11320
                              fs_give((void **) &name);
 
11321
                          }
 
11322
                          else
 
11323
                            Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj("Unknown", -1));
 
11324
 
 
11325
                          /* file size */
 
11326
                          Tcl_ListObjAppendElement(interp, objAttach,
 
11327
                                                   Tcl_NewLongObj((p->l.b.body->encoding == ENCBASE64)
 
11328
                                                                  ? ((p->l.b.body->size.bytes * 3)/4)
 
11329
                                                                  : p->l.b.body->size.bytes));
 
11330
 
 
11331
                          /* type/subtype */
 
11332
                          snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s/%s",
 
11333
                                   body_type_names(p->l.b.body->type),
 
11334
                                   p->l.b.body->subtype ? p->l.b.body->subtype : "Unknown");
 
11335
                          Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(tmp_20k_buf, -1));
 
11336
 
 
11337
                          Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach);
 
11338
                      }
 
11339
 
 
11340
                    return(TCL_OK);
 
11341
                }
10236
11342
            }
10237
11343
            else if(objc == 3){
10238
11344
                if(!strcmp(s1, "unattach")){
10276
11382
                                char *name;
10277
11383
 
10278
11384
                                /* file name */
10279
 
                                if((name = rfc2231_get_param(a->l.b.body->disposition.parameter, "filename", NULL, NULL))
10280
 
                                   || (name = rfc2231_get_param(a->l.b.body->parameter, "name", NULL, NULL))){
 
11385
                                if((name = get_filename_parameter(NULL, 0, a->l.b.body, NULL)) != NULL){
10281
11386
                                    Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(name, -1));
10282
11387
                                    fs_give((void **) &name);
10283
11388
                                }
10301
11406
                                if(a->l.b.body->description){
10302
11407
                                    snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%.*s", 256, a->l.b.body->description);
10303
11408
                                }
10304
 
                                else if((s = rfc2231_get_param(a->l.b.body->parameter, "description", NULL, NULL)) != NULL){
 
11409
                                else if((s = parameter_val(a->l.b.body->parameter, "description")) != NULL){
10305
11410
                                    snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%.*s", 256, s);
10306
11411
                                    fs_give((void **) &s);
10307
11412
                                }
10332
11437
                       && (remote = Tcl_GetStringFromObj(objv[5], NULL))){
10333
11438
                        int  dl;
10334
11439
 
10335
 
                        desc = (char *) peGetUtf8FromObj(objv[6], &dl);
 
11440
                        desc = Tcl_GetStringFromObj(objv[6], &dl);
10336
11441
 
10337
11442
                        if(desc){
10338
11443
                            Tcl_SetResult(interp, peFileAttachID(file, type, subtype, remote, desc, dl), TCL_VOLATILE);
10537
11642
int
10538
11643
peDoPost(METAENV *metaenv, BODY *body, char *fcc, CONTEXT_S **fcc_cntxtp, char *errp)
10539
11644
{
10540
 
    int        rv = TCL_OK, recipients;
 
11645
    int   rv = TCL_OK, recipients;
 
11646
    char *s;
10541
11647
 
10542
11648
    if(commence_fcc(fcc, fcc_cntxtp, TRUE)){
10543
11649
 
10544
11650
        ps_global->c_client_error[0] = ps_global->last_error[0] = '\0';
10545
 
        peCredentialError = peNoPassword = 0;
 
11651
        pePrepareForAuthException();
10546
11652
        
10547
11653
        if((recipients = (metaenv->env->to || metaenv->env->cc || metaenv->env->bcc))
10548
11654
           && call_mailer(metaenv, body, NULL, 0, NULL, NULL) < 0){
10549
 
            if(peNoPassword){
10550
 
                strcpy(errp, AUTH_EMPTY_STRING);
10551
 
            }
10552
 
            else if(peCredentialError){
10553
 
                strcpy(errp, AUTH_FAILURE_STRING);
 
11655
            if(s = peAuthException()){
 
11656
                strcpy(errp, s);
10554
11657
            }
10555
11658
            else if(ps_global->last_error[0]){
10556
11659
                sprintf(errp, "Send Error: %.*s", 64, ps_global->last_error);
10564
11667
            rv = TCL_ERROR;
10565
11668
            dprint((1, "call_mailer failed!"));
10566
11669
        }
10567
 
        else if(!wrapup_fcc(fcc, *fcc_cntxtp, recipients ? NULL : metaenv, body)){
 
11670
        else if(fcc && fcc_cntxtp && !wrapup_fcc(fcc, *fcc_cntxtp, recipients ? NULL : metaenv, body)){
10568
11671
            strcpy(errp, "Fcc Failed!.  No message saved.");
10569
11672
            rv = TCL_ERROR;
10570
11673
            dprint((1, "explicit fcc write failed!"));
10633
11736
        char *s1 = Tcl_GetStringFromObj(objv[1], NULL);
10634
11737
 
10635
11738
        if(s1){
10636
 
            if(objc == 2){
10637
 
                if(!strcmp(s1, "any")){
10638
 
                    MAILSTREAM *stream;
10639
 
 
10640
 
                    if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
10641
 
                        Tcl_SetResult(interp, "1", TCL_STATIC);
10642
 
 
10643
 
                        if(stream != ps_global->mail_stream)
10644
 
                          pine_mail_close(stream);
10645
 
                    }
10646
 
                    else
10647
 
                      Tcl_SetResult(interp, "0", TCL_STATIC);
10648
 
 
10649
 
                    return(TCL_OK);
10650
 
                }
10651
 
                else if(!strcmp(s1, "count")){
10652
 
                    MAILSTREAM *stream;
10653
 
 
10654
 
                    if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
10655
 
                        Tcl_SetResult(interp, Tcl_NewLongObj(stream->nmsgs), TCL_STATIC);
10656
 
 
10657
 
                        if(stream != ps_global->mail_stream)
10658
 
                          pine_mail_close(stream);
10659
 
                    }
10660
 
                    else
10661
 
                      Tcl_SetResult(interp, "-1", TCL_STATIC);
10662
 
 
10663
 
                    return(TCL_OK);
10664
 
                }
10665
 
                else if(!strcmp(s1, "list")){
10666
 
                    MAILSTREAM *stream;
10667
 
                    ENVELOPE   *env;
10668
 
                    Tcl_Obj    *objEnv = NULL, *objEnvList;
 
11739
            if(!strcmp(s1, "extract")){
 
11740
                if(Tcl_GetLongFromObj(interp, objv[2], &uid) == TCL_OK){
 
11741
                    Tcl_Obj    *objHdr = NULL, *objBod = NULL, *objAttach = NULL, *objOpts = NULL;
 
11742
                    MAILSTREAM *stream;
 
11743
                    BODY       *b;
 
11744
                    ENVELOPE   *env = NULL;
 
11745
                    PINEFIELD  *custom = NULL, *cp;
 
11746
                    REPLY_S    *reply = NULL;
 
11747
                    ACTION_S   *role = NULL;
 
11748
                    STORE_S    *so;
10669
11749
                    long        n;
10670
 
 
10671
 
                    if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
10672
 
                        if(!stream->nmsgs){
10673
 
                            (void) redraft_cleanup(&stream, FALSE, REDRAFT_PPND);
10674
 
                            Tcl_SetResult(interp, "", TCL_STATIC);
10675
 
                            return(TCL_OK);
10676
 
                        }
10677
 
 
10678
 
                        objEnvList = Tcl_NewListObj(0, NULL);
10679
 
 
10680
 
                        for(n = 1; n <= stream->nmsgs; n++){
10681
 
                            if((env = pine_mail_fetchstructure(stream, n, NULL)) != NULL){
10682
 
                                objEnv = Tcl_NewListObj(0, NULL);
10683
 
 
10684
 
                                peAppListF(interp, objEnv, "%s%s", "uid",
10685
 
                                           ulong2string(mail_uid(stream, n)));
10686
 
 
10687
 
                                peAppListF(interp, objEnv, "%s%a", "to", env->to);
10688
 
 
10689
 
                                date_str((char *)env->date, iSDate, 1, tmp_20k_buf, SIZEOF_20KBUF, 0);
10690
 
 
10691
 
                                peAppListF(interp, objEnv, "%s%s", "date", tmp_20k_buf);
10692
 
 
10693
 
                                peAppListF(interp, objEnv, "%s%s", "subj",
10694
 
                                           rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf,
10695
 
                                                                  SIZEOF_20KBUF, env->subject));
10696
 
 
10697
 
                                Tcl_ListObjAppendElement(interp, objEnvList, objEnv);
 
11750
                    int         rv = TCL_OK;
 
11751
                    char       *fcc = NULL, *lcc = NULL;
 
11752
                    unsigned    flags = REDRAFT_DEL | REDRAFT_PPND;
 
11753
 
 
11754
                    if(objc > 3){                       /* optional flags */
 
11755
                        int       i, nFlags;
 
11756
                        Tcl_Obj **objFlags;
 
11757
                        char     *flagstr;
 
11758
 
 
11759
                        Tcl_ListObjGetElements(interp, objv[3], &nFlags, &objFlags);
 
11760
                        for(i = 0; i < nFlags; i++){
 
11761
                            if((flagstr = Tcl_GetStringFromObj(objFlags[i], NULL)) == NULL){
 
11762
                                rv = TCL_ERROR;
10698
11763
                            }
 
11764
 
 
11765
                            if(!strucmp(flagstr, "html"))
 
11766
                              flags |= REDRAFT_HTML;
10699
11767
                        }
10700
 
 
10701
 
                        Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objEnvList);
10702
 
 
10703
 
                        Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10704
 
                                                 Tcl_NewStringObj("utf-8", -1));
10705
 
 
10706
 
                        if(stream != ps_global->mail_stream)
10707
 
                          pine_mail_close(stream);
10708
11768
                    }
10709
 
 
10710
 
                    return(TCL_OK);
10711
 
                }
10712
 
            }
10713
 
            else if(objc == 3){
10714
 
                if(!strcmp(s1, "extract")){
10715
 
                    if(Tcl_GetLongFromObj(interp, objv[2], &uid) == TCL_OK){
10716
 
                        Tcl_Obj      *objHdr = NULL, *objBod = NULL, *objAttach = NULL, *objOpts = NULL;
10717
 
                        MAILSTREAM    *stream;
10718
 
                        BODY          *b;
10719
 
                        ENVELOPE      *env = NULL;
10720
 
                        PINEFIELD     *custom = NULL, *cp;
10721
 
                        REPLY_S       *reply = NULL;
10722
 
                        ACTION_S      *role = NULL;
10723
 
                        STORE_S       *so;
10724
 
                        long           n;
10725
 
                        char          *fcc = NULL,
10726
 
                                      *lcc = NULL;
10727
 
 
10728
 
                        if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
10729
 
                            if((so = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
10730
 
                                if(((n = mail_msgno(stream, uid)) > 0L
10731
 
                                   && redraft_work(&stream, n, &env, &b, &fcc, &lcc, &reply,
10732
 
                                                   NULL, &custom, &role, /* should role be NULL? */
10733
 
                                                   REDRAFT_DEL | REDRAFT_PPND, so))){
 
11769
                    /* BUG: should probably complain if argc > 4 */
 
11770
 
 
11771
                    if(rv == TCL_OK
 
11772
                       && postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0)
 
11773
                       && stream){
 
11774
                        if((so = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
 
11775
                            if((n = mail_msgno(stream, uid)) > 0L){
 
11776
                                if(redraft_work(&stream, n, &env, &b, &fcc, &lcc, &reply,
 
11777
                                                NULL, &custom, &role, /* should role be NULL? */
 
11778
                                                flags, so)){
10734
11779
                                    char *charset = NULL;
10735
11780
 
10736
11781
                                    /* prepare to package up for caller */
10737
11782
                                    objHdr = Tcl_NewListObj(0, NULL);
10738
11783
 
10739
11784
                                    /* determine body part's charset */
10740
 
                                    if((charset = rfc2231_get_param(b->parameter,"charset",NULL,NULL)) != NULL){
 
11785
                                    if((charset = parameter_val(b->parameter,"charset")) != NULL){
10741
11786
                                        objOpts = Tcl_NewListObj(0, NULL);
10742
11787
                                        peAppListF(interp, objOpts, "%s%s", "charset", charset);
10743
11788
                                        fs_give((void **) &charset);
10744
11789
                                    }
10745
 
                                      
 
11790
 
 
11791
                                    /* body part's MIME subtype */
 
11792
                                    if(b->subtype && strucmp(b->subtype,"plain")){
 
11793
                                        if(!objOpts)
 
11794
                                          objOpts = Tcl_NewListObj(0, NULL);
 
11795
 
 
11796
                                        peAppListF(interp, objOpts, "%s%s", "subtype", b->subtype);
 
11797
                                    }
 
11798
 
10746
11799
                                    peAppListF(interp, objHdr, "%s%a", "from",
10747
 
                                                     role && role->from ? role->from : env->from);
 
11800
                                               role && role->from ? role->from : env->from);
10748
11801
                                    peAppListF(interp, objHdr, "%s%a", "to", env->to);
10749
11802
                                    peAppListF(interp, objHdr, "%s%a", "cc", env->cc);
10750
11803
                                    peAppListF(interp, objHdr, "%s%a", "bcc", env->bcc);
10797
11850
 
10798
11851
                                            snprintf(uidbuf, sizeof(uidbuf), "(%s%s%s)(%ld %lu %s)%s",
10799
11852
                                                     reply->prefix ? int2string(strlen(reply->prefix))
10800
 
                                                                   : (reply->forwarded) ? "" : "0 ",
 
11853
                                                     : (reply->forwarded) ? "" : "0 ",
10801
11854
                                                     reply->prefix ? " " : "",
10802
11855
                                                     reply->prefix ? reply->prefix : "",
10803
 
                                                    i, reply->data.uid.validity,
10804
 
                                                    tmp_20k_buf, reply->mailbox);
 
11856
                                                     i, reply->data.uid.validity,
 
11857
                                                     tmp_20k_buf, reply->mailbox);
10805
11858
 
10806
11859
                                            peAppListF(interp, objHdr, "%s%s", "x-reply-uid", uidbuf);
10807
11860
                                        }
10837
11890
                                    pine_free_body(&b);
10838
11891
                                    free_action(&role);
10839
11892
 
 
11893
                                    /* if Drafts got whacked, open INBOX */
 
11894
                                    if(!ps_global->mail_stream)
 
11895
                                      do_broach_folder(ps_global->inbox_name,
 
11896
                                                       ps_global->context_list,
 
11897
                                                       NULL, DB_INBOXWOCNTXT);
 
11898
 
10840
11899
                                    return(TCL_OK);
10841
11900
                                }
10842
11901
 
10843
11902
                                so_give(&so);
10844
11903
                            }
10845
11904
                            else
10846
 
                              err = "No internal storage";
10847
 
 
10848
 
                            /* redraft_work cleaned up the "stream" */
10849
 
                        }
10850
 
                        else
10851
 
                          err = "No Postponed stream";
10852
 
                    }
10853
 
                    else
10854
 
                      err = "Malformed extract request";
10855
 
                }
10856
 
                else if(!strcmp(s1, "append")){
10857
 
                    return(peMsgCollector(interp, objc - 2, (Tcl_Obj **) &objv[2], peDoPostpone));
 
11905
                              err = "Unknown UID";
 
11906
                        }
 
11907
                        else
 
11908
                          err = "No internal storage";
 
11909
 
 
11910
                        /* redraft_work cleaned up the "stream" */
 
11911
                    }
 
11912
                    else
 
11913
                      err = "No Postponed stream";
 
11914
                }
 
11915
                else
 
11916
                  err = "Malformed extract request";
 
11917
            }
 
11918
            else if(objc == 2){
 
11919
                if(!strcmp(s1, "any")){
 
11920
                    MAILSTREAM *stream;
 
11921
 
 
11922
                    if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
 
11923
                        Tcl_SetResult(interp, "1", TCL_STATIC);
 
11924
 
 
11925
                        if(stream != ps_global->mail_stream)
 
11926
                          pine_mail_close(stream);
 
11927
                    }
 
11928
                    else
 
11929
                      Tcl_SetResult(interp, "0", TCL_STATIC);
 
11930
 
 
11931
                    return(TCL_OK);
 
11932
                }
 
11933
                else if(!strcmp(s1, "count")){
 
11934
                    MAILSTREAM *stream;
 
11935
 
 
11936
                    if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
 
11937
                        Tcl_SetResult(interp, long2string(stream->nmsgs), TCL_STATIC);
 
11938
 
 
11939
                        if(stream != ps_global->mail_stream)
 
11940
                          pine_mail_close(stream);
 
11941
                    }
 
11942
                    else
 
11943
                      Tcl_SetResult(interp, "-1", TCL_STATIC);
 
11944
 
 
11945
                    return(TCL_OK);
 
11946
                }
 
11947
                else if(!strcmp(s1, "list")){
 
11948
                    MAILSTREAM *stream;
 
11949
                    ENVELOPE   *env;
 
11950
                    Tcl_Obj    *objEnv = NULL, *objEnvList;
 
11951
                    long        n;
 
11952
 
 
11953
                    if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
 
11954
                        if(!stream->nmsgs){
 
11955
                            (void) redraft_cleanup(&stream, FALSE, REDRAFT_PPND);
 
11956
                            Tcl_SetResult(interp, "", TCL_STATIC);
 
11957
                            return(TCL_OK);
 
11958
                        }
 
11959
 
 
11960
                        objEnvList = Tcl_NewListObj(0, NULL);
 
11961
 
 
11962
                        for(n = 1; n <= stream->nmsgs; n++){
 
11963
                            if((env = pine_mail_fetchstructure(stream, n, NULL)) != NULL){
 
11964
                                objEnv = Tcl_NewListObj(0, NULL);
 
11965
 
 
11966
                                peAppListF(interp, objEnv, "%s%s", "uid",
 
11967
                                           ulong2string(mail_uid(stream, n)));
 
11968
 
 
11969
                                peAppListF(interp, objEnv, "%s%a", "to", env->to);
 
11970
 
 
11971
                                date_str((char *)env->date, iSDate, 1, tmp_20k_buf, SIZEOF_20KBUF, 0);
 
11972
 
 
11973
                                peAppListF(interp, objEnv, "%s%s", "date", tmp_20k_buf);
 
11974
 
 
11975
                                peAppListF(interp, objEnv, "%s%s", "subj",
 
11976
                                           rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf,
 
11977
                                                                  SIZEOF_20KBUF, env->subject));
 
11978
 
 
11979
                                Tcl_ListObjAppendElement(interp, objEnvList, objEnv);
 
11980
                            }
 
11981
                        }
 
11982
 
 
11983
                        Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objEnvList);
 
11984
 
 
11985
                        Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
 
11986
                                                 Tcl_NewStringObj("utf-8", -1));
 
11987
 
 
11988
                        if(stream != ps_global->mail_stream)
 
11989
                          pine_mail_close(stream);
 
11990
                    }
 
11991
 
 
11992
                    return(TCL_OK);
 
11993
                }
 
11994
            }
 
11995
            else if(objc == 3){
 
11996
                if(!strcmp(s1, "append")){
 
11997
                    int rv;
 
11998
 
 
11999
                    if((rv = peMsgCollector(interp, objc - 2, (Tcl_Obj **) &objv[2], peDoPostpone, PMC_NONE)) == TCL_OK)
 
12000
                      Tcl_SetResult(interp, ulong2string(get_last_append_uid()), TCL_VOLATILE);
 
12001
 
 
12002
                    return(rv);
 
12003
                }
 
12004
                else if(!strcmp(s1, "delete")){
 
12005
                    if(Tcl_GetLongFromObj(interp, objv[2], &uid) == TCL_OK){
 
12006
                        MAILSTREAM    *stream;
 
12007
                        long           rawno;
 
12008
 
 
12009
                        if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
 
12010
                            if((rawno = mail_msgno(stream, uid)) > 0L){
 
12011
                                mail_flag(stream, long2string(rawno), "\\DELETED", ST_SET);
 
12012
                                ps_global->expunge_in_progress = 1;
 
12013
                                mail_expunge(stream);
 
12014
                                ps_global->expunge_in_progress = 0;
 
12015
                                if(stream != ps_global->mail_stream)
 
12016
                                  pine_mail_actually_close(stream);
 
12017
 
 
12018
                                return(TCL_OK);
 
12019
                            }
 
12020
                            else
 
12021
                              err = "PEPostpone delete: UID no longer exists";
 
12022
                        }
 
12023
                        else
 
12024
                          err = "PEPostpone delete: No Postponed stream";
 
12025
                    }
 
12026
                    else
 
12027
                      err = "PEPostpone delete: No uid provided";
10858
12028
                }
10859
12029
            }
10860
12030
        }
10871
12041
int
10872
12042
peDoPostpone(METAENV *metaenv, BODY *body, char *fcc, CONTEXT_S **fcc_cntxtp, char *errp)
10873
12043
{
10874
 
    PINEFIELD *pf;
 
12044
    PINEFIELD   *pf;
 
12045
    int          rv;
 
12046
    appenduid_t *au;
10875
12047
    
10876
12048
    /*
10877
12049
     * resolve fcc and store it in fcc custom header field data
10903
12075
            break;
10904
12076
        }
10905
12077
 
10906
 
    return((write_postponed(metaenv, body) < 0) ? TCL_ERROR : TCL_OK);
 
12078
    au = mail_parameters(NIL, GET_APPENDUID, NIL);
 
12079
    mail_parameters(NIL, SET_APPENDUID, (void *) appenduid_cb);
 
12080
 
 
12081
    rv = write_postponed(metaenv, body);
 
12082
 
 
12083
    mail_parameters(NIL, SET_APPENDUID, (void *) au);
 
12084
 
 
12085
    return((rv < 0) ? TCL_ERROR : TCL_OK);
10907
12086
}
10908
12087
 
10909
12088
 
10914
12093
peMsgCollector(Tcl_Interp *interp,
10915
12094
               int objc,
10916
12095
               Tcl_Obj **objv,
10917
 
               int (*postfunc)(METAENV *, BODY *, char *, CONTEXT_S **, char *))
 
12096
               int (*postfunc)(METAENV *, BODY *, char *, CONTEXT_S **, char *),
 
12097
               long flags)
10918
12098
{
10919
12099
    Tcl_Obj    **objMsg, **objField, **objBody;
10920
12100
    int          i, j, vl, nMsg, nField, nBody;
10927
12107
    memset(&md, 0, sizeof(MSG_COL_S));
10928
12108
    md.postop_fcc_no_attach = -1;
10929
12109
    md.postfunc = postfunc;
 
12110
    md.qualified_addrs = ((flags & PMC_FORCE_QUAL) == PMC_FORCE_QUAL);
10930
12111
 
10931
12112
    if(objc != 1){
10932
 
        Tcl_SetResult(interp, "pePostpone: malformed message data", TCL_STATIC);
 
12113
        Tcl_SetResult(interp, "Malformed message data", TCL_STATIC);
10933
12114
        return(TCL_ERROR);
10934
12115
    }
10935
12116
    else if(!ps_global){
10936
 
        Tcl_SetResult(interp, "pePostpone: no open folder", TCL_STATIC);
 
12117
        Tcl_SetResult(interp, "No open folder", TCL_STATIC);
10937
12118
        return(TCL_ERROR);
10938
12119
    }
10939
12120
 
10951
12132
        if(nField && (field = Tcl_GetStringFromObj(objField[0], NULL))){
10952
12133
            if(!strcmp(field, "body")){
10953
12134
                if(md.msgtext){
10954
 
                    err = "pePostpone: Too many bodies";
 
12135
                    err = "Too many bodies";
10955
12136
                    return(peMsgCollected(interp, &md, err));
10956
12137
                }
10957
12138
                else if((md.msgtext = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
10960
12141
 
10961
12142
                    Tcl_ListObjGetElements(interp, objField[1], &nBody, &objBody);
10962
12143
                    for(j = 0; j < nBody; j++){
10963
 
                        value = (char *) peGetUtf8FromObj(objBody[j], &vl);
 
12144
                        value = Tcl_GetStringFromObj(objBody[j], &vl);
10964
12145
                        if(value){
10965
12146
                            so_nputs(md.msgtext, value, vl);
10966
12147
                            so_puts(md.msgtext, "\n");
10967
12148
                        }
10968
12149
                        else{
10969
 
                            err = "pePostpone: Value read Failure";
 
12150
                            err = "Value read failure";
10970
12151
                            return(peMsgCollected(interp, &md, err));
10971
12152
                        }
10972
12153
                    }
10973
12154
                }
10974
12155
                else {
10975
 
                    err = "pePostpone: Can't acquire body storage";
 
12156
                    err = "Can't acquire body storage";
10976
12157
                    return(peMsgCollected(interp, &md, err));
10977
12158
                }
10978
12159
            }
10996
12177
                      md.attach = tp;
10997
12178
                }
10998
12179
                else{
10999
 
                    strcpy(err = tmp_20k_buf, "pePostpone: unknown attachment ID");
 
12180
                    strcpy(err = tmp_20k_buf, "Unknown attachment ID");
11000
12181
                    return(peMsgCollected(interp, &md, err));
11001
12182
                }
11002
12183
            }
11014
12195
                    md.fcc = cpystr(value);
11015
12196
                }
11016
12197
                else {
11017
 
                    strcpy(err = tmp_20k_buf, "Unrecognized Fcc: specification");
 
12198
                    strcpy(err = tmp_20k_buf, "Unrecognized Fcc specification");
11018
12199
                    return(peMsgCollected(interp, &md, err));
11019
12200
                }
11020
12201
            }
11070
12251
                            }
11071
12252
                        }
11072
12253
                    }
11073
 
                    else if(!strucmp(value, "richtext")){
11074
 
                        if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){
11075
 
                            if(!strucmp(value, "yes"))
11076
 
                              md.rich = 1;
 
12254
                    else if(!strucmp(value, "subtype")){
 
12255
                        if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){
 
12256
                            if(!strucmp(value, "html"))
 
12257
                              md.html = 1;
 
12258
                        }
 
12259
                        else{
 
12260
                            err = "Post option read failure";
 
12261
                            return(peMsgCollected(interp, &md, err));
 
12262
                        }
 
12263
                    }
 
12264
                    else if(!strucmp(value, "priority")){
 
12265
                        if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){
 
12266
                            char *priority = NULL;
 
12267
 
 
12268
                            if(!strucmp(value, "highest"))
 
12269
                              priority = "Highest";
 
12270
                            else if(!strucmp(value, "high"))
 
12271
                              priority = "High";
 
12272
                            else if(!strucmp(value, "normal"))
 
12273
                              priority = "Normal";
 
12274
                            else if(!strucmp(value, "low"))
 
12275
                              priority = "Low";
 
12276
                            else if(!strucmp(value, "lowest"))
 
12277
                              priority = "Lowest";
 
12278
 
 
12279
                            if(priority){
 
12280
                                if(pf = set_priority_header(md.metaenv, priority))
 
12281
                                  pf->text = &pf->textbuf;
 
12282
                            }
11077
12283
                        }
11078
12284
                        else{
11079
12285
                            err = "Post option read failure";
11092
12298
            }
11093
12299
            else {
11094
12300
                if(nField != 2){
11095
 
                    sprintf(err = tmp_20k_buf, "pePostpone: malformed header (%s)", field);
 
12301
                    sprintf(err = tmp_20k_buf, "Malformed header (%s)", field);
11096
12302
                    return(peMsgCollected(interp, &md, err));
11097
12303
                }
11098
12304
 
11099
 
                if((value = (char *) peGetUtf8FromObj(objField[1], &vl)) != NULL){
 
12305
                if((value = Tcl_GetStringFromObj(objField[1], &vl)) != NULL){
11100
12306
                    ADDRESS **addrp = NULL;
11101
12307
                    char    **valp = NULL, *valcpy;
11102
12308
 
11175
12381
                          ;
11176
12382
 
11177
12383
                        rfc822_parse_adrlist(addrp, valcpy,
11178
 
                                             (F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global))
 
12384
                                             (flags & PMC_FORCE_QUAL)
11179
12385
                                               ? fakedomain : ps_global->maildomain);
11180
12386
                        fs_give((void **) &valcpy);
11181
12387
                    }
11182
12388
                }
11183
12389
                else{
11184
 
                    err = "pePostpone: Value read Failure";
 
12390
                    err = "Value read failure";
11185
12391
                    return(peMsgCollected(interp, &md, err));
11186
12392
                }
11187
12393
            }
11209
12415
 
11210
12416
        rv = TCL_ERROR;
11211
12417
    }
11212
 
    else if(F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global) && check_addresses(md->metaenv) == CA_BAD){
 
12418
    else if(md->qualified_addrs && check_addresses(md->metaenv) == CA_BAD){
11213
12419
        sprintf(err = tmp_20k_buf, "Address must be fully qualified.");
11214
12420
        rv = TCL_ERROR;
11215
12421
    }
11312
12518
                    peBodyMoveContents(a->l.b.body, &(*np)->body);
11313
12519
                }
11314
12520
                else{
11315
 
                    err = "BOTCH: Unknown attacmnent type";
 
12521
                    err = "BOTCH: Unknown attachment type";
11316
12522
                    rv = TCL_ERROR;
11317
12523
                    break;
11318
12524
                }
11323
12529
 
11324
12530
        /* assign MIME parameters to text body part */
11325
12531
        tbp->type = TYPETEXT;
11326
 
        if(md->rich)
 
12532
        if(md->html)
11327
12533
          tbp->subtype = cpystr("HTML");
11328
12534
 
11329
12535
        tbp->contents.text.data = (void *) md->msgtext;
11443
12649
                Tcl_ListObjAppendElement(interp, aObj, Tcl_NewStringObj(id, -1));
11444
12650
 
11445
12651
                /* name */
11446
 
                if((name = rfc2231_get_param(part->body.disposition.parameter, "filename", NULL, NULL))
11447
 
                   || (name = rfc2231_get_param(part->body.parameter, "name", NULL, NULL))){
 
12652
                if((name = get_filename_parameter(NULL, 0, &part->body, NULL)) != NULL){
11448
12653
                    Tcl_ListObjAppendElement(interp, aObj, Tcl_NewStringObj(name, -1));
11449
12654
                    fs_give((void **) &name);
11450
12655
                }
11788
12993
                Tcl_SetResult(interp, buf, TCL_VOLATILE);
11789
12994
                return(TCL_ERROR);
11790
12995
            }
11791
 
            else if(!strcmp(op, "complete")){
11792
 
                /*
11793
 
                 * CMD: complete
11794
 
                 *
11795
 
                 *    Look for possible completions for
11796
 
                 *    given query_string.  
11797
 
                 *
11798
 
                 * ARGS: <query_string>
11799
 
                 *
11800
 
                 * Returns: candidate list: {nickname  {personal mailbox}}
11801
 
                 */
11802
 
                char        *query;
11803
 
                COMPLETE_S  *completions, *cp;
11804
 
 
11805
 
                if(peInitAddrbooks(interp, 0) != TCL_OK)
11806
 
                  return(TCL_ERROR);
11807
 
 
11808
 
                if((query = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
11809
 
 
11810
 
                    completions = adrbk_list_of_completions(query);
11811
 
 
11812
 
                    if(completions){
11813
 
                        for(cp = completions; cp; cp = cp->next)
11814
 
                          peAppListF(interp, Tcl_GetObjResult(interp), "%s %s",
11815
 
                                     cp->nickname ? cp->nickname : "",
11816
 
                                     cp->full_address ? cp->full_address : "");
11817
 
 
11818
 
                        free_complete_s(&completions);
11819
 
                    }
11820
 
                    else
11821
 
                      Tcl_SetResult(interp, "", TCL_STATIC);
11822
 
                }
11823
 
 
11824
 
                return(TCL_OK);
11825
 
            }
11826
 
 
11827
12996
        }
11828
12997
        else if(objc == 4){
11829
12998
            if(!strcmp(op, "verify")){
11901
13070
                                    adrObj = Tcl_NewListObj(0,NULL);
11902
13071
#ifdef ENABLE_LDAP
11903
13072
                                    if(*tsl) {
11904
 
                                        LDAP_SERV_RES_S *tres, *trl;
 
13073
                                        LDAP_CHOOSE_S   *tres;
 
13074
                                        LDAP_SERV_RES_S *trl;
11905
13075
                                        LDAPMessage *e;
11906
13076
                                        ADDRESS *newadr;
11907
13077
                                        char    *ret_to;
11908
13078
                                        
11909
 
                                        tres = (LDAP_SERV_RES_S *)fs_get(sizeof(LDAP_SERV_RES_S));
 
13079
                                        tres = (LDAP_CHOOSE_S *)fs_get(sizeof(LDAP_CHOOSE_S));
11910
13080
                                        for(trl = (*tsl)->reslist; trl; 
11911
13081
                                            trl = trl->next){
11912
13082
                                            for(e = ldap_first_entry(trl->ld, 
11914
13084
                                                e != NULL; 
11915
13085
                                                e = ldap_next_entry(trl->ld, e)){
11916
13086
                                                tres->ld        = trl->ld;
11917
 
                                                tres->res       = e;
 
13087
                                                tres->selected_entry = e;
11918
13088
                                                tres->info_used = trl->info_used;
11919
13089
                                                tres->serv      = trl->serv;
11920
 
                                                tres->next      = NULL;
11921
13090
                                                if((newadr = address_from_ldap(tres)) != NULL){
11922
13091
                                                    if(newadr->mailbox && newadr->host){
11923
13092
                                                        RFC822BUFFER rbuf;
12087
13256
                    }
12088
13257
                }
12089
13258
            }
 
13259
            else if(!strcmp(op, "complete")){
 
13260
                /*
 
13261
                 * CMD: complete uid
 
13262
                 *
 
13263
                 *    Look for possible completions for
 
13264
                 *    given query_string.  
 
13265
                 *
 
13266
                 * ARGS: <query_string> <uid>
 
13267
                 *
 
13268
                 * Returns: candidate list: {nickname  {personal mailbox}}
 
13269
                 */
 
13270
                char        *query, *errstr;
 
13271
                long         uid;
 
13272
                COMPLETE_S  *completions, *cp;
 
13273
 
 
13274
                if(peInitAddrbooks(interp, 0) == TCL_OK){
 
13275
                    if((query = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
 
13276
                        if(Tcl_GetLongFromObj(interp, objv[3], &uid) == TCL_OK){
 
13277
 
 
13278
                            completions = adrbk_list_of_completions(query,
 
13279
                                                                    ps_global->mail_stream,
 
13280
                                                                    uid,
 
13281
#ifdef ENABLE_LDAP
 
13282
                                                                    ((strlen(query) >= 5) ? ALC_INCLUDE_LDAP : 0) |
 
13283
#endif /* ENABLE_LDAP */
 
13284
                                                                    0);
 
13285
 
 
13286
                            if(completions){
 
13287
                                for(cp = completions; cp; cp = cp->next)
 
13288
                                  peAppListF(interp, Tcl_GetObjResult(interp), "%s %s",
 
13289
                                             cp->nickname ? cp->nickname : "",
 
13290
                                             cp->full_address ? cp->full_address : "");
 
13291
 
 
13292
                                free_complete_s(&completions);
 
13293
                            }
 
13294
                            else
 
13295
                              Tcl_SetResult(interp, "", TCL_STATIC);
 
13296
 
 
13297
                            return(TCL_OK);
 
13298
                        }
 
13299
                        else
 
13300
                          errstr = "PEAddress: Cannot read UID";
 
13301
                    }
 
13302
                    else
 
13303
                      errstr = "PEAddress: Cannot get completion query";
 
13304
                }
 
13305
                else
 
13306
                  errstr = "PEAddress: Address Book initialization failed";
 
13307
 
 
13308
                Tcl_SetResult(interp, errstr, TCL_STATIC);
 
13309
                return(TCL_ERROR);
 
13310
            }
12090
13311
        }
12091
13312
        else if(objc == 5){
12092
13313
            if(!strcmp(op, "entry")){
12281
13502
                int           booknum, adri, add, rv, aindex;
12282
13503
                char         *nick, *fn, *fcc, *comment, *addrfield, 
12283
13504
                              buf[256], **addrs, *orignick = NULL;
12284
 
                AdrBk_Entry  *ae;
 
13505
                AdrBk_Entry  *ae = NULL;
12285
13506
                AdrBk        *ab;
12286
 
                adrbk_cntr_t  old_entry, new_entry;
 
13507
                adrbk_cntr_t  old_entry = NO_NEXT, new_entry;
12287
13508
                Tag           tag;
12288
13509
                ADDRESS      *adr = NULL;
12289
13510
                
12294
13515
                    if(as.adrbks[booknum].access != ReadWrite) return TCL_ERROR;
12295
13516
                    nick    = Tcl_GetStringFromObj(objv[3], NULL);
12296
13517
                    removing_leading_and_trailing_white_space(nick);
12297
 
                    if(Tcl_GetIntFromObj(interp, objv[4], &aindex) != TCL_OK
12298
 
                        || (*nick == '\0' && aindex < 0))
12299
 
                      return(TCL_ERROR);
 
13518
                    if(Tcl_GetIntFromObj(interp, objv[4], &aindex) != TCL_OK){
 
13519
                        Tcl_SetResult(interp, "No Address Handle", TCL_VOLATILE);
 
13520
                        return(TCL_ERROR);
 
13521
                    }
12300
13522
                    fn      = Tcl_GetStringFromObj(objv[5], NULL);
12301
13523
                    removing_leading_and_trailing_white_space(fn);
12302
13524
                    if(!*fn) fn = NULL;
12324
13546
                        orignick     = Tcl_GetStringFromObj(objv[10], NULL);
12325
13547
                        removing_leading_and_trailing_white_space(orignick);
12326
13548
                    }
12327
 
                    if(addrfield == NULL){
12328
 
                        Tcl_SetResult(interp, "No addresses defined",
12329
 
                                      TCL_VOLATILE);
12330
 
                        return(TCL_OK);
12331
 
                    }
12332
13549
                    if((addrs = parse_addrlist(addrfield)) != NULL){
12333
13550
                      int tbuflen = strlen(addrfield);
12334
13551
                      char *tbuf;
12353
13570
                                if(tbuf)
12354
13571
                                  fs_give((void **) &tbuf);
12355
13572
                                fs_give((void **) &addrs);
12356
 
                                return(TCL_OK);
 
13573
                                return(TCL_ERROR);
12357
13574
                              }
12358
13575
                          }
12359
13576
                      }
12370
13587
                        ab = as.adrbks[booknum].address_book;
12371
13588
                    }
12372
13589
                    else{
12373
 
                      fs_give((void **) &addrs);
 
13590
                      if(addrs)
 
13591
                        fs_give((void **) &addrs);
12374
13592
                      return(TCL_ERROR);
12375
13593
                    }
12376
13594
                    adrbk_check_validity(ab, 1L);
12381
13599
                                      TCL_VOLATILE);
12382
13600
                        return(TCL_ERROR);
12383
13601
                    }
12384
 
                    if(!nick) {
12385
 
                        snprintf(buf, sizeof(buf), "No nickname defined.");
12386
 
                        Tcl_SetResult(interp, buf, TCL_VOLATILE);
12387
 
                        fs_give((void **) &addrs);
12388
 
                        return(TCL_OK);
 
13602
                    if(aindex >= 0){
 
13603
                        ae = adrbk_get_ae(as.adrbks[booknum].address_book, aindex);
 
13604
                        if(ae){
 
13605
                            old_entry = (adrbk_cntr_t) aindex;
 
13606
                        }
 
13607
                        else{
 
13608
                            Tcl_SetResult(interp, "No Address Handle!", TCL_VOLATILE);
 
13609
                            return(TCL_ERROR);
 
13610
                        }
12389
13611
                    }
12390
 
                    if((orignick ? *orignick : *nick)
12391
 
                       ? !(ae = adrbk_lookup_by_nick(ab, orignick ? orignick : nick, &old_entry))
12392
 
                       : !((ae = adrbk_get_ae(as.adrbks[booknum].address_book, aindex))
12393
 
                           && ((old_entry = (adrbk_cntr_t)aindex) != -1)))
12394
 
                      old_entry = NO_NEXT;
12395
 
                    if((ae && add) || 
12396
 
                       (orignick && strcmp(orignick, nick) 
12397
 
                        && adrbk_lookup_by_nick(ab, nick, NULL))) {
 
13612
                    else if(nick && *nick && adrbk_lookup_by_nick(ab, nick, NULL)){
12398
13613
                        snprintf(buf, sizeof(buf), "Entry with nickname %.128s already exists.",
12399
13614
                                nick);
12400
13615
                        Tcl_SetResult(interp, buf, TCL_VOLATILE);
12401
 
                        fs_give((void **) &addrs);
12402
 
                        return(TCL_OK);
 
13616
                        if(addrs)
 
13617
                          fs_give((void **) &addrs);
 
13618
                        return(TCL_ERROR);
12403
13619
                    }
12404
13620
                    if(ae &&
12405
13621
                       ((tag == List && ae->tag == Single) ||
12409
13625
                                    ae->tag == Single ? "Single" : "List", 
12410
13626
                                    tag == List ? "List" : "Single");
12411
13627
                            Tcl_SetResult(interp, buf, TCL_VOLATILE);
12412
 
                            fs_give((void **) &addrs);
 
13628
                            if(addrs)
 
13629
                              fs_give((void **) &addrs);
12413
13630
                            return(TCL_ERROR);
12414
13631
                        }
12415
13632
                        old_entry = NO_NEXT;
12418
13635
                                       nick ? nick : "", 
12419
13636
                                       fn ? fn : "", 
12420
13637
                                       tag == List ? (char *)addrs : 
12421
 
                                       *addrs ? *addrs : "", 
 
13638
                                       (addrs && *addrs) ? *addrs : "", 
12422
13639
                                       fcc ? fcc : "", 
12423
13640
                                       comment ? comment : "", 
12424
13641
                                       tag, &new_entry, NULL, 0, 1, 
12425
13642
                                       tag == List ? 0 : 1)) != 0){
12426
13643
                        snprintf(buf, sizeof(buf), "Couldn't add entry! rv=%d.", rv);
12427
13644
                        Tcl_SetResult(interp, buf, TCL_VOLATILE);
12428
 
                        fs_give((void **) &addrs);
12429
 
                        return(TCL_OK);
 
13645
                        if(addrs)
 
13646
                          fs_give((void **) &addrs);
 
13647
                        return(TCL_ERROR);
12430
13648
                    }
12431
13649
                    if(tag == List) {
12432
13650
                      adrbk_listdel_all(ab, new_entry);
13482
14700
    Tcl_Obj  *itemObj, *secObj = NULL, *resObj = NULL;
13483
14701
    int anum = 0;
13484
14702
 
13485
 
    mn_set_cur(ps_global->msgmap, peMessageNumber(uid));
 
14703
    mn_set_cur(sp_msgmap(ps_global->mail_stream), peMessageNumber(uid));
13486
14704
 
13487
 
    if(set_up_takeaddr('a', ps_global, ps_global->msgmap,
 
14705
    if(set_up_takeaddr('a', ps_global, sp_msgmap(ps_global->mail_stream),
13488
14706
                       &talist, &anum, TA_NOPROMPT, NULL) < 0
13489
14707
                       || (talist == NULL)){
13490
14708
        Tcl_SetResult(interp,
13574
14792
}
13575
14793
 
13576
14794
 
 
14795
/*
 
14796
 * peTakeFrom - Take only From Address
 
14797
 */
 
14798
int
 
14799
peTakeFrom(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
 
14800
{
 
14801
    char     *err = NULL;
 
14802
    Tcl_Obj  *objItem;
 
14803
    ADDRESS  *ap;
 
14804
    ENVELOPE *env;
 
14805
    long      rawno;
 
14806
 
 
14807
    /*
 
14808
     * Return value will be of the form:
 
14809
     *  {
 
14810
     *   { "line to print",
 
14811
     *     {"personal", "mailbox", "host"}         # addr
 
14812
     *     {"nick", "fullname", "fcc", "comment"}  # suggested
 
14813
     *   }
 
14814
     *   ...
 
14815
     *  }
 
14816
     *
 
14817
     *  The two list items will be empty if that line is
 
14818
     *  just informational.
 
14819
     */
 
14820
 
 
14821
    if(uid){
 
14822
        if((env = pine_mail_fetchstructure(ps_global->mail_stream,
 
14823
                                           rawno = peSequenceNumber(uid),
 
14824
                                           NULL))){
 
14825
            /* append the address information */
 
14826
            for(ap = env->from; ap; ap = ap->next){
 
14827
                objItem = Tcl_NewListObj(0, NULL);
 
14828
                /* append EMPTY "line to print" */
 
14829
                if(Tcl_ListObjAppendElement(interp, objItem, Tcl_NewStringObj("",-1)) != TCL_OK)
 
14830
                  return(TCL_ERROR);
 
14831
 
 
14832
                /* append address info */
 
14833
                peAppListF(interp, objItem, "%s%s%s",
 
14834
                           ap->personal ? (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, SIZEOF_20KBUF, ap->personal) : "",
 
14835
                           ap->mailbox ? ap->mailbox : "",
 
14836
                           ap->host ? ap->host : "");
 
14837
 
 
14838
                /* append suggested info */
 
14839
                peAddSuggestedContactInfo(interp, objItem, ap);
 
14840
 
 
14841
                if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objItem) != TCL_OK)
 
14842
                  return(TCL_ERROR);
 
14843
            }
 
14844
 
 
14845
            return(TCL_OK);
 
14846
        }
 
14847
        else
 
14848
          err = ps_global->last_error;
 
14849
    }
 
14850
    else
 
14851
      err = "Invalid UID";
 
14852
 
 
14853
    return(TCL_ERROR);
 
14854
}
 
14855
 
 
14856
 
 
14857
int
 
14858
peAddSuggestedContactInfo(Tcl_Interp *interp, Tcl_Obj *lobjp, ADDRESS *addr)
 
14859
{
 
14860
    char *nick = NULL, *full = NULL, *fcc = NULL, *comment = NULL;
 
14861
 
 
14862
    get_contactinfo_from_addr(addr, &nick, &full, &fcc, &comment);
 
14863
 
 
14864
    peAppListF(interp, lobjp, "%s%s%s%s",
 
14865
               nick ? nick : "",
 
14866
               full ? full : "",
 
14867
               fcc ? fcc : "",
 
14868
               comment ? comment : "");
 
14869
 
 
14870
    if(nick)
 
14871
      fs_give((void **) &nick);
 
14872
 
 
14873
    if(full)
 
14874
      fs_give((void **) &full);
 
14875
 
 
14876
    if(fcc)
 
14877
      fs_give((void **) &fcc);
 
14878
 
 
14879
    if(comment)
 
14880
      fs_give((void **) &comment);
 
14881
}
 
14882
 
 
14883
 
13577
14884
/* * * * * * * * * Status message ring management * * * * * * * * * * * * */
13578
14885
 
13579
14886
STATMSG_S *
13710
15017
        else if(!strcmp(s1, "query")){
13711
15018
            int               dir;
13712
15019
            char             *srchstr, *filtstr;
13713
 
            LDAP_SERV_RES_S  *winning_e = NULL, *results = NULL;
 
15020
            LDAP_CHOOSE_S    *winning_e = NULL;
 
15021
            LDAP_SERV_RES_S  *results = NULL;
13714
15022
            WP_ERR_S          wp_err;
13715
15023
            CUSTOM_FILT_S    *filter = NULL;
13716
15024
 
13785
15093
                char *whichrec = Tcl_GetStringFromObj(objv[3], NULL);
13786
15094
                char *tmpstr, *tmp, *tmp2, **vals, *a;
13787
15095
                WPLDAPRES_S     *curres;
13788
 
                LDAP_SERV_RES_S *winning_e = NULL, *trl;
 
15096
                LDAP_CHOOSE_S   *winning_e = NULL;
 
15097
                LDAP_SERV_RES_S *trl;
13789
15098
                Tcl_Obj     *secObj = NULL, *resObj = NULL, *itemObj;
13790
15099
                BerElement *ber;
13791
15100
                LDAPMessage *e;
13830
15139
                  Tcl_SetResult(interp, "Ldap ldapext error 5", TCL_VOLATILE);
13831
15140
                  return TCL_ERROR;
13832
15141
                }
13833
 
                winning_e = (LDAP_SERV_RES_S *)fs_get(sizeof(LDAP_SERV_RES_S));
 
15142
                winning_e = (LDAP_CHOOSE_S *)fs_get(sizeof(LDAP_CHOOSE_S));
13834
15143
                winning_e->ld        = trl->ld;
13835
 
                winning_e->res       = e;
 
15144
                winning_e->selected_entry = e;
13836
15145
                winning_e->info_used = trl->info_used;
13837
15146
                winning_e->serv      = trl->serv;
13838
 
                winning_e->next      = NULL;
13839
 
                a = ldap_get_dn(winning_e->ld, winning_e->res);
 
15147
                a = ldap_get_dn(winning_e->ld, winning_e->selected_entry);
13840
15148
                if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), 
13841
15149
                                            Tcl_NewStringObj(a ? a : "", -1)) != TCL_OK)
13842
15150
                  return(TCL_ERROR);
13844
15152
                  our_ldap_dn_memfree(a);
13845
15153
                
13846
15154
                itemObj = Tcl_NewListObj(0, NULL);
13847
 
                for(a = ldap_first_attribute(winning_e->ld, winning_e->res, &ber);
 
15155
                for(a = ldap_first_attribute(winning_e->ld, winning_e->selected_entry, &ber);
13848
15156
                    a != NULL;
13849
 
                    a = ldap_next_attribute(winning_e->ld, winning_e->res, ber)){
 
15157
                    a = ldap_next_attribute(winning_e->ld, winning_e->selected_entry, ber)){
13850
15158
                    if(a && *a){
13851
15159
                        secObj = Tcl_NewListObj(0, NULL);
13852
15160
                        if(Tcl_ListObjAppendElement(interp, secObj,
13854
15162
                                                  winning_e->info_used), -1)) != TCL_OK)
13855
15163
                          return(TCL_ERROR);
13856
15164
                        resObj = Tcl_NewListObj(0, NULL);
13857
 
                        vals = ldap_get_values(winning_e->ld, winning_e->res, a);
 
15165
                        vals = ldap_get_values(winning_e->ld, winning_e->selected_entry, a);
13858
15166
                        if(vals){
13859
15167
                            for(i = 0; vals[i]; i++){
13860
15168
                                if(Tcl_ListObjAppendElement(interp, resObj,
13894
15202
              ADDRESS         *adr = NULL, *curadr, *prevadr, *newadr,
13895
15203
                              *curnewadr, *newadrs;
13896
15204
              int              curi, i, j, numsrchs, numset, setit;
13897
 
              LDAP_SERV_RES_S *tres, *trl;
 
15205
              LDAP_CHOOSE_S   *tres;
 
15206
              LDAP_SERV_RES_S *trl;
13898
15207
              WPLDAPRES_S     *curres;
13899
15208
              LDAPMessage     *e;
13900
15209
              RFC822BUFFER     rbuf;
13956
15265
                      if(setit){
13957
15266
                          was_char = *tmp2;
13958
15267
                          *tmp2 = '\0';
13959
 
                          lset[i][j++] = atoi(tmp);                             
 
15268
                          lset[i][j++] = atoi(tmp);
13960
15269
                          *tmp2 = was_char;
13961
15270
                      }
13962
15271
                      if(*tmp2) tmp2++;
13984
15293
                      e != NULL && lset[i][curi] != -1;
13985
15294
                      e = ldap_next_entry(trl->ld, e), j++){
13986
15295
                      if(j == lset[i][curi]){
13987
 
                          tres = (LDAP_SERV_RES_S *)fs_get(sizeof(LDAP_SERV_RES_S));
 
15296
                          tres = (LDAP_CHOOSE_S *)fs_get(sizeof(LDAP_CHOOSE_S));
13988
15297
                          tres->ld        = trl->ld;
13989
 
                          tres->res       = e;
 
15298
                          tres->selected_entry = e;
13990
15299
                          tres->info_used = trl->info_used;
13991
15300
                          tres->serv      = trl->serv;
13992
 
                          tres->next      = NULL;
13993
15301
                          newadr = address_from_ldap(tres);
13994
15302
                          fs_give((void **)&tres);
13995
15303
 
14143
15451
            if(org)
14144
15452
              ldap_value_free(org);
14145
15453
            if(mail)
14146
 
              ldap_value_free(mail);        
 
15454
              ldap_value_free(mail);
14147
15455
        }
14148
15456
        }
14149
15457
        if(Tcl_ListObjAppendElement(interp, secObj, resObj) != TCL_OK)
14166
15474
        for(i = 0; strl[i] && strl[i][0]; i++){
14167
15475
            if(Tcl_ListObjAppendElement(interp, strlObj,
14168
15476
                       Tcl_NewStringObj(strl[i], -1)) != TCL_OK)
14169
 
                return(TCL_ERROR);                  
 
15477
                return(TCL_ERROR);
14170
15478
        }
14171
15479
    }
14172
15480
    if(Tcl_ListObjAppendElement(interp, itemObj, strlObj) != TCL_OK)
14539
15847
 
14540
15848
    return(TRUE);
14541
15849
}
 
15850
 
 
15851
char *
 
15852
peWebAlpinePrefix(void)
 
15853
{
 
15854
    return("Web ");
 
15855
}
 
15856
 
 
15857
 
 
15858
/* * * * * * * * * RSS 2.0 Support Routines  * * * * * * * * * * * */
 
15859
 
 
15860
/*
 
15861
 * PERssCmd - RSS TCL interface
 
15862
 */
 
15863
int
 
15864
PERssCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 
15865
{
 
15866
    char *s1;
 
15867
 
 
15868
    dprint((2, "PERssCmd"));
 
15869
 
 
15870
    if(objc == 1){
 
15871
        Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
 
15872
        return(TCL_ERROR);
 
15873
    }
 
15874
    s1 = Tcl_GetStringFromObj(objv[1], NULL);
 
15875
 
 
15876
    if(s1){
 
15877
        if(!strcmp(s1, "news")){
 
15878
            return(peRssReturnFeed(interp, "news", ps_global->VAR_RSS_NEWS));
 
15879
        }
 
15880
        else if(!strcmp(s1, "weather")){
 
15881
            return(peRssReturnFeed(interp, "weather", ps_global->VAR_RSS_WEATHER));
 
15882
        }
 
15883
    }
 
15884
 
 
15885
    Tcl_SetResult(interp, "Unknown PERss command", TCL_STATIC);
 
15886
    return(TCL_ERROR);
 
15887
}
 
15888
 
 
15889
/*
 
15890
 * peRssReturnFeed - fetch feed contents and package Tcl response
 
15891
 */
 
15892
int
 
15893
peRssReturnFeed(Tcl_Interp *interp, char *type, char *link)
 
15894
{
 
15895
    RSS_FEED_S *feed;
 
15896
    char       *errstr = "UNKNOWN";
 
15897
 
 
15898
    if(link){
 
15899
        ps_global->c_client_error[0] = '\0';
 
15900
 
 
15901
        if((feed = peRssFeed(interp, type, link)) != NULL)
 
15902
          return(peRssPackageFeed(interp, feed));
 
15903
 
 
15904
        if(ps_global->mm_log_error)
 
15905
          errstr = ps_global->c_client_error;
 
15906
    }
 
15907
    else
 
15908
      errstr = "missing setting";
 
15909
 
 
15910
    snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s feed fail: %s", type, errstr);
 
15911
    Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE);
 
15912
    return(TCL_ERROR);
 
15913
}
 
15914
 
 
15915
/*
 
15916
 * peRssPackageFeed - build a list of feed item elements
 
15917
 *
 
15918
 *      LIST ORDER: {title} {link} {description} {image}
 
15919
 */
 
15920
int
 
15921
peRssPackageFeed(Tcl_Interp *interp, RSS_FEED_S *feed)
 
15922
{
 
15923
    RSS_ITEM_S *item;
 
15924
 
 
15925
    for(item = feed->items; item; item = item->next)
 
15926
      if(peAppListF(interp, Tcl_GetObjResult(interp), "%s %s %s %s",
 
15927
                    (item->title && *item->title)? item->title : "Feed Provided No Title",
 
15928
                    item->link ? item->link : "",
 
15929
                    item->description ? item->description : "",
 
15930
                    feed->image ? feed->image : "") != TCL_OK)
 
15931
        return(TCL_ERROR);
 
15932
 
 
15933
    return(TCL_OK);
 
15934
}
 
15935
 
 
15936
 
 
15937
/*
 
15938
 * peRssFeed - return cached feed struct or fetch a new one
 
15939
 */
 
15940
RSS_FEED_S *
 
15941
peRssFeed(Tcl_Interp *interp, char *type, char *link)
 
15942
{
 
15943
    int          i, cache_l, cp_ref;
 
15944
    time_t       now = time(0);
 
15945
    RSS_FEED_S  *feed = NULL;
 
15946
    RSS_CACHE_S *cache, *cp;
 
15947
    static RSS_CACHE_S news_cache[RSS_NEWS_CACHE_SIZE], weather_cache[RSS_WEATHER_CACHE_SIZE];
 
15948
 
 
15949
    if(!strucmp(type,"news")){
 
15950
        cache   =  &news_cache[0];
 
15951
        cache_l = RSS_NEWS_CACHE_SIZE;
 
15952
    }
 
15953
    else{
 
15954
        cache   = &weather_cache[0];
 
15955
        cache_l = RSS_WEATHER_CACHE_SIZE;
 
15956
    }
 
15957
 
 
15958
    /* search/purge cache */
 
15959
    for(i = 0; i < cache_l; i++)
 
15960
      if(cache[i].link){
 
15961
          if(now > cache[i].stale){
 
15962
              peRssClearCacheEntry(&cache[i]);
 
15963
          }
 
15964
          else if(!strcmp(link, cache[i].link)){
 
15965
              cache[i].referenced++;
 
15966
              return(cache[i].feed); /* HIT! */
 
15967
          }
 
15968
      }
 
15969
 
 
15970
    if((feed = peRssFetch(interp, link)) != NULL){
 
15971
        /* find cache slot, and insert feed into cache */
 
15972
        for(i = 0, cp_ref = 0; i < cache_l; i++)
 
15973
          if(!cache[i].feed){
 
15974
              cp = &cache[i];
 
15975
              break;
 
15976
          }
 
15977
          else if(cache[i].referenced >= cp_ref)
 
15978
            cp = &cache[i];
 
15979
 
 
15980
        if(!cp)
 
15981
          cp = &cache[0];               /* failsafe */
 
15982
 
 
15983
        peRssClearCacheEntry(cp);       /* make sure */
 
15984
 
 
15985
        cp->link       = cpystr(link);
 
15986
        cp->feed       = feed;
 
15987
        cp->referenced = 0;
 
15988
        cp->stale      = now + (((feed->ttl > 0) ? feed->ttl : 60) * 60);
 
15989
    }
 
15990
 
 
15991
    return(feed);
 
15992
}
 
15993
 
 
15994
/*
 
15995
 * peRssFetch - follow the provided link an return the resulting struct
 
15996
 */
 
15997
RSS_FEED_S *
 
15998
peRssFetch(Tcl_Interp *interp, char *link)
 
15999
{
 
16000
    char          *scheme = NULL, *loc = NULL, *path = NULL, *parms = NULL, *query = NULL, *frag = NULL;
 
16001
    char          *buffer = NULL, *bp, *p, *q;
 
16002
    unsigned long  port = 0L, buffer_len = 0L;
 
16003
    STORE_S       *feed_so = NULL;
 
16004
    TCPSTREAM     *tcp_stream;
 
16005
 
 
16006
    if(link){
 
16007
        /* grok url */
 
16008
        rfc1808_tokens(link, &scheme, &loc, &path, &parms, &query, &frag);
 
16009
        if(scheme && loc && path){
 
16010
            if((p = strchr(loc,':')) != NULL){
 
16011
                *p++  = '\0';
 
16012
                while(*p && isdigit((unsigned char) *p))
 
16013
                  port = ((port * 10) + (*p++ - '0'));
 
16014
 
 
16015
                if(*p){
 
16016
                    Tcl_SetResult(interp, "Bad RSS port number", TCL_STATIC);
 
16017
                    peRssComponentFree(&scheme,&loc,&path,&parms,&query,&frag);
 
16018
                    return(NULL);
 
16019
                }
 
16020
            }
 
16021
 
 
16022
            mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long) 5);
 
16023
            tcp_stream = tcp_open (loc, scheme, port | NET_NOOPENTIMEOUT);
 
16024
            mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long) 30);
 
16025
 
 
16026
            if(tcp_stream != NULL){
 
16027
                char rev[128];
 
16028
 
 
16029
                snprintf(tmp_20k_buf, SIZEOF_20KBUF, "GET /%s%s%s%s%s HTTP/1.1\r\nHost: %s\r\nAccept: application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nUser-Agent: Web-Alpine/%s (%s %s)\r\n\r\n",
 
16030
                         path, parms ? ":" : "", parms ? parms : "",
 
16031
                         query ? "?" : "", query ? query : "", loc,
 
16032
                         ALPINE_VERSION, SYSTYPE, get_alpine_revision_string(rev, sizeof(rev)));
 
16033
 
 
16034
                mail_parameters(NULL, SET_READTIMEOUT, (void *)(long) 5);
 
16035
 
 
16036
                if(tcp_sout(tcp_stream, tmp_20k_buf, strlen(tmp_20k_buf))){
 
16037
                    int ok = 0;
 
16038
 
 
16039
                    while((p = tcp_getline(tcp_stream)) != NULL){
 
16040
                        if(!ok){
 
16041
                            ok++;
 
16042
                            if(strucmp(p,"HTTP/1.1 200 OK")){
 
16043
                                fs_give((void **) &p);
 
16044
                                break;
 
16045
                            }
 
16046
                        }
 
16047
                        else if(*p == '\0'){
 
16048
                            if(buffer_len){
 
16049
                                buffer = fs_get(buffer_len + 16);
 
16050
                                if(!tcp_getbuffer(tcp_stream, buffer_len, buffer))
 
16051
                                  fs_give((void **) &buffer);
 
16052
 
 
16053
                                fs_give((void **) &p);
 
16054
                                break;
 
16055
                            }
 
16056
                            else{                       /* no content-length: */
 
16057
                                if((feed_so = so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){
 
16058
                                    fs_give((void **) &p);
 
16059
                                    break;
 
16060
                                }
 
16061
                            }
 
16062
                        }
 
16063
                        else if(feed_so){
 
16064
                            so_puts(feed_so, p);
 
16065
                        }
 
16066
                        else{
 
16067
                            if(q = strchr(p,':')){
 
16068
                                int l = q - p;
 
16069
 
 
16070
                                *q++ = '\0';
 
16071
                                while(isspace((unsigned char ) *q))
 
16072
                                  q++;
 
16073
 
 
16074
                                /* content-length */
 
16075
                                if(l == 14 && !strucmp(p,"content-length")){
 
16076
                                    while(*q && isdigit((unsigned char) *q))
 
16077
                                      buffer_len = ((buffer_len * 10) + (*q++ - '0'));
 
16078
 
 
16079
                                    if(*q)
 
16080
                                      break;
 
16081
                                }
 
16082
                                else if(l == 12 && !strucmp(p, "content-type")
 
16083
                                        && strucmp(q,"text/xml")
 
16084
                                        && strucmp(q,"application/xhtml+xml")
 
16085
                                        && strucmp(q,"application/xml")){
 
16086
                                    break;
 
16087
                                }
 
16088
                                /* SHOULD: if(l == 7 && !strucmp(p, "expires")) */
 
16089
                            }
 
16090
                        }
 
16091
 
 
16092
                        fs_give((void **) &p);
 
16093
                    }
 
16094
                }
 
16095
                else{
 
16096
                    Tcl_SetResult(interp, "RSS send failure", TCL_STATIC);
 
16097
                    peRssComponentFree(&scheme,&loc,&path,&parms,&query,&frag);
 
16098
                }
 
16099
 
 
16100
                tcp_close(tcp_stream);
 
16101
                mail_parameters(NULL, SET_READTIMEOUT, (void *)(long) 60);
 
16102
                peRssComponentFree(&scheme,&loc,&path,&parms,&query,&frag);
 
16103
 
 
16104
                if(feed_so){
 
16105
                    buffer = (char *) so_text(feed_so);
 
16106
                    buffer_len = (int) so_tell(feed_so);
 
16107
                }
 
16108
 
 
16109
                if(buffer){
 
16110
                    RSS_FEED_S *feed;
 
16111
                    char       *err;
 
16112
                    STORE_S    *bucket;
 
16113
                    gf_io_t     gc, pc;
 
16114
 
 
16115
                    /* grok response */
 
16116
                    bucket = so_get(CharStar, NULL, EDIT_ACCESS);
 
16117
                    gf_set_readc(&gc, buffer, buffer_len, CharStar, 0);
 
16118
                    gf_set_so_writec(&pc, bucket);
 
16119
                    gf_filter_init();
 
16120
                    gf_link_filter(gf_html2plain, gf_html2plain_rss_opt(&feed,0));
 
16121
                    if((err = gf_pipe(gc, pc)) != NULL){
 
16122
                        gf_html2plain_rss_free(&feed);
 
16123
                        Tcl_SetResult(interp, "RSS connection failure", TCL_STATIC);
 
16124
                    }
 
16125
 
 
16126
                    if(feed_so)
 
16127
                      so_give(&feed_so);
 
16128
 
 
16129
                    so_give(&bucket);
 
16130
                    fs_give((void **) &buffer);
 
16131
                    return(feed);
 
16132
                }
 
16133
                else
 
16134
                  Tcl_SetResult(interp, "RSS response error", TCL_STATIC);
 
16135
            }
 
16136
            else
 
16137
              Tcl_SetResult(interp, "RSS connection failure", TCL_STATIC);
 
16138
        }
 
16139
        else
 
16140
          Tcl_SetResult(interp, "RSS feed missing scheme", TCL_STATIC);
 
16141
    }
 
16142
    else
 
16143
      Tcl_SetResult(interp, "No RSS Feed Defined", TCL_STATIC);
 
16144
 
 
16145
    return(NULL);
 
16146
}
 
16147
 
 
16148
 
 
16149
void
 
16150
peRssComponentFree(char **scheme,char **loc,char **path,char **parms,char **query,char **frag)
 
16151
{
 
16152
    if(scheme) fs_give((void **) scheme);
 
16153
    if(loc) fs_give((void **) loc);
 
16154
    if(path) fs_give((void **) path);
 
16155
    if(parms) fs_give((void **) parms);
 
16156
    if(query) fs_give((void **) query);
 
16157
    if(frag) fs_give((void **) frag);
 
16158
}
 
16159
 
 
16160
void
 
16161
peRssClearCacheEntry(RSS_CACHE_S *entry)
 
16162
{
 
16163
    if(entry){
 
16164
        if(entry->link)
 
16165
          fs_give((void **) &entry->link);
 
16166
 
 
16167
        gf_html2plain_rss_free(&entry->feed);
 
16168
        memset(entry, 0, sizeof(RSS_CACHE_S));
 
16169
    }
 
16170
}