1 /* ========================================================================
2 * Copyright 2006-2008 University of Washington
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * ========================================================================
13 /* ========================================================================
14 Implement alpine TCL interfaces. Execute TCL interfaces
15 via interpreter reading commands and writing results over
17 ======================================================================== */
23 #include "../../../c-client/c-client.h"
24 #include "../../../c-client/imap4r1.h"
26 #include "../../../pith/osdep/color.h" /* color support library */
27 #include "../../../pith/osdep/canaccess.h"
28 #include "../../../pith/osdep/temp_nam.h"
29 #include "../../../pith/osdep/collate.h"
30 #include "../../../pith/osdep/filesize.h"
31 #include "../../../pith/osdep/writ_dir.h"
32 #include "../../../pith/osdep/err_desc.h"
34 #include "../../../pith/stream.h"
35 #include "../../../pith/context.h"
36 #include "../../../pith/state.h"
37 #include "../../../pith/msgno.h"
38 #include "../../../pith/debug.h"
39 #include "../../../pith/init.h"
40 #include "../../../pith/conf.h"
41 #include "../../../pith/conftype.h"
42 #include "../../../pith/detoken.h"
43 #include "../../../pith/flag.h"
44 #include "../../../pith/help.h"
45 #include "../../../pith/remote.h"
46 #include "../../../pith/status.h"
47 #include "../../../pith/mailcmd.h"
48 #include "../../../pith/savetype.h"
49 #include "../../../pith/save.h"
50 #include "../../../pith/reply.h"
51 #include "../../../pith/sort.h"
52 #include "../../../pith/ldap.h"
53 #include "../../../pith/addrbook.h"
54 #include "../../../pith/ablookup.h"
55 #include "../../../pith/takeaddr.h"
56 #include "../../../pith/bldaddr.h"
57 #include "../../../pith/copyaddr.h"
58 #include "../../../pith/thread.h"
59 #include "../../../pith/folder.h"
60 #include "../../../pith/mailview.h"
61 #include "../../../pith/indxtype.h"
62 #include "../../../pith/icache.h"
63 #include "../../../pith/mailindx.h"
64 #include "../../../pith/mailpart.h"
65 #include "../../../pith/mimedesc.h"
66 #include "../../../pith/detach.h"
67 #include "../../../pith/newmail.h"
68 #include "../../../pith/charset.h"
69 #include "../../../pith/util.h"
70 #include "../../../pith/rfc2231.h"
71 #include "../../../pith/string.h"
72 #include "../../../pith/send.h"
73 #include "../../../pith/options.h"
74 #include "../../../pith/list.h"
75 #include "../../../pith/mimetype.h"
76 #include "../../../pith/mailcap.h"
77 #include "../../../pith/sequence.h"
78 #include "../../../pith/smime.h"
79 #include "../../../pith/url.h"
80 #include "../../../pith/charconv/utf8.h"
93 * Fake screen dimension for word wrap and such
95 #define FAKE_SCREEN_WIDTH 80
96 #define FAKE_SCREEN_LENGTH 24
99 * Arbitrary minimum display width (in characters)
101 #define MIN_SCREEN_COLS 20
105 * Maximum number of lines allowed in signatures
107 #define SIG_MAX_LINES 24
108 #define SIG_MAX_COLS 1024
112 * Number of seconds we'll wait before we assume the client has wondered
113 * on to more interesting content
115 #define PE_INPUT_TIMEOUT 1800
119 * Posting error length max
121 #define WP_MAX_POST_ERROR 128
125 * AUTH Response Tokens
127 #define AUTH_EMPTY_STRING "NOPASSWD"
128 #define AUTH_FAILURE_STRING "BADPASSWD"
131 * CERT Response Tokens
133 #define CERT_QUERY_STRING "CERTQUERY"
134 #define CERT_FAILURE_STRING "CERTFAIL"
138 * Charset used within alpined and to communicate with alpined
139 * Note: posting-charset still respected
141 #define WP_INTERNAL_CHARSET "UTF-8"
145 * Globals referenced throughout pine...
147 struct pine
*wps_global
; /* THE global variable! */
153 long gPeITop
, gPeICount
;
155 long gPeInputTimeout
= PE_INPUT_TIMEOUT
;
156 long gPEAbandonTimeout
= 0;
160 * Authorization issues
162 int peNoPassword
, peCredentialError
;
163 int peCertFailure
, peCertQuery
;
164 char peCredentialRequestor
[CRED_REQ_SIZE
];
170 CONTEXT_S
*config_context_list
;
172 STRLIST_S
*peCertHosts
;
174 bitmap_t changed_feature_list
;
175 #define F_CH_ON(feature) (bitnset((feature),changed_feature_list))
176 #define F_CH_OFF(feature) (!F_CH_ON(feature))
177 #define F_CH_TURN_ON(feature) (setbitn((feature),changed_feature_list))
178 #define F_CH_TURN_OFF(feature) (clrbitn((feature),changed_feature_list))
179 #define F_CH_SET(feature,value) ((value) ? F_CH_TURN_ON((feature)) \
180 : F_CH_TURN_OFF((feature)))
183 typedef struct _status_msg
{
189 struct _status_msg
*next
;
192 static STATMSG_S
*peStatList
;
194 typedef struct _composer_attachment
{
215 struct _composer_attachment
*next
;
218 static COMPATT_S
*peCompAttach
;
223 typedef struct _msg_data
{
231 int postop_fcc_no_attach
;
234 int (*postfunc
)(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *);
237 unsigned qualified_addrs
:1;
242 * locally global structure to keep track of various bits of state
243 * needed to collect filtered output
245 static struct _embedded_data
{
266 typedef struct _rss_cache_s
{
273 #define RSS_NEWS_CACHE_SIZE 1
274 #define RSS_WEATHER_CACHE_SIZE 1
278 WPLDAP_S
*wpldap_global
;
282 * random string generator flags
284 #define PRS_NONE 0x0000
285 #define PRS_LOWER_CASE 0x0001
286 #define PRS_UPPER_CASE 0x0002
287 #define PRS_MIXED_CASE 0x0004
290 * peSaveWork flag definitions
292 #define PSW_NONE 0x00
293 #define PSW_COPY 0x01
294 #define PSW_MOVE 0x02
297 * Message Collector flags
299 #define PMC_NONE 0x00
300 #define PMC_FORCE_QUAL 0x01
301 #define PMC_PRSRV_ATT 0x02
304 * length of thread info string
306 #define WP_MAX_THRD_S 64
309 * static buf size for putenv() if necessary
311 #define PUTENV_MAX 64
315 /*----------------------------------------------------------------------
316 General use big buffer. It is used in the following places:
317 compose_mail: while parsing header of postponed message
318 append_message2: while writing header into folder
319 q_status_messageX: while doing printf formatting
320 addr_book: Used to return expanded address in. (Can only use here
321 because mm_log doesn't q_status on PARSE errors !)
322 alpine.c: When address specified on command line
323 init.c: When expanding variable values
324 and many many more...
327 char wtmp_20k_buf
[20480];
332 /* Internal prototypes */
333 void peReturn(int, char *, const char *);
334 int peWrite(int, char *);
335 char *peCreateUserContext(Tcl_Interp
*, char *, char *, char *);
336 void peDestroyUserContext(struct pine
**);
337 char *peLoadConfig(struct pine
*);
338 int peCreateStream(Tcl_Interp
*, CONTEXT_S
*, char *, int);
339 void peDestroyStream(struct pine
*);
340 void pePrepareForAuthException(void);
341 char *peAuthException(void);
342 void peInitVars(struct pine
*);
343 int peSelect(Tcl_Interp
*, int, Tcl_Obj
**, int);
344 int peSelectNumber(Tcl_Interp
*, int, Tcl_Obj
**, int);
345 int peSelectDate(Tcl_Interp
*, int, Tcl_Obj
**, int);
346 int peSelectText(Tcl_Interp
*, int, Tcl_Obj
**, int);
347 int peSelectStatus(Tcl_Interp
*, int, Tcl_Obj
**, int);
348 char *peSelValTense(Tcl_Obj
*);
349 char *peSelValYear(Tcl_Obj
*);
350 char *peSelValMonth(Tcl_Obj
*);
351 char *peSelValDay(Tcl_Obj
*);
352 int peSelValCase(Tcl_Obj
*);
353 int peSelValField(Tcl_Obj
*);
354 int peSelValFlag(Tcl_Obj
*);
355 int peSelected(Tcl_Interp
*, int, Tcl_Obj
**, int);
356 int peSelectError(Tcl_Interp
*, char *);
357 int peApply(Tcl_Interp
*, int, Tcl_Obj
**);
358 char *peApplyFlag(MAILSTREAM
*, MSGNO_S
*, char, int, long *);
359 int peApplyError(Tcl_Interp
*, char *);
360 int peIndexFormat(Tcl_Interp
*);
361 int peAppendIndexParts(Tcl_Interp
*, imapuid_t
, Tcl_Obj
*, int *);
362 int peAppendIndexColor(Tcl_Interp
*, imapuid_t
, Tcl_Obj
*, int *);
363 int peMessageStatusBits(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
364 char *peMsgStatBitString(struct pine
*, MAILSTREAM
*, MSGNO_S
*, long, long, long, int *);
365 Tcl_Obj
*peMsgStatNameList(Tcl_Interp
*, struct pine
*, MAILSTREAM
*, MSGNO_S
*, long, long, long, int *);
366 int peNewMailResult(Tcl_Interp
*);
367 int peMessageSize(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
368 int peMessageDate(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
369 int peMessageSubject(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
370 int peMessageFromAddr(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
371 int peMessageToAddr(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
372 int peMessageCcAddr(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
373 int peMessageField(Tcl_Interp
*, imapuid_t
, char *);
374 int peMessageStatus(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
375 int peMessageCharset(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
376 int peMessageBounce(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
377 int peMessageSpamNotice(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
378 char *peSendSpamReport(long, char *, char *, char *);
379 int peMsgnoFromUID(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
380 int peMessageText(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
381 int peMessageHeader(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
382 void peFormatEnvelope(MAILSTREAM
*, long, char *, ENVELOPE
*, gf_io_t
, long, char *, int);
383 void peFormatEnvelopeAddress(MAILSTREAM
*, long, char *, char *, ADDRESS
*, int, char *, gf_io_t
);
384 void peFormatEnvelopeNewsgroups(char *, char *, int, gf_io_t
);
385 void peFormatEnvelopeText(char *, char *);
386 int peMessageAttachments(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
387 int peMessageBody(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
388 int peMessagePartFromCID(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
389 int peLocateBodyByCID(char *, char *, BODY
*);
390 char *peColorStr(char *, char *);
391 int peInterpWritec(int);
392 int peInterpFlush(void);
393 int peNullWritec(int);
394 void peGetMimeTyping(BODY
*, Tcl_Obj
**, Tcl_Obj
**, Tcl_Obj
**, Tcl_Obj
**);
395 int peGetFlag(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
396 int peIsFlagged(MAILSTREAM
*, imapuid_t
, char *);
397 int peSetFlag(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
398 int peMsgSelect(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
399 int peReplyHeaders(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
400 int peAppListF(Tcl_Interp
*, Tcl_Obj
*, char *, ...);
401 void pePatAppendID(Tcl_Interp
*, Tcl_Obj
*, PAT_S
*);
402 void pePatAppendPattern(Tcl_Interp
*, Tcl_Obj
*, PAT_S
*);
403 char *pePatStatStr(int);
404 int peReplyText(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
405 int peSoStrToList(Tcl_Interp
*, Tcl_Obj
*, STORE_S
*);
406 int peForwardHeaders(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
407 int peForwardText(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
408 int peDetach(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
409 int peAttachInfo(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
410 int peSaveDefault(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
411 int peSaveWork(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**, long);
412 int peSave(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
413 int peCopy(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
414 int peMove(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
415 int peGotoDefault(Tcl_Interp
*, imapuid_t
, Tcl_Obj
**);
416 int peTakeaddr(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
417 int peTakeFrom(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
418 int peAddSuggestedContactInfo(Tcl_Interp
*, Tcl_Obj
*, ADDRESS
*);
419 int peReplyQuote(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
420 long peMessageNumber(imapuid_t
);
421 long peSequenceNumber(imapuid_t
);
422 int peMsgCollector(Tcl_Interp
*, int, Tcl_Obj
**,
423 int (*)(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *), long);
424 int peMsgCollected(Tcl_Interp
*, MSG_COL_S
*, char *, long);
425 void peMsgSetParm(PARAMETER
**, char *, char *);
426 Tcl_Obj
*peMsgAttachCollector(Tcl_Interp
*, BODY
*);
427 int peFccAppend(Tcl_Interp
*, Tcl_Obj
*, char *, int);
428 int peDoPost(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *);
429 int peDoPostpone(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *);
430 int peWriteSig (Tcl_Interp
*, char *, Tcl_Obj
**);
431 int peInitAddrbooks(Tcl_Interp
*, int);
432 int peRuleStatVal(char *, int *);
433 int peRuleSet(Tcl_Interp
*, Tcl_Obj
**);
434 int peAppendCurrentSort(Tcl_Interp
*interp
);
435 int peAppendDefaultSort(Tcl_Interp
*interp
);
437 ADDRESS
*peAEToAddress(AdrBk_Entry
*);
438 char *peAEFcc(AdrBk_Entry
*);
440 NAMEVAL_S
*sort_key_rules(int);
441 NAMEVAL_S
*wp_indexheight_rules(int);
442 PINEFIELD
*peCustomHdrs(void);
443 STATMSG_S
*sml_newmsg(int, char *);
444 char *sml_getmsg(void);
445 char **sml_getmsgs(void);
448 int peLdapQueryResults(Tcl_Interp
*);
449 int peLdapStrlist(Tcl_Interp
*, Tcl_Obj
*, struct berval
**);
450 int init_ldap_pname(struct pine
*);
451 #endif /* ENABLE_LDAP */
452 char *strqchr(char *, int, int *, int);
453 Tcl_Obj
*wp_prune_folders(CONTEXT_S
*, char *, int, char *,
454 unsigned, int *, int, Tcl_Interp
*);
455 int hex_colorstr(char *, char *);
457 int ascii_colorstr(char *, char *);
458 COMPATT_S
*peNewAttach(void);
459 void peFreeAttach(COMPATT_S
**);
460 COMPATT_S
*peGetAttachID(char *);
461 char *peFileAttachID(char *, char *, char *, char *, char *, int);
462 char *peBodyAttachID(BODY
*);
463 void peBodyMoveContents(BODY
*, BODY
*);
464 int peClearAttachID(char *);
465 char *peRandomString(char *, int, int);
466 void ms_init(STRING
*, void *, unsigned long);
467 char ms_next(STRING
*);
468 void ms_setpos(STRING
*, unsigned long);
469 long peAppendMsg(MAILSTREAM
*, void *, char **, char **, STRING
**);
470 int remote_pinerc_failure(void);
471 char *peWebAlpinePrefix(void);
472 void peNewMailAnnounce(MAILSTREAM
*, long, long);
473 int peMessageNeedPassphrase(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
474 int peRssReturnFeed(Tcl_Interp
*, char *, char *);
475 int peRssPackageFeed(Tcl_Interp
*, RSS_FEED_S
*);
476 RSS_FEED_S
*peRssFeed(Tcl_Interp
*, char *, char *);
477 RSS_FEED_S
*peRssFetch(Tcl_Interp
*, char *);
478 void peRssComponentFree(char **,char **,char **,char **,char **,char **);
479 void peRssClearCacheEntry(RSS_CACHE_S
*);
482 /* Prototypes for Tcl-exported methods */
483 int PEInit(Tcl_Interp
*interp
, char *);
484 void PEExitCleanup(ClientData
);
485 int PEInfoCmd(ClientData clientData
, Tcl_Interp
*interp
,
486 int objc
, Tcl_Obj
*CONST objv
[]);
487 int PEConfigCmd(ClientData clientData
, Tcl_Interp
*interp
,
488 int objc
, Tcl_Obj
*CONST objv
[]);
489 int PEDebugCmd(ClientData clientData
, Tcl_Interp
*interp
,
490 int objc
, Tcl_Obj
*CONST objv
[]);
491 int PESessionCmd(ClientData clientData
, Tcl_Interp
*interp
,
492 int objc
, Tcl_Obj
*CONST objv
[]);
493 int PEMailboxCmd(ClientData clientData
, Tcl_Interp
*interp
,
494 int objc
, Tcl_Obj
*CONST objv
[]);
495 int PEThreadCmd(ClientData clientData
, Tcl_Interp
*interp
,
496 int objc
, Tcl_Obj
*CONST objv
[]);
497 int PEMessageCmd(ClientData clientData
, Tcl_Interp
*interp
,
498 int objc
, Tcl_Obj
*CONST objv
[]);
499 int PEFolderCmd(ClientData clientData
, Tcl_Interp
*interp
,
500 int objc
, Tcl_Obj
*CONST objv
[]);
501 int PEComposeCmd(ClientData clientData
, Tcl_Interp
*interp
,
502 int objc
, Tcl_Obj
*CONST objv
[]);
503 int PEPostponeCmd(ClientData clientData
, Tcl_Interp
*interp
,
504 int objc
, Tcl_Obj
*CONST objv
[]);
505 int PEAddressCmd(ClientData clientData
, Tcl_Interp
*interp
,
506 int objc
, Tcl_Obj
*CONST objv
[]);
507 int PEClistCmd(ClientData clientData
, Tcl_Interp
*interp
,
508 int objc
, Tcl_Obj
*CONST objv
[]);
509 int PELdapCmd(ClientData clientData
, Tcl_Interp
*interp
,
510 int objc
, Tcl_Obj
*CONST objv
[]);
511 int PERssCmd(ClientData clientData
, Tcl_Interp
*interp
,
512 int objc
, Tcl_Obj
*CONST objv
[]);
515 typedef struct append_pkg
{
516 MAILSTREAM
*stream
; /* source stream */
517 unsigned long msgno
; /* current message number */
518 unsigned long msgmax
; /* maximum message number */
519 char *flags
; /* current flags */
520 char *date
; /* message internal date */
521 STRING
*message
; /* stringstruct of message */
524 STRINGDRIVER mstring
= {
525 ms_init
, /* initialize string structure */
526 ms_next
, /* get next byte in string structure */
527 ms_setpos
/* set position in string structure */
531 /*----------------------------------------------------------------------
532 main routine -- entry point
534 Args: argv, argc -- The command line arguments
537 Setup c-client drivers and dive into TCL interpreter engine
542 main(int argc
, char *argv
[])
544 int ev
= 1, s
, cs
, n
, co
, o
, l
, bl
= 256, argerr
;
545 char *buf
, sname
[256];
546 struct sockaddr_un name
;
549 extern AUTHENTICATOR auth_gss_proxy
;
552 srandom(getpid() + time(0));
554 /*----------------------------------------------------------------------
556 ----------------------------------------------------------------------*/
559 * NO LOCAL DRIVERS ALLOWED
560 * For this to change pintecld *MUST* be running under the user's UID and
561 * and signal.[ch] need to get fixed to handle KOD rather than change
564 mail_link (&imapdriver
); /* link in the imap driver */
565 mail_link (&unixdriver
); /* link in the unix driver */
566 mail_link (&dummydriver
); /* link in the dummy driver */
568 /* link authentication drivers */
570 auth_link (&auth_gss_proxy
); /* pubcoookie proxy authenticator */
572 auth_link (&auth_md5
); /* link in the md5 authenticator */
573 auth_link (&auth_pla
);
574 auth_link (&auth_log
); /* link in the log authenticator */
576 mail_parameters (NIL
,SET_DISABLEPLAINTEXT
,(void *) 2);
579 /* if REMOTE_USER set, use it as username */
580 if(buf
= getenv("REMOTE_USER"))
581 env_init(buf
, "/tmp");
584 if(!mail_parameters(NULL
, DISABLE_DRIVER
, "unix")){
585 fprintf(stderr
, "Can't disable unix driver");
590 * Set network timeouts so we don't hang forever
591 * The open timeout can be pretty short since we're
592 * just opening tcp connection. The read timeout needs
593 * to be longer because the response to some actions can
594 * take awhile. Hopefully this is well within httpd's
595 * cgi timeout threshold.
597 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long) 30);
598 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long) 60);
600 /*----------------------------------------------------------------------
601 Initialize pith library
602 ----------------------------------------------------------------------*/
603 pith_opt_remote_pinerc_failure
= remote_pinerc_failure
;
604 pith_opt_user_agent_prefix
= peWebAlpinePrefix
;
605 pith_opt_newmail_announce
= peNewMailAnnounce
;
607 setup_for_index_index_screen();
610 /*----------------------------------------------------------------------
612 ----------------------------------------------------------------------*/
614 for(argerr
= 0; !argerr
&& ((n
= getopt(argc
,argv
,"d")) != -1); ) {
616 case 'd' : debug
++; break;
617 case '?' : argerr
= 1; break;
621 if(argerr
|| optind
!= argc
){
622 char *p
= strrchr(argv
[0],'/');
623 fprintf(stderr
, "Usage: %s [-d]\n", p
? p
+ 1 : argv
[0]);
627 /*----------------------------------------------------------------------
628 Hop into the Tcl processing loop
629 ----------------------------------------------------------------------*/
631 buf
= (char *) fs_get(bl
* sizeof(char));
633 if(fgets(sname
, 255, stdin
) && *sname
){
634 if(sname
[l
= strlen(sname
) - 1] == '\n')
637 if((s
= socket(AF_UNIX
, SOCK_STREAM
, 0)) != -1){
639 name
.sun_family
= AF_UNIX
;
640 strcpy(name
.sun_path
, peSocketName
= sname
);
643 if(bind(s
, (struct sockaddr
*) &name
, l
) == 0){
644 if(listen(s
, 5) == 0){
646 * after the groundwork's done, go into the background.
647 * the fork saves the caller from invoking us in the background
648 * which introduces a timing race between the first client
649 * request arrival and our being prepared to accept it.
653 case -1 : /* error */
658 close(0); /* disassociate */
664 default : /* parent */
670 dprint((SYSDBG_INFO
, "started"));
672 interp
= Tcl_CreateInterp();
674 PEInit(interp
, sname
);
682 tv
.tv_sec
= (gPEAbandonTimeout
) ? gPEAbandonTimeout
: gPeInputTimeout
;
684 if((n
= select(s
+1, &rfd
, 0, 0, &tv
)) > 0){
687 gPEAbandonTimeout
= 0;
689 if((cs
= accept(s
, (struct sockaddr
*) &name
, &ll
)) == -1){
690 dprint((SYSDBG_ERR
, "accept failure: %s",
691 error_description(errno
)));
695 dprint((5, "accept success: %d", cs
));
698 * tcl commands are prefixed with a number representing
699 * the length of the command string and a newline character.
700 * the characters representing the length and the newline
701 * are not included in the command line length calculation.
704 while((n
= read(cs
, buf
+ o
, bl
- o
- 1)) > 0){
709 for(i
= 0; i
< o
; i
++)
715 fs_resize((void **) &buf
, bl
* sizeof(char));
721 x
= (x
* 10) + (buf
[i
] - '0');
729 dprint((SYSDBG_ERR
, "read EOF"));
732 dprint((SYSDBG_ERR
, "read failure: %s", error_description(errno
)));
737 /* Log every Eval if somebody *really* wants to see it. */
740 int dlim
= (debug
>= 9) ? 256 : 5120 - 32;
742 snprintf(dbuf
, sizeof(dbuf
), "Tcl_Eval(%.*s)", dlim
, &buf
[co
]);
744 /* But DON'T log any clear-text credentials */
748 && !strncmp(dbuf
+ 12, "ession creds ", 13)){
751 for(p
= &dbuf
[25]; *p
; p
++)
758 switch(Tcl_Eval(interp
, &buf
[co
])){
759 case TCL_OK
: peReturn(cs
, "OK", Tcl_GetStringResult(interp
)); break;
760 case TCL_ERROR
: peReturn(cs
, "ERROR", Tcl_GetStringResult(interp
)); break;
761 case TCL_BREAK
: peReturn(cs
, "BREAK", Tcl_GetStringResult(interp
)); break;
762 case TCL_RETURN
: peReturn(cs
, "RETURN", Tcl_GetStringResult(interp
)); break;
763 default : peReturn(cs
, "BOGUS", "eval returned unexpected value"); break;
769 else if(errno
!= EINTR
){
771 dprint((SYSDBG_ALERT
, "select failure: %s", error_description(errno
)));
774 dprint((SYSDBG_INFO
, "timeout after %d seconds", tv
.tv_sec
));
779 /* Tcl_Exit should never return. Getting here is an error. */
780 dprint((SYSDBG_ERR
, "Tcl_Exit failure"));
797 fprintf(stderr
, "Can't read socket name\n");
804 * peReturn - common routine to return TCL result
807 peReturn(int sock
, char *status
, const char *result
)
809 if(peWrite(sock
, status
))
810 if(peWrite(sock
, "\n"))
811 peWrite(sock
, (char *) result
);
815 * peWrite - write all the given string on the given socket
818 peWrite(int sock
, char *s
)
822 for(i
= 0, n
= strlen(s
); n
; n
= n
- i
)
823 if((i
= write(sock
, s
+ i
, n
)) < 0){
824 dprint((SYSDBG_ERR
, "write: %s", error_description(errno
)));
832 * PEInit - Initialize exported TCL functions
835 PEInit(Tcl_Interp
*interp
, char *sname
)
837 dprint((2, "PEInit: %s", sname
));
839 if(Tcl_Init(interp
) == TCL_ERROR
) {
843 Tcl_CreateObjCommand(interp
, "PEInfo", PEInfoCmd
,
844 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
846 Tcl_CreateObjCommand(interp
, "PEConfig", PEConfigCmd
,
847 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
849 Tcl_CreateObjCommand(interp
, "PEDebug", PEDebugCmd
,
850 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
852 Tcl_CreateObjCommand(interp
, "PESession", PESessionCmd
,
853 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
855 Tcl_CreateObjCommand(interp
, "PEFolder", PEFolderCmd
,
856 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
858 Tcl_CreateObjCommand(interp
, "PEMailbox", PEMailboxCmd
,
859 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
861 Tcl_CreateObjCommand(interp
, "PEThread", PEThreadCmd
,
862 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
864 Tcl_CreateObjCommand(interp
, "PEMessage", PEMessageCmd
,
865 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
867 Tcl_CreateObjCommand(interp
, "PECompose", PEComposeCmd
,
868 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
870 Tcl_CreateObjCommand(interp
, "PEPostpone", PEPostponeCmd
,
871 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
873 Tcl_CreateObjCommand(interp
, "PEAddress", PEAddressCmd
,
874 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
876 Tcl_CreateObjCommand(interp
, "PEClist", PEClistCmd
,
877 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
879 Tcl_CreateObjCommand(interp
, "PELdap", PELdapCmd
,
880 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
882 Tcl_CreateObjCommand(interp
, "PERss", PERssCmd
,
883 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
885 Tcl_CreateExitHandler(PEExitCleanup
, sname
);
888 wpldap_global
= (WPLDAP_S
*)fs_get(sizeof(WPLDAP_S
));
889 wpldap_global
->query_no
= 0;
890 wpldap_global
->ldap_search_list
= NULL
;
891 #endif /* ENABLE_LDAP */
898 PEExitCleanup(ClientData clientData
)
900 dprint((4, "PEExitCleanup"));
903 /* destroy any open stream */
904 peDestroyStream(wps_global
);
906 /* destroy user context */
907 peDestroyUserContext(&wps_global
);
912 if(wpldap_global
->ldap_search_list
)
913 free_wpldapres(wpldap_global
->ldap_search_list
);
914 fs_give((void **)&wpldap_global
);
916 #endif /* ENABLE_LDAP */
918 if((char *) clientData
)
919 unlink((char *) clientData
);
921 peFreeAttach(&peCompAttach
);
923 dprint((SYSDBG_INFO
, "finished"));
928 * PEInfoCmd - export various bits of alpine state
931 PEInfoCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
933 char *err
= "Unknown PEInfo request";
935 dprint((2, "PEInfoCmd"));
938 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
941 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
944 if(!strcmp(s1
, "colorset")){
945 char *varname
, *fghex
, *bghex
;
946 char tvname
[256], asciicolor
[256];
947 struct variable
*vtmp
;
950 SPEC_COLOR_S
*hcolors
, *thc
;
952 if(!(varname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
953 Tcl_SetResult(interp
, "colorset: can't read variable name", TCL_STATIC
);
957 if(!strcmp(varname
, "viewer-hdr-colors")){
958 char *newhdr
= NULL
, *newpat
= NULL
, *utype
;
962 Tcl_SetResult(interp
, "colorset: too few view-hdr args", TCL_STATIC
);
966 hcolors
= spec_colors_from_varlist(wps_global
->VAR_VIEW_HDR_COLORS
, 0);
967 if(!(utype
= Tcl_GetStringFromObj(objv
[3], NULL
))){
968 Tcl_SetResult(interp
, "colorset: can't read operation", TCL_STATIC
);
972 if(!strcmp(utype
, "delete")){
974 Tcl_SetResult(interp
, "colorset: no viewer-hdrs to delete", TCL_STATIC
);
978 if(Tcl_GetIntFromObj(interp
, objv
[4], &hindex
) == TCL_ERROR
){
979 Tcl_SetResult(interp
, "colorset: can't read index", TCL_STATIC
);
985 hcolors
= hcolors
->next
;
987 free_spec_colors(&thc
);
991 for(thc
= hcolors
, i
= 1; thc
&& i
< hindex
; thc
= thc
->next
, i
++)
994 if(thc
&& thc
->next
){
995 SPEC_COLOR_S
*thc2
= thc
->next
;
997 thc
->next
= thc2
->next
;
999 free_spec_colors(&thc2
);
1002 Tcl_SetResult(interp
, "colorset: invalid index", TCL_STATIC
);
1007 else if(!strcmp(utype
, "add")){
1009 Tcl_SetResult(interp
, "colorset: wrong number of view-hdr add args", TCL_STATIC
);
1013 if(Tcl_ListObjGetElements(interp
, objv
[4], &cObjc
, &cObj
) != TCL_OK
)
1017 Tcl_SetResult(interp
, "colorset: wrong number of hdrs for view-hdr add", TCL_STATIC
);
1021 newhdr
= Tcl_GetStringFromObj(cObj
[0], NULL
);
1022 newpat
= Tcl_GetStringFromObj(cObj
[1], NULL
);
1023 if(Tcl_ListObjGetElements(interp
, objv
[5], &cObjc
, &cObj
) != TCL_OK
)
1027 Tcl_SetResult(interp
, "colorset: wrong number of colors for view-hdr add", TCL_STATIC
);
1031 fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
);
1032 bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
);
1033 if(newhdr
&& newpat
&& fghex
&& bghex
){
1036 for(hcp
= &hcolors
; *hcp
!= NULL
; hcp
= &(*hcp
)->next
)
1039 *hcp
= (SPEC_COLOR_S
*)fs_get(sizeof(SPEC_COLOR_S
));
1040 (*hcp
)->inherit
= 0;
1041 (*hcp
)->spec
= cpystr(newhdr
);
1042 (*hcp
)->fg
= cpystr((ascii_colorstr(asciicolor
, fghex
) == 0) ? asciicolor
: "black");
1043 (*hcp
)->bg
= cpystr((ascii_colorstr(asciicolor
, bghex
) == 0) ? asciicolor
: "white");
1045 if(newpat
&& *newpat
)
1046 (*hcp
)->val
= string_to_pattern(newpat
);
1050 (*hcp
)->next
= NULL
;
1053 Tcl_SetResult(interp
, "colorset: invalid args for view-hdr add", TCL_STATIC
);
1057 else if(!strcmp(utype
, "update")){
1059 Tcl_SetResult(interp
, "colorset: wrong number of view-hdr update args", TCL_STATIC
);
1063 if(!(Tcl_ListObjGetElements(interp
, objv
[4], &cObjc
, &cObj
) == TCL_OK
1065 && Tcl_GetIntFromObj(interp
, cObj
[0], &hindex
) == TCL_OK
1066 && (newhdr
= Tcl_GetStringFromObj(cObj
[1], NULL
))
1067 && (newpat
= Tcl_GetStringFromObj(cObj
[2], NULL
)))){
1068 Tcl_SetResult(interp
, "colorset: view-hdr update can't read index or header", TCL_STATIC
);
1072 if(!(Tcl_ListObjGetElements(interp
, objv
[5], &cObjc
, &cObj
) == TCL_OK
1074 && (fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
))
1075 && (bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
)))){
1076 Tcl_SetResult(interp
, "colorset: view-hdr update can't read colors", TCL_STATIC
);
1080 for(thc
= hcolors
, i
= 0; thc
&& i
< hindex
; thc
= thc
->next
, i
++)
1084 Tcl_SetResult(interp
, "colorset: view-hdr update invalid index", TCL_STATIC
);
1089 fs_give((void **)&thc
->spec
);
1091 thc
->spec
= cpystr(newhdr
);
1092 if(ascii_colorstr(asciicolor
, fghex
) == 0) {
1094 fs_give((void **)&thc
->fg
);
1096 thc
->fg
= cpystr(asciicolor
);
1099 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid foreground color value %.100s", fghex
);
1100 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1104 if(ascii_colorstr(asciicolor
, bghex
) == 0) {
1106 fs_give((void **)&thc
->bg
);
1108 thc
->bg
= cpystr(asciicolor
);
1111 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
1112 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1117 fs_give((void **)&thc
->val
);
1119 if(newpat
&& *newpat
){
1120 thc
->val
= string_to_pattern(newpat
);
1124 Tcl_SetResult(interp
, "colorset: unknown operation", TCL_STATIC
);
1128 vtmp
= &wps_global
->vars
[V_VIEW_HDR_COLORS
];
1129 for(i
= 0; vtmp
->main_user_val
.l
&& vtmp
->main_user_val
.l
[i
]; i
++)
1130 fs_give((void **)&vtmp
->main_user_val
.l
[i
]);
1132 if(vtmp
->main_user_val
.l
)
1133 fs_give((void **)&vtmp
->main_user_val
.l
);
1135 vtmp
->main_user_val
.l
= varlist_from_spec_colors(hcolors
);
1136 set_current_val(vtmp
, FALSE
, FALSE
);
1137 free_spec_colors(&hcolors
);
1142 Tcl_SetResult(interp
, "colorset: Wrong number of args", TCL_STATIC
);
1146 if(!(Tcl_ListObjGetElements(interp
, objv
[3], &cObjc
, &cObj
) == TCL_OK
1148 && (fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
))
1149 && (bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
)))){
1150 Tcl_SetResult(interp
, "colorset: Problem reading fore/back ground colors", TCL_STATIC
);
1154 snprintf(tvname
, sizeof(tvname
), "%.200s-foreground-color", varname
);
1155 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
1156 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
1160 if(!vtmp
->name
|| vtmp
->is_list
){
1161 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
1162 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1166 if(ascii_colorstr(asciicolor
, fghex
) == 0) {
1167 if(vtmp
->main_user_val
.p
)
1168 fs_give((void **)&vtmp
->main_user_val
.p
);
1170 vtmp
->main_user_val
.p
= cpystr(asciicolor
);
1171 set_current_val(vtmp
, FALSE
, FALSE
);
1172 if(!strucmp(varname
, "normal"))
1173 pico_set_fg_color(asciicolor
);
1176 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid color value %.100s", fghex
);
1177 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1181 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-background-color");
1183 if((vtmp
->name
&& strucmp(vtmp
->name
, tvname
)) || !vtmp
->name
)
1184 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
1185 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
1189 if(!vtmp
->name
|| vtmp
->is_list
){
1190 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
1191 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1195 if(ascii_colorstr(asciicolor
, bghex
) == 0) {
1196 if(vtmp
->main_user_val
.p
)
1197 fs_give((void **)&vtmp
->main_user_val
.p
);
1199 vtmp
->main_user_val
.p
= cpystr(asciicolor
);
1200 set_current_val(vtmp
, FALSE
, FALSE
);
1201 if(!strucmp(varname
, "normal"))
1202 pico_set_bg_color(asciicolor
);
1205 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
1206 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1210 Tcl_SetResult(interp
, "1", TCL_STATIC
);
1214 else if(!strcmp(s1
, "lappend")){
1219 if((dObj
= Tcl_ObjGetVar2(interp
, objv
[2], NULL
, TCL_LEAVE_ERR_MSG
)) != NULL
){
1220 for(i
= 3; i
< objc
; i
++)
1221 if(Tcl_ListObjAppendElement(interp
, dObj
, objv
[i
]) != TCL_OK
)
1229 err
= "PEInfo lappend: Unknown list name";
1232 err
= "PEInfo lappend: Too few args";
1235 if(!strcmp(s1
, "version")){
1241 * Returns: string representing Pine version
1244 Tcl_SetResult(interp
, ALPINE_VERSION
, TCL_STATIC
);
1247 else if(!strcmp(s1
, "revision")){
1253 * Returns: string representing Pine SVN revision
1257 Tcl_SetResult(interp
, get_alpine_revision_number(buf
, sizeof(buf
)), TCL_VOLATILE
);
1260 else if(!strcmp(s1
, "key")){
1261 static char key
[64];
1264 peRandomString(key
,32,PRS_UPPER_CASE
);
1266 Tcl_SetResult(interp
, key
, TCL_STATIC
);
1269 else if(!strcmp(s1
, "indexheight")){
1270 Tcl_SetResult(interp
, wps_global
->VAR_WP_INDEXHEIGHT
?
1271 wps_global
->VAR_WP_INDEXHEIGHT
: "", TCL_VOLATILE
);
1274 else if(!strcmp(s1
, "indexlines")){
1275 Tcl_SetResult(interp
, wps_global
->VAR_WP_INDEXLINES
?
1276 wps_global
->VAR_WP_INDEXLINES
: "0", TCL_VOLATILE
);
1279 else if(!strcmp(s1
, "aggtabstate")){
1280 Tcl_SetResult(interp
, wps_global
->VAR_WP_AGGSTATE
?
1281 wps_global
->VAR_WP_AGGSTATE
: "0", TCL_VOLATILE
);
1284 else if(!strcmp(s1
, "alpinestate")){
1287 if((wps
= wps_global
->VAR_WP_STATE
) != NULL
){
1288 wps
= p
= q
= cpystr(wps
);
1290 if(*q
== '\\' && *(q
+1) == '$')
1292 while((*p
++ = *q
++) != '\0');
1295 Tcl_SetResult(interp
, wps
? wps
: "", TCL_VOLATILE
);
1298 fs_give((void **) &wps
);
1302 else if(!strcmp(s1
, "foreground")){
1305 if(!((color
= pico_get_last_fg_color())
1306 && (color
= color_to_asciirgb(color
))
1307 && (color
= peColorStr(color
,wtmp_20k_buf
))))
1310 Tcl_SetResult(interp
, color
, TCL_VOLATILE
);
1313 else if(!strcmp(s1
, "background")){
1316 if(!((color
= pico_get_last_bg_color())
1317 && (color
= color_to_asciirgb(color
))
1318 && (color
= peColorStr(color
,wtmp_20k_buf
))))
1321 Tcl_SetResult(interp
, color
, TCL_VOLATILE
);
1324 else if(!strcmp(s1
, "flaglist")){
1330 * BUG: This list should get merged with the static list in "cmd_flag"
1331 * and exported via some function similar to "feature_list()"
1333 static char *flag_list
[] = {
1334 "Important", "New", "Answered", "Deleted", NULL
1340 * Returns: list of FLAGS available for setting
1342 for(i
= 0; (p
= flag_list
[i
]); i
++)
1343 if((itemObj
= Tcl_NewStringObj(p
, -1)) != NULL
){
1344 if(Tcl_ListObjAppendElement(interp
,
1345 Tcl_GetObjResult(interp
),
1352 else if(!strcmp(s1
, "featurelist")){
1354 char *curfeature
, *s
;
1356 Tcl_Obj
*itemObj
, *secObj
= NULL
, *resObj
= NULL
;
1361 * Returns: list of FEATURES available for setting
1363 for(i
= 0, curfeature
= NULL
; (feature
= feature_list(i
)); i
++)
1364 if((s
= feature_list_section(feature
)) != NULL
){
1365 if(!curfeature
|| strucmp(s
, curfeature
)){
1367 Tcl_ListObjAppendElement(interp
,
1370 Tcl_ListObjAppendElement(interp
,
1371 Tcl_GetObjResult(interp
),
1375 secObj
= Tcl_NewListObj(0, NULL
);
1376 resObj
= Tcl_NewListObj(0, NULL
);
1377 if(Tcl_ListObjAppendElement(interp
,
1379 Tcl_NewStringObj(s
,-1)) != TCL_OK
)
1385 if((itemObj
= Tcl_NewStringObj(feature
->name
, -1)) != NULL
){
1386 if(Tcl_ListObjAppendElement(interp
,
1394 Tcl_ListObjAppendElement(interp
, secObj
, resObj
);
1395 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), secObj
);
1400 else if(!strcmp(s1
, "featuresettings")){
1406 * CMD: featuresettings
1408 * Returns: list of FEATURES currently SET
1410 for(i
= 0; (feature
= feature_list(i
)); i
++)
1411 if(feature_list_section(feature
)){
1412 if(F_ON(feature
->id
, wps_global
)){
1413 if((itemObj
= Tcl_NewStringObj(feature
->name
, -1)) != NULL
){
1414 if(Tcl_ListObjAppendElement(interp
,
1415 Tcl_GetObjResult(interp
),
1424 else if(!strcmp(s1
, "signature")){
1427 if((wps_global
->VAR_LITERAL_SIG
1428 || (wps_global
->VAR_SIGNATURE_FILE
1429 && IS_REMOTE(wps_global
->VAR_SIGNATURE_FILE
)))
1430 && (sig
= detoken(NULL
, NULL
, 2, 0, 1, NULL
, NULL
))){
1433 for(p
= sig
; (q
= strindex(p
, '\n')); p
= q
+ 1)
1434 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1435 Tcl_NewStringObj(p
, q
- p
));
1438 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1439 Tcl_NewStringObj(p
, -1));
1441 fs_give((void **) &sig
);
1444 Tcl_SetResult(interp
, "", TCL_STATIC
);
1448 else if(!strcmp(s1
, "rawsig")){
1449 char *err
= NULL
, *sig
= NULL
, *p
, *q
;
1451 if(wps_global
->VAR_LITERAL_SIG
){
1455 if(wps_global
->restricted
){
1456 err
= "Alpine demo can't change config file";
1459 /* BUG: no "exceptions file" support */
1460 if((apval
= APVAL(&wps_global
->vars
[V_LITERAL_SIG
], Main
)) != NULL
){
1461 sig
= (char *) fs_get((strlen(*apval
? *apval
: "") + 1) * sizeof(char));
1463 cstring_to_string(*apval
, sig
);
1466 err
= "Problem accessing configuration";
1469 else if(!IS_REMOTE(wps_global
->VAR_SIGNATURE_FILE
))
1470 snprintf(err
= wtmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote signature file: %s",
1471 wps_global
->VAR_SIGNATURE_FILE
? wps_global
->VAR_SIGNATURE_FILE
: "<null>");
1472 else if(!(sig
= simple_read_remote_file(wps_global
->VAR_SIGNATURE_FILE
, REMOTE_SIG_SUBTYPE
)))
1473 err
= "Can't read remote pinerc";
1476 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
1480 for(p
= sig
; (q
= strindex(p
, '\n')); p
= q
+ 1)
1481 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1482 Tcl_NewStringObj(p
, q
- p
));
1484 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1485 Tcl_NewStringObj(p
, -1));
1486 fs_give((void **) &sig
);
1489 else if(!strcmp(s1
, "statmsg")){
1490 char *s
= sml_getmsg();
1491 /* BUG: can this be removed? */
1493 Tcl_SetResult(interp
, s
? s
: "", TCL_VOLATILE
);
1496 else if(!strcmp(s1
, "statmsgs")){
1497 char **s
= sml_getmsgs();
1498 char **tmps
, *lmsg
= NULL
;
1500 for(tmps
= s
; tmps
&& *tmps
; lmsg
= *tmps
++)
1501 if(!lmsg
|| strcmp(lmsg
, *tmps
))
1502 Tcl_ListObjAppendElement(interp
,
1503 Tcl_GetObjResult(interp
),
1504 Tcl_NewStringObj(*tmps
, -1));
1506 fs_give((void **)&s
);
1509 else if(!strcmp(s1
, "saveconf")){
1510 write_pinerc(wps_global
, Main
, WRP_NOUSER
);
1513 else if(!strucmp(s1
, "sort")){
1514 return(peAppendDefaultSort(interp
));
1516 else if(!strcmp(s1
, "ldapenabled")){
1520 * Returns: 1 if enabled 0 if not
1523 Tcl_SetResult(interp
, "1", TCL_VOLATILE
);
1525 Tcl_SetResult(interp
, "0", TCL_VOLATILE
);
1530 else if(!strcmp(s1
, "prunecheck")){
1535 if(!check_prune_time(&now
, &tm_now
)){
1536 Tcl_SetResult(interp
, "0", TCL_VOLATILE
);
1540 * We're going to reset the last-time-pruned variable
1541 * so that it asks a maximum of 1 time per month.
1542 * PROs: Annoying-factor is at its lowest
1543 * Can go ahead and move folders right away if
1544 * pruning-rule is automatically set to do so
1545 * CONs: Annoying-factor is at its lowest, if it's set
1546 * later then we can ensure that the questions
1547 * actually get answered or it will keep asking
1549 wps_global
->last_expire_year
= tm_now
->tm_year
;
1550 wps_global
->last_expire_month
= tm_now
->tm_mon
;
1551 snprintf(tmp
, sizeof(tmp
), "%d.%d", wps_global
->last_expire_year
,
1552 wps_global
->last_expire_month
+ 1);
1553 set_variable(V_LAST_TIME_PRUNE_QUESTION
, tmp
, 0, 1, Main
);
1555 Tcl_SetResult(interp
, "1", TCL_VOLATILE
);
1559 else if(!strcmp(s1
, "prunetime")){
1562 CONTEXT_S
*prune_cntxt
;
1563 Tcl_Obj
*retObj
= NULL
;
1564 int cur_month
, ok
= 1;
1566 static int moved_fldrs
= 0;
1568 now
= time((time_t *)0);
1569 tm_now
= localtime(&now
);
1570 cur_month
= (1900 + tm_now
->tm_year
) * 12 + tm_now
->tm_mon
;
1572 if(!(prune_cntxt
= default_save_context(wps_global
->context_list
)))
1573 prune_cntxt
= wps_global
->context_list
;
1576 if(wps_global
->VAR_DEFAULT_FCC
&& *wps_global
->VAR_DEFAULT_FCC
1577 && context_isambig(wps_global
->VAR_DEFAULT_FCC
))
1578 if((retObj
= wp_prune_folders(prune_cntxt
,
1579 wps_global
->VAR_DEFAULT_FCC
,
1581 wps_global
->pruning_rule
, &ok
,
1582 moved_fldrs
, interp
)) != NULL
)
1583 Tcl_ListObjAppendElement(interp
,
1584 Tcl_GetObjResult(interp
),
1587 if(ok
&& wps_global
->VAR_READ_MESSAGE_FOLDER
1588 && *wps_global
->VAR_READ_MESSAGE_FOLDER
1589 && context_isambig(wps_global
->VAR_READ_MESSAGE_FOLDER
))
1590 if((retObj
= wp_prune_folders(prune_cntxt
,
1591 wps_global
->VAR_READ_MESSAGE_FOLDER
,
1593 wps_global
->pruning_rule
, &ok
,
1594 moved_fldrs
, interp
)) != NULL
)
1595 Tcl_ListObjAppendElement(interp
,
1596 Tcl_GetObjResult(interp
),
1598 if(ok
&& (p
= wps_global
->VAR_PRUNED_FOLDERS
)){
1599 for(; ok
&& *p
; p
++)
1600 if(**p
&& context_isambig(*p
))
1601 if((retObj
= wp_prune_folders(prune_cntxt
,
1603 wps_global
->pruning_rule
, &ok
,
1604 moved_fldrs
, interp
)) != NULL
)
1605 Tcl_ListObjAppendElement(interp
,
1606 Tcl_GetObjResult(interp
),
1613 else if(!strcmp(s1
, "authrequestor")){
1614 Tcl_SetResult(interp
, peCredentialRequestor
, TCL_STATIC
);
1617 else if(!strcmp(s1
, "noop")){
1618 /* tickle the imap server too */
1619 if(wps_global
->mail_stream
)
1620 pine_mail_ping(wps_global
->mail_stream
);
1622 Tcl_SetResult(interp
, "NOOP", TCL_STATIC
);
1625 else if(!strcmp(s1
, "inputtimeout")){
1626 Tcl_SetResult(interp
, int2string(get_input_timeout()), TCL_VOLATILE
);
1631 if(!strcmp(s1
, "feature")){
1639 * ARGS: featurename -
1641 * Returns: 1 if named feature set, 0 otherwise
1644 if((featurename
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
)
1645 for(i
= 0; (feature
= feature_list(i
)); i
++)
1646 if(!strucmp(featurename
, feature
->name
)){
1647 isset
= F_ON(feature
->id
, wps_global
);
1651 Tcl_SetResult(interp
, int2string(isset
), TCL_VOLATILE
);
1654 else if(!strcmp(s1
, "colorget")){
1656 char tvname
[256], hexcolor
[256];
1657 struct variable
*vtmp
;
1658 if(!(varname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
1661 if(strcmp("viewer-hdr-colors", varname
) == 0){
1662 SPEC_COLOR_S
*hcolors
, *thc
;
1664 char hexcolor
[256], *tstr
= NULL
;
1666 hcolors
= spec_colors_from_varlist(wps_global
->VAR_VIEW_HDR_COLORS
, 0);
1667 for(thc
= hcolors
; thc
; thc
= thc
->next
){
1668 resObj
= Tcl_NewListObj(0,NULL
);
1669 Tcl_ListObjAppendElement(interp
, resObj
,
1670 Tcl_NewStringObj(thc
->spec
, -1));
1671 hex_colorstr(hexcolor
, thc
->fg
);
1672 Tcl_ListObjAppendElement(interp
, resObj
,
1673 Tcl_NewStringObj(hexcolor
, -1));
1674 hex_colorstr(hexcolor
, thc
->bg
);
1675 Tcl_ListObjAppendElement(interp
, resObj
,
1676 Tcl_NewStringObj(hexcolor
, -1));
1677 Tcl_ListObjAppendElement(interp
, resObj
,
1678 Tcl_NewStringObj(thc
->val
1679 ? tstr
= pattern_to_string(thc
->val
)
1681 if(tstr
) fs_give((void **)&tstr
);
1682 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1685 fs_give((void **)&hcolors
);
1689 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-foreground-color");
1690 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
1691 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
1693 if(!vtmp
->name
) return(TCL_ERROR
);
1694 if(vtmp
->is_list
) return(TCL_ERROR
);
1695 if(!vtmp
->current_val
.p
)
1696 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1697 Tcl_NewStringObj("", -1));
1699 hex_colorstr(hexcolor
, vtmp
->current_val
.p
);
1700 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1701 Tcl_NewStringObj(hexcolor
, -1));
1703 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-background-color");
1705 if((vtmp
->name
&& strucmp(vtmp
->name
, tvname
)) || !vtmp
->name
)
1706 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
1707 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
1711 if(!vtmp
->name
) return(TCL_ERROR
);
1712 if(vtmp
->is_list
) return(TCL_ERROR
);
1713 if(!vtmp
->current_val
.p
)
1714 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1715 Tcl_NewStringObj("", -1));
1717 hex_colorstr(hexcolor
, vtmp
->current_val
.p
);
1718 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1719 Tcl_NewStringObj(hexcolor
, -1));
1724 else if(!strcmp(s1
, "varget")){
1725 struct variable
*vtmp
;
1726 Tcl_Obj
*itemObj
, *resObj
, *secObj
;
1727 char *vallist
, *varname
, tmperrmsg
[256];
1734 * Returns: get the values for the requested variable
1736 * The list returned follows this general form:
1738 * char *; variable name
1739 * char **; list of set values
1740 * char *; display type (listbox, text, textarea, ...)
1741 * char **; list of possible values
1742 * (so far this is only useful for listboxes)
1744 if(!(varname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
1745 Tcl_SetResult(interp
, "Can't Tcl_GetStringFromObj",
1750 for(vtmp
= wps_global
->vars
;
1751 vtmp
->name
&& strucmp(vtmp
->name
, varname
);
1756 snprintf(tmperrmsg
, sizeof(tmperrmsg
), "Can't find variable named %s",
1757 strlen(varname
) < 200 ? varname
: "");
1758 Tcl_SetResult(interp
, tmperrmsg
, TCL_VOLATILE
);
1761 if((itemObj
= Tcl_NewStringObj(vtmp
->name
, -1)) != NULL
){
1762 Tcl_ListObjAppendElement(interp
,
1763 Tcl_GetObjResult(interp
),
1765 resObj
= Tcl_NewListObj(0, NULL
);
1767 for(i
= 0 ; vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]; i
++){
1768 vallist
= vtmp
->current_val
.l
[i
];
1770 itemObj
= Tcl_NewStringObj(vallist
, -1);
1772 itemObj
= Tcl_NewStringObj("", -1);
1773 Tcl_ListObjAppendElement(interp
, resObj
, itemObj
);
1777 itemObj
= Tcl_NewStringObj(vtmp
->current_val
.p
?
1778 vtmp
->current_val
.p
: "", -1);
1779 Tcl_ListObjAppendElement(interp
, resObj
, itemObj
);
1781 Tcl_ListObjAppendElement(interp
,
1782 Tcl_GetObjResult(interp
),
1784 secObj
= Tcl_NewListObj(0, NULL
);
1786 itemObj
= Tcl_NewStringObj("textarea", -1);
1788 NAMEVAL_S
*(*tmpf
)(int);
1789 switch(vtmp
- wps_global
->vars
){
1790 case V_SAVED_MSG_NAME_RULE
:
1791 tmpf
= save_msg_rules
;
1797 tmpf
= sort_key_rules
;
1799 case V_AB_SORT_RULE
:
1800 tmpf
= ab_sort_rules
;
1802 case V_FLD_SORT_RULE
:
1803 tmpf
= fld_sort_rules
;
1805 case V_GOTO_DEFAULT_RULE
:
1808 case V_INCOMING_STARTUP
:
1809 tmpf
= incoming_startup_rules
;
1811 case V_PRUNING_RULE
:
1812 tmpf
= pruning_rules
;
1814 case V_WP_INDEXHEIGHT
:
1815 tmpf
= wp_indexheight_rules
;
1822 for(i
= 0; (tmpnv
= (tmpf
)(i
)); i
++){
1823 itemObj
= Tcl_NewListObj(0, NULL
);
1824 Tcl_ListObjAppendElement(interp
, itemObj
,
1825 Tcl_NewStringObj(tmpnv
->name
, -1));
1826 if(tmpnv
->shortname
)
1827 Tcl_ListObjAppendElement(interp
, itemObj
,
1828 Tcl_NewStringObj(tmpnv
->shortname
, -1));
1829 Tcl_ListObjAppendElement(interp
, secObj
, itemObj
);
1831 itemObj
= Tcl_NewStringObj("listbox", -1);
1834 itemObj
= Tcl_NewStringObj("text", -1);
1836 Tcl_ListObjAppendElement(interp
,
1837 Tcl_GetObjResult(interp
),
1839 Tcl_ListObjAppendElement(interp
,
1840 Tcl_GetObjResult(interp
),
1845 else if(!strcmp(s1
, "rawsig")){
1847 if(wps_global
->VAR_LITERAL_SIG
){
1848 char *cstring_version
, *sig
, *line
;
1852 wtmp_20k_buf
[0] = '\0';
1853 Tcl_ListObjGetElements(interp
, objv
[2], &nSig
, &objSig
);
1854 for(i
= 0; i
< nSig
&& i
< SIG_MAX_LINES
; i
++)
1855 if((line
= Tcl_GetStringFromObj(objSig
[i
], NULL
)) != NULL
)
1856 snprintf(wtmp_20k_buf
+ strlen(wtmp_20k_buf
), SIZEOF_20KBUF
- strlen(wtmp_20k_buf
), "%.*s\n", SIG_MAX_COLS
, line
);
1858 sig
= cpystr(wtmp_20k_buf
);
1860 if((cstring_version
= string_to_cstring(sig
)) != NULL
){
1861 set_variable(V_LITERAL_SIG
, cstring_version
, 0, 0, Main
);
1862 fs_give((void **)&cstring_version
);
1865 fs_give((void **) &sig
);
1869 return(peWriteSig(interp
, wps_global
->VAR_SIGNATURE_FILE
,
1870 &((Tcl_Obj
**)objv
)[2]));
1872 else if(!strcmp(s1
, "statmsg")){
1878 * ARGS: msg - text to set
1880 * Returns: nothing, but with global status message
1881 * buf set to given msg
1884 if((msg
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
)
1889 else if(!strcmp(s1
, "mode")){
1898 * Returns: return value of given binary mode
1901 if((mode
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
1902 if(!strcmp(mode
, "full-header-mode"))
1903 rv
= wps_global
->full_header
;
1906 Tcl_SetResult(interp
, int2string(rv
), TCL_VOLATILE
);
1909 else if(!strcmp(s1
, "indexlines")){
1913 if(Tcl_GetIntFromObj(interp
, objv
[2], &n
) == TCL_OK
){
1914 set_variable(V_WP_INDEXLINES
, p
= int2string(n
), 0, 0, Main
);
1915 Tcl_SetResult(interp
, p
, TCL_VOLATILE
);
1919 else if(!strcmp(s1
, "aggtabstate")){
1923 if(Tcl_GetIntFromObj(interp
, objv
[2], &n
) == TCL_OK
){
1924 set_variable(V_WP_AGGSTATE
, p
= int2string(n
), 0, 0, Main
);
1925 Tcl_SetResult(interp
, p
, TCL_VOLATILE
);
1929 else if(!strcmp(s1
, "alpinestate")){
1930 char *wps
, *p
, *q
, *twps
= NULL
;
1933 if((wps
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
1934 for(p
= wps
; *p
; p
++)
1939 twps
= (char *) fs_get(((p
- wps
) + (dollars
+ 1)) * sizeof(char));
1946 while((*q
++ = *p
++) != '\0');
1949 set_variable(V_WP_STATE
, twps
? twps
: wps
, 0, 1, Main
);
1950 Tcl_SetResult(interp
, wps
, TCL_VOLATILE
);
1952 fs_give((void **) &twps
);
1957 else if(!strcmp(s1
, "set")){
1960 if((rObj
= Tcl_ObjGetVar2(interp
, objv
[2], NULL
, TCL_LEAVE_ERR_MSG
)) != NULL
){
1961 Tcl_SetObjResult(interp
, rObj
);
1967 else if(!strcmp(s1
, "unset")){
1970 return((varname
= Tcl_GetStringFromObj(objv
[2], NULL
)) ? Tcl_UnsetVar2(interp
, varname
, NULL
, TCL_LEAVE_ERR_MSG
) : TCL_ERROR
);
1974 if(!strcmp(s1
, "feature")){
1976 int i
, set
, wasset
= 0;
1982 * ARGS: featurename -
1983 * value - new value to assign flag
1985 * Returns: 1 if named feature set, 0 otherwise
1988 if((featurename
= Tcl_GetStringFromObj(objv
[2], NULL
))
1989 && Tcl_GetIntFromObj(interp
, objv
[3], &set
) != TCL_ERROR
)
1990 for(i
= 0; (feature
= feature_list(i
)); i
++)
1991 if(!strucmp(featurename
, feature
->name
)){
1992 if(set
!= F_ON(feature
->id
, wps_global
)){
1993 toggle_feature(wps_global
,
1994 &wps_global
->vars
[V_FEATURE_LIST
],
1995 feature
, TRUE
, Main
);
1998 wps_global
->prc
->outstanding_pinerc_changes
= 1;
2004 Tcl_SetResult(interp
, int2string(wasset
), TCL_VOLATILE
);
2007 else if(!strucmp(s1
, "help")){
2010 char **help_text
, **ptext
, *helpname
, tmperrmsg
[256],
2013 struct variable
*vtmp
;
2016 if(!(helpname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
2017 Tcl_SetResult(interp
,
2018 "Can't Tcl_GetStringFromObj for helpname",
2022 if(!(function
= Tcl_GetStringFromObj(objv
[3], NULL
))){
2023 Tcl_SetResult(interp
,
2024 "Can't Tcl_GetStringFromObj for function",
2028 if(strucmp(function
, "plain") == 0){
2029 if((text
= help_name2section(helpname
, strlen(helpname
)))
2033 else if(strucmp(function
, "variable") == 0){
2034 for(vtmp
= wps_global
->vars
;
2035 vtmp
->name
&& strucmp(vtmp
->name
, helpname
);
2038 snprintf(tmperrmsg
, sizeof(tmperrmsg
), "Can't find variable named %s",
2039 strlen(helpname
) < 200 ? helpname
: "");
2040 Tcl_SetResult(interp
, tmperrmsg
, TCL_VOLATILE
);
2043 text
= config_help(vtmp
- wps_global
->vars
, 0);
2047 else if(strucmp(function
, "feature") == 0){
2048 for(i
= 0; (ftmp
= feature_list(i
)); i
++){
2049 if(!strucmp(helpname
, ftmp
->name
)){
2054 if(!ftmp
|| text
== NO_HELP
){
2059 snprintf(tmperrmsg
, sizeof(tmperrmsg
), "Invalid function: %s",
2060 strlen(helpname
) < 200 ? function
: "");
2061 Tcl_SetResult(interp
, tmperrmsg
, TCL_VOLATILE
);
2064 /* assumption here is that HelpType is char ** */
2066 for(ptext
= help_text
; *ptext
; ptext
++){
2067 itemObj
= Tcl_NewStringObj(*ptext
, -1);
2068 Tcl_ListObjAppendElement(interp
,
2069 Tcl_GetObjResult(interp
),
2074 else if(!strcmp(s1
, "varset")){
2075 char *varname
, **tmpstrlist
, *line
;
2076 struct variable
*vtmp
;
2078 int i
, numlistvals
= 0, strlistpos
;
2080 if((varname
= Tcl_GetStringFromObj(objv
[2], NULL
))
2081 && (Tcl_ListObjGetElements(interp
, objv
[3], &numlistvals
,
2082 &objVal
) == TCL_OK
)){
2083 for(vtmp
= wps_global
->vars
;
2084 vtmp
->name
&& strucmp(vtmp
->name
, varname
);
2090 /* found the variable */
2092 for(i
= 0; vtmp
->main_user_val
.l
&& vtmp
->main_user_val
.l
[i
]; i
++)
2093 fs_give((void **)&vtmp
->main_user_val
.l
[i
]);
2094 if(vtmp
->main_user_val
.l
)
2095 fs_give((void **)&vtmp
->main_user_val
.l
);
2096 if(numlistvals
> 0){
2097 tmpstrlist
= (char **)fs_get((numlistvals
+ 1) * sizeof(char *));
2098 for(i
= 0, strlistpos
= 0; i
< numlistvals
; i
++){
2099 if((line
= Tcl_GetStringFromObj(objVal
[i
], 0)) != NULL
){
2100 removing_leading_and_trailing_white_space(line
);
2102 tmpstrlist
[strlistpos
++] = cpystr(line
);
2105 tmpstrlist
[strlistpos
] = NULL
;
2106 vtmp
->main_user_val
.l
= (char **)fs_get((strlistpos
+1) *
2108 for(i
= 0; i
<= strlistpos
; i
++)
2109 vtmp
->main_user_val
.l
[i
] = tmpstrlist
[i
];
2110 fs_give((void **)&tmpstrlist
);
2112 set_current_val(vtmp
, FALSE
, FALSE
);
2116 if((line
= Tcl_GetStringFromObj(objVal
[0], NULL
)) != NULL
){
2117 if(strucmp(vtmp
->name
, "reply-indent-string"))
2118 removing_leading_and_trailing_white_space(line
);
2119 if(vtmp
->main_user_val
.p
)
2120 fs_give((void **)&vtmp
->main_user_val
.p
);
2122 vtmp
->main_user_val
.p
= cpystr(line
);
2123 set_current_val(vtmp
, FALSE
, FALSE
);
2131 else if(!strcmp(s1
, "mode")){
2138 * ARGS: <mode> <value>
2140 * Returns: old value of binary mode we were told to set
2143 if((mode
= Tcl_GetStringFromObj(objv
[2], NULL
))
2144 && Tcl_GetIntFromObj(interp
, objv
[3], &value
) != TCL_ERROR
){
2145 if(!strcmp(mode
, "full-header-mode")){
2146 rv
= wps_global
->full_header
;
2147 wps_global
->full_header
= value
;
2151 Tcl_SetResult(interp
, int2string(rv
), TCL_VOLATILE
);
2154 else if(!strcmp(s1
, "set")){
2157 if((rObj
= Tcl_ObjSetVar2(interp
, objv
[2], NULL
, objv
[3], TCL_LEAVE_ERR_MSG
)) != NULL
){
2158 Tcl_SetObjResult(interp
, rObj
);
2166 err
= "PEInfo: Too many arguments";
2170 Tcl_SetResult(interp
, err
, TCL_STATIC
);
2176 * PEConfigCmd - edit various alpine config variables
2178 * The goal here is to remember what's changed, but not write to pinerc
2179 * until the user's actually chosen to save.
2182 PEConfigCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
2184 char *err
= "Unknown PEConfig request";
2187 dprint((2, "PEConfigCmd"));
2190 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
2191 Tcl_SetResult(interp
, err
, TCL_STATIC
);
2194 s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
2197 if(!strcmp(s1
, "colorset")){
2198 char *varname
, *fghex
, *bghex
;
2199 char tvname
[256], asciicolor
[256];
2200 struct variable
*vtmp
;
2203 SPEC_COLOR_S
*hcolors
, *thc
;
2205 if(!(varname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
2206 Tcl_SetResult(interp
, "colorset: can't read variable name", TCL_STATIC
);
2210 if(!strcmp(varname
, "viewer-hdr-colors")){
2211 char *newhdr
= NULL
, *newpat
= NULL
, *utype
;
2215 Tcl_SetResult(interp
, "colorset: too few view-hdr args", TCL_STATIC
);
2219 if(wps_global
->vars
[V_VIEW_HDR_COLORS
].is_changed_val
)
2220 hcolors
= spec_colors_from_varlist(wps_global
->vars
[V_VIEW_HDR_COLORS
].changed_val
.l
, 0);
2222 hcolors
= spec_colors_from_varlist(wps_global
->VAR_VIEW_HDR_COLORS
, 0);
2223 if(!(utype
= Tcl_GetStringFromObj(objv
[3], NULL
))){
2224 Tcl_SetResult(interp
, "colorset: can't read operation", TCL_STATIC
);
2228 if(!strcmp(utype
, "delete")){
2230 Tcl_SetResult(interp
, "colorset: no viewer-hdrs to delete", TCL_STATIC
);
2234 if(Tcl_GetIntFromObj(interp
, objv
[4], &hindex
) == TCL_ERROR
){
2235 Tcl_SetResult(interp
, "colorset: can't read index", TCL_STATIC
);
2241 hcolors
= hcolors
->next
;
2243 free_spec_colors(&thc
);
2247 for(thc
= hcolors
, i
= 1; thc
&& i
< hindex
; thc
= thc
->next
, i
++)
2250 if(thc
&& thc
->next
){
2251 SPEC_COLOR_S
*thc2
= thc
->next
;
2253 thc
->next
= thc2
->next
;
2255 free_spec_colors(&thc2
);
2258 Tcl_SetResult(interp
, "colorset: invalid index", TCL_STATIC
);
2263 else if(!strcmp(utype
, "add")){
2265 Tcl_SetResult(interp
, "colorset: wrong number of view-hdr add args", TCL_STATIC
);
2269 if(Tcl_ListObjGetElements(interp
, objv
[4], &cObjc
, &cObj
) != TCL_OK
)
2273 Tcl_SetResult(interp
, "colorset: wrong number of hdrs for view-hdr add", TCL_STATIC
);
2277 newhdr
= Tcl_GetStringFromObj(cObj
[0], NULL
);
2278 newpat
= Tcl_GetStringFromObj(cObj
[1], NULL
);
2279 if(Tcl_ListObjGetElements(interp
, objv
[5], &cObjc
, &cObj
) != TCL_OK
)
2283 Tcl_SetResult(interp
, "colorset: wrong number of colors for view-hdr add", TCL_STATIC
);
2287 fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
);
2288 bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
);
2289 if(newhdr
&& newpat
&& fghex
&& bghex
){
2292 for(hcp
= &hcolors
; *hcp
!= NULL
; hcp
= &(*hcp
)->next
)
2295 *hcp
= (SPEC_COLOR_S
*)fs_get(sizeof(SPEC_COLOR_S
));
2296 (*hcp
)->inherit
= 0;
2297 (*hcp
)->spec
= cpystr(newhdr
);
2298 (*hcp
)->fg
= cpystr((ascii_colorstr(asciicolor
, fghex
) == 0) ? asciicolor
: "black");
2299 (*hcp
)->bg
= cpystr((ascii_colorstr(asciicolor
, bghex
) == 0) ? asciicolor
: "white");
2301 if(newpat
&& *newpat
)
2302 (*hcp
)->val
= string_to_pattern(newpat
);
2306 (*hcp
)->next
= NULL
;
2309 Tcl_SetResult(interp
, "colorset: invalid args for view-hdr add", TCL_STATIC
);
2313 else if(!strcmp(utype
, "update")){
2315 Tcl_SetResult(interp
, "colorset: wrong number of view-hdr update args", TCL_STATIC
);
2319 if(!(Tcl_ListObjGetElements(interp
, objv
[4], &cObjc
, &cObj
) == TCL_OK
2321 && Tcl_GetIntFromObj(interp
, cObj
[0], &hindex
) == TCL_OK
2322 && (newhdr
= Tcl_GetStringFromObj(cObj
[1], NULL
))
2323 && (newpat
= Tcl_GetStringFromObj(cObj
[2], NULL
)))){
2324 Tcl_SetResult(interp
, "colorset: view-hdr update can't read index or header", TCL_STATIC
);
2328 if(!(Tcl_ListObjGetElements(interp
, objv
[5], &cObjc
, &cObj
) == TCL_OK
2330 && (fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
))
2331 && (bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
)))){
2332 Tcl_SetResult(interp
, "colorset: view-hdr update can't read colors", TCL_STATIC
);
2336 for(thc
= hcolors
, i
= 0; thc
&& i
< hindex
; thc
= thc
->next
, i
++)
2340 Tcl_SetResult(interp
, "colorset: view-hdr update invalid index", TCL_STATIC
);
2345 fs_give((void **)&thc
->spec
);
2347 thc
->spec
= cpystr(newhdr
);
2348 if(ascii_colorstr(asciicolor
, fghex
) == 0) {
2350 fs_give((void **)&thc
->fg
);
2352 thc
->fg
= cpystr(asciicolor
);
2355 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid foreground color value %.100s", fghex
);
2356 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2360 if(ascii_colorstr(asciicolor
, bghex
) == 0) {
2362 fs_give((void **)&thc
->bg
);
2364 thc
->bg
= cpystr(asciicolor
);
2367 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
2368 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2373 fs_give((void **)&thc
->val
);
2375 if(newpat
&& *newpat
){
2376 thc
->val
= string_to_pattern(newpat
);
2380 Tcl_SetResult(interp
, "colorset: unknown operation", TCL_STATIC
);
2384 vtmp
= &wps_global
->vars
[V_VIEW_HDR_COLORS
];
2385 for(i
= 0; vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]; i
++)
2386 fs_give((void **)&vtmp
->changed_val
.l
[i
]);
2388 if(vtmp
->changed_val
.l
)
2389 fs_give((void **)&vtmp
->changed_val
.l
);
2391 vtmp
->changed_val
.l
= varlist_from_spec_colors(hcolors
);
2392 vtmp
->is_changed_val
= 1;
2393 free_spec_colors(&hcolors
);
2398 Tcl_SetResult(interp
, "colorset: Wrong number of args", TCL_STATIC
);
2402 if(!(Tcl_ListObjGetElements(interp
, objv
[3], &cObjc
, &cObj
) == TCL_OK
2404 && (fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
))
2405 && (bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
)))){
2406 Tcl_SetResult(interp
, "colorset: Problem reading fore/back ground colors", TCL_STATIC
);
2410 snprintf(tvname
, sizeof(tvname
), "%.200s-foreground-color", varname
);
2411 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
2412 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
2416 if(!vtmp
->name
|| vtmp
->is_list
){
2417 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
2418 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2422 if(ascii_colorstr(asciicolor
, fghex
) == 0) {
2423 if(vtmp
->changed_val
.p
)
2424 fs_give((void **)&vtmp
->changed_val
.p
);
2426 vtmp
->changed_val
.p
= cpystr(asciicolor
);
2427 vtmp
->is_changed_val
= 1;
2429 /* We need to handle this in the actual config setting
2430 * if(!strucmp(varname, "normal"))
2431 * pico_set_fg_color(asciicolor);
2435 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid color value %.100s", fghex
);
2436 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2440 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-background-color");
2442 if((vtmp
->name
&& strucmp(vtmp
->name
, tvname
)) || !vtmp
->name
)
2443 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
2444 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
2448 if(!vtmp
->name
|| vtmp
->is_list
){
2449 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
2450 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2454 if(ascii_colorstr(asciicolor
, bghex
) == 0) {
2455 if(vtmp
->changed_val
.p
)
2456 fs_give((void **)&vtmp
->changed_val
.p
);
2458 vtmp
->changed_val
.p
= cpystr(asciicolor
);
2459 vtmp
->is_changed_val
= 1;
2460 /* again, we need to handle this when we actually set the variable
2461 * if(!strucmp(varname, "normal"))
2462 * pico_set_bg_color(asciicolor);
2466 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
2467 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2471 Tcl_SetResult(interp
, "1", TCL_STATIC
);
2475 else if(!strcmp(s1
, "ruleset")){
2476 return(peRuleSet(interp
, &((Tcl_Obj
**)objv
)[2]));
2479 if(!strcmp(s1
, "featuresettings")){
2480 struct variable
*vtmp
;
2484 vtmp
= &wps_global
->vars
[V_FEATURE_LIST
];
2485 for(i
= 0; (feature
= feature_list(i
)); i
++)
2486 if(feature_list_section(feature
)){
2487 if(vtmp
->is_changed_val
? F_CH_ON(feature
->id
)
2488 : F_ON(feature
->id
, wps_global
)){
2489 Tcl_ListObjAppendElement(interp
,
2490 Tcl_GetObjResult(interp
),
2491 Tcl_NewStringObj(feature
->name
, -1));
2496 else if(!strcmp(s1
, "rawsig")){
2497 char *err
= NULL
, *sig
= NULL
, *p
, *q
;
2499 struct variable
*vtmp
;
2501 vtmp
= &wps_global
->vars
[V_LITERAL_SIG
];
2502 if(vtmp
->is_changed_val
? vtmp
->changed_val
.p
2503 : wps_global
->VAR_LITERAL_SIG
){
2507 if(wps_global
->restricted
){
2508 err
= "Alpine demo can't change config file";
2511 /* BUG: no "exceptions file" support */
2512 apval
= (vtmp
->is_changed_val
? &vtmp
->changed_val
.p
2513 : APVAL(&wps_global
->vars
[V_LITERAL_SIG
], Main
));
2515 sig
= (char *) fs_get((strlen(*apval
? *apval
: "") + 1) * sizeof(char));
2517 cstring_to_string(*apval
, sig
);
2520 err
= "Problem accessing configuration";
2523 else if((vtmp
= &wps_global
->vars
[V_SIGNATURE_FILE
])
2524 && !IS_REMOTE(vtmp
->is_changed_val
? vtmp
->changed_val
.p
2525 : wps_global
->VAR_SIGNATURE_FILE
))
2526 snprintf(err
= wtmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote signature file: %s",
2527 vtmp
->is_changed_val
? (vtmp
->changed_val
.p
2528 ? vtmp
->changed_val
.p
: "<null>")
2529 : (wps_global
->VAR_SIGNATURE_FILE
2530 ? wps_global
->VAR_SIGNATURE_FILE
: "<null>"));
2531 else if(!(peTSig
|| (sig
= simple_read_remote_file(vtmp
->is_changed_val
2532 ? vtmp
->changed_val
.p
2533 : wps_global
->VAR_SIGNATURE_FILE
, REMOTE_SIG_SUBTYPE
))))
2534 err
= "Can't read remote pinerc";
2537 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
2542 for(i
= 0; peTSig
[i
]; i
++)
2543 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2544 Tcl_NewStringObj(peTSig
[i
],-1));
2547 for(p
= sig
; (q
= strindex(p
, '\n')); p
= q
+ 1)
2548 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2549 Tcl_NewStringObj(p
, q
- p
));
2551 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2552 Tcl_NewStringObj(p
, -1));
2553 fs_give((void **) &sig
);
2557 else if(!strcmp(s1
, "filters")){
2558 long rflags
= ROLE_DO_FILTER
| PAT_USE_CHANGED
;
2562 close_every_pattern();
2563 if(any_patterns(rflags
, &pstate
)){
2564 for(pat
= first_pattern(&pstate
);
2566 pat
= next_pattern(&pstate
)){
2567 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2568 Tcl_NewStringObj(pat
->patgrp
->nick
, -1));
2573 else if(!strcmp(s1
, "scores")){
2574 long rflags
= ROLE_DO_SCORES
| PAT_USE_CHANGED
;
2578 close_every_pattern();
2579 if(any_patterns(rflags
, &pstate
)){
2580 for(pat
= first_pattern(&pstate
);
2582 pat
= next_pattern(&pstate
)){
2583 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2584 Tcl_NewStringObj(pat
->patgrp
->nick
, -1));
2589 else if(!strcmp(s1
, "indexcolors")){
2590 long rflags
= ROLE_DO_INCOLS
| PAT_USE_CHANGED
;
2594 close_every_pattern();
2595 if(any_patterns(rflags
, &pstate
)){
2596 for(pat
= first_pattern(&pstate
);
2598 pat
= next_pattern(&pstate
)){
2599 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2600 Tcl_NewStringObj(pat
->patgrp
->nick
, -1));
2605 else if(!strcmp(s1
, "collections")){
2606 struct variable
*vtmp
;
2608 CONTEXT_S
*new_ctxt
;
2610 vtmp
= &wps_global
->vars
[V_FOLDER_SPEC
];
2611 for(i
= 0; (vtmp
->is_changed_val
2612 ? vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]
2613 : vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]);
2615 new_ctxt
= new_context(vtmp
->is_changed_val
2616 ? vtmp
->changed_val
.l
[i
]
2617 : vtmp
->current_val
.l
[i
], NULL
);
2618 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s",
2620 ? new_ctxt
->nickname
2625 : "Some Collection")),
2626 new_ctxt
->label
? new_ctxt
->label
: "");
2627 free_context(&new_ctxt
);
2629 vtmp
= &wps_global
->vars
[V_NEWS_SPEC
];
2630 for(i
= 0; (vtmp
->is_changed_val
2631 ? vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]
2632 : vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]);
2634 new_ctxt
= new_context(vtmp
->is_changed_val
2635 ? vtmp
->changed_val
.l
[i
]
2636 : vtmp
->current_val
.l
[i
], NULL
);
2637 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s",
2639 ? new_ctxt
->nickname
2644 : "Some Collection")),
2645 new_ctxt
->label
? new_ctxt
->label
: "");
2646 free_context(&new_ctxt
);
2651 else if(!strcmp(s1
, "newconf")){
2652 struct variable
*vtmp
;
2656 for(vtmp
= wps_global
->vars
; vtmp
->name
; vtmp
++)
2657 vtmp
->is_changed_val
= 0;
2659 for(i
= 0; (feature
= feature_list(i
)); i
++)
2660 F_CH_SET(feature
->id
, F_ON(feature
->id
, wps_global
));
2663 for(i
= 0; peTSig
[i
]; i
++)
2664 fs_give((void **)&peTSig
[i
]);
2665 fs_give((void **)&peTSig
);
2668 close_patterns(ROLE_DO_FILTER
| ROLE_DO_INCOLS
| ROLE_DO_SCORES
| PAT_USE_CHANGED
);
2671 else if(!strcmp(s1
, "saveconf")){
2672 struct variable
*vtmp
;
2673 int i
, did_change
= 0, def_sort_rev
;
2676 if(wps_global
->vars
[V_FEATURE_LIST
].is_changed_val
){
2677 wps_global
->vars
[V_FEATURE_LIST
].is_changed_val
= 0;
2678 for(i
= 0; (feature
= feature_list(i
)); i
++)
2679 if(feature_list_section(feature
)){
2680 if(F_CH_ON(feature
->id
) != F_ON(feature
->id
, wps_global
)){
2682 toggle_feature(wps_global
,
2683 &wps_global
->vars
[V_FEATURE_LIST
],
2684 feature
, TRUE
, Main
);
2689 for(vtmp
= wps_global
->vars
; vtmp
->name
; vtmp
++){
2690 if(vtmp
->is_changed_val
2691 && (vtmp
- wps_global
->vars
!= V_FEATURE_LIST
)){
2693 for(i
= 0; vtmp
->main_user_val
.l
2694 && vtmp
->main_user_val
.l
[i
]; i
++)
2695 fs_give((void **)&vtmp
->main_user_val
.l
[i
]);
2696 if(vtmp
->main_user_val
.l
)
2697 fs_give((void **)&vtmp
->main_user_val
.l
);
2698 vtmp
->main_user_val
.l
= vtmp
->changed_val
.l
;
2699 vtmp
->changed_val
.l
= NULL
;
2702 if(vtmp
->main_user_val
.p
)
2703 fs_give((void **)&vtmp
->main_user_val
.p
);
2704 vtmp
->main_user_val
.p
= vtmp
->changed_val
.p
;
2705 vtmp
->changed_val
.p
= NULL
;
2707 set_current_val(vtmp
, FALSE
, FALSE
);
2708 vtmp
->is_changed_val
= 0;
2710 switch (vtmp
- wps_global
->vars
) {
2712 init_hostname(wps_global
);
2715 free_contexts(&wps_global
->context_list
);
2716 init_folders(wps_global
);
2718 case V_NORM_FORE_COLOR
:
2719 pico_set_fg_color(vtmp
->current_val
.p
);
2721 case V_NORM_BACK_COLOR
:
2722 pico_set_bg_color(vtmp
->current_val
.p
);
2725 case V_GLOB_ADDRBOOK
:
2727 case V_LDAP_SERVERS
:
2729 case V_ABOOK_FORMATS
:
2731 case V_INDEX_FORMAT
:
2732 init_index_format(wps_global
->VAR_INDEX_FORMAT
,
2733 &wps_global
->index_disp_format
);
2734 clear_index_cache(sp_inbox_stream(), 0);
2737 close_patterns(ROLE_DO_FILTER
| PAT_USE_CURRENT
);
2738 role_process_filters();
2741 close_patterns(ROLE_DO_INCOLS
| PAT_USE_CURRENT
);
2742 clear_index_cache(sp_inbox_stream(), 0);
2743 role_process_filters();
2746 close_patterns(ROLE_DO_SCORES
| PAT_USE_CURRENT
);
2747 role_process_filters();
2750 case V_DEFAULT_SAVE_FOLDER
:
2751 init_save_defaults();
2754 decode_sort(wps_global
->VAR_SORT_KEY
, &wps_global
->def_sort
, &def_sort_rev
);
2756 case V_VIEW_HDR_COLORS
:
2757 set_custom_spec_colors(wps_global
);
2759 case V_POST_CHAR_SET
:
2760 update_posting_charset(wps_global
, 1);
2768 peWriteSig(interp
, wps_global
->VAR_SIGNATURE_FILE
, NULL
);
2771 if(write_pinerc(wps_global
, Main
, WRP_NOUSER
) == 0)
2772 q_status_message(SM_ORDER
, 0, 3, "Configuration changes saved!");
2776 else if(!strcmp(s1
, "columns")){
2777 Tcl_SetResult(interp
, int2string(wps_global
->ttyo
->screen_cols
), TCL_VOLATILE
);
2780 else if(!strcmp(s1
, "indextokens")){
2784 for(i
= 0; (tok
= itoken(i
)) != NULL
; i
++)
2785 if(tok
->what_for
& FOR_INDEX
)
2786 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2787 Tcl_NewStringObj(tok
->name
, -1));
2793 if(!strcmp(s1
, "varget")){
2794 char *varname
= Tcl_GetStringFromObj(objv
[2], NULL
);
2795 struct variable
*vtmp
;
2796 Tcl_Obj
*resObj
, *secObj
;
2801 if(varname
== NULL
) return(TCL_ERROR
);
2803 for(vtmp
= wps_global
->vars
;
2804 vtmp
->name
&& strucmp(vtmp
->name
, varname
);
2809 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
2812 resObj
= Tcl_NewListObj(0, NULL
);
2814 if(vtmp
->is_changed_val
){
2815 for(i
= 0; vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]; i
++){
2816 Tcl_ListObjAppendElement(interp
, resObj
,
2817 Tcl_NewStringObj(vtmp
->changed_val
.l
[i
], -1));
2821 for(i
= 0; vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]; i
++){
2822 Tcl_ListObjAppendElement(interp
, resObj
,
2823 Tcl_NewStringObj(vtmp
->current_val
.l
[i
], -1));
2828 if(vtmp
->is_changed_val
){
2829 if(vtmp
->changed_val
.p
)
2830 Tcl_ListObjAppendElement(interp
, resObj
,
2831 Tcl_NewStringObj(vtmp
->changed_val
.p
[0]
2832 ? vtmp
->changed_val
.p
2836 if(vtmp
->current_val
.p
)
2837 Tcl_ListObjAppendElement(interp
, resObj
,
2838 Tcl_NewStringObj(vtmp
->current_val
.p
[0]
2839 ? vtmp
->current_val
.p
2843 Tcl_ListObjAppendElement(interp
,
2844 Tcl_GetObjResult(interp
),
2846 secObj
= Tcl_NewListObj(0, NULL
);
2848 input_type
= cpystr("textarea");
2850 NAMEVAL_S
*(*tmpf
)(int);
2851 switch(vtmp
- wps_global
->vars
){
2852 case V_SAVED_MSG_NAME_RULE
:
2853 tmpf
= save_msg_rules
;
2859 tmpf
= sort_key_rules
;
2861 case V_AB_SORT_RULE
:
2862 tmpf
= ab_sort_rules
;
2864 case V_FLD_SORT_RULE
:
2865 tmpf
= fld_sort_rules
;
2867 case V_GOTO_DEFAULT_RULE
:
2870 case V_INCOMING_STARTUP
:
2871 tmpf
= incoming_startup_rules
;
2873 case V_PRUNING_RULE
:
2874 tmpf
= pruning_rules
;
2876 case V_WP_INDEXHEIGHT
:
2877 tmpf
= wp_indexheight_rules
;
2884 for(i
= 0; (tmpnv
= (tmpf
)(i
)); i
++){
2885 if(tmpnv
->shortname
)
2886 peAppListF(interp
, secObj
, "%s%s", tmpnv
->name
, tmpnv
->shortname
);
2888 Tcl_ListObjAppendElement(interp
, secObj
,
2889 Tcl_NewStringObj(tmpnv
->name
, -1));
2891 input_type
= cpystr("listbox");
2894 input_type
= cpystr("text");
2896 Tcl_ListObjAppendElement(interp
,
2897 Tcl_GetObjResult(interp
),
2898 Tcl_NewStringObj(input_type
, -1));
2899 Tcl_ListObjAppendElement(interp
,
2900 Tcl_GetObjResult(interp
),
2903 is_default
= !vtmp
->is_changed_val
&& !vtmp
->main_user_val
.l
;
2905 is_default
= !vtmp
->is_changed_val
&& !vtmp
->main_user_val
.p
;
2906 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2907 Tcl_NewIntObj(is_default
));
2908 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2909 Tcl_NewIntObj(vtmp
->is_fixed
));
2912 else if(!strcmp(s1
, "filtextended")){
2914 long rflags
= ROLE_DO_FILTER
| PAT_USE_CHANGED
;
2917 Tcl_Obj
*resObj
= NULL
, *tObj
= NULL
;
2919 if(Tcl_GetIntFromObj(interp
, objv
[2], &fl
) == TCL_ERROR
)
2922 close_every_pattern();
2923 if(any_patterns(rflags
, &pstate
)){
2924 for(pat
= first_pattern(&pstate
), i
= 0;
2926 pat
= next_pattern(&pstate
), i
++);
2931 /* append the pattern ID */
2932 tObj
= Tcl_NewListObj(0, NULL
);
2933 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("id", -1));
2934 pePatAppendID(interp
, tObj
, pat
);
2935 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
2937 /* append the pattern */
2938 tObj
= Tcl_NewListObj(0, NULL
);
2939 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("pattern", -1));
2940 pePatAppendPattern(interp
, tObj
, pat
);
2941 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
2943 /* now append the filter action */
2944 resObj
= Tcl_NewListObj(0, NULL
);
2945 peAppListF(interp
, resObj
, "%s%i", "kill", pat
->action
->folder
? 0 : 1);
2946 peAppListF(interp
, resObj
, "%s%p", "folder", pat
->action
->folder
);
2947 peAppListF(interp
, resObj
, "%s%i", "move_only_if_not_deleted",
2948 pat
->action
->move_only_if_not_deleted
);
2949 tObj
= Tcl_NewListObj(0, NULL
);
2950 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("filtaction", -1));
2951 Tcl_ListObjAppendElement(interp
, tObj
, resObj
);
2952 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
2954 else return(TCL_ERROR
);
2958 else if(!strcmp(s1
, "indexcolorextended")){
2960 long rflags
= ROLE_DO_INCOLS
| PAT_USE_CHANGED
;
2963 Tcl_Obj
*resObj
= NULL
, *tObj
= NULL
;
2965 if(Tcl_GetIntFromObj(interp
, objv
[2], &fl
) == TCL_ERROR
)
2968 close_every_pattern();
2969 if(any_patterns(rflags
, &pstate
)){
2970 for(pat
= first_pattern(&pstate
), i
= 0;
2972 pat
= next_pattern(&pstate
), i
++);
2977 /* append the pattern ID */
2978 tObj
= Tcl_NewListObj(0, NULL
);
2979 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("id", -1));
2980 pePatAppendID(interp
, tObj
, pat
);
2981 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
2983 /* append the pattern */
2984 tObj
= Tcl_NewListObj(0, NULL
);
2985 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("pattern", -1));
2986 pePatAppendPattern(interp
, tObj
, pat
);
2987 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
2989 /* now append the pattern colors */
2990 resObj
= Tcl_NewListObj(0, NULL
);
2991 tObj
= Tcl_NewListObj(0, NULL
);
2992 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("indexcolor", -1));
2993 if(pat
->action
->is_a_incol
){
2995 Tcl_Obj
*colObj
= Tcl_NewListObj(0, NULL
);
2997 if(!(pat
->action
->incol
2998 && pat
->action
->incol
->fg
2999 && pat
->action
->incol
->fg
[0]
3000 && (color
= color_to_asciirgb(pat
->action
->incol
->fg
))
3001 && (color
= peColorStr(color
,wtmp_20k_buf
))))
3004 Tcl_ListObjAppendElement(interp
, colObj
, Tcl_NewStringObj(color
, -1));
3006 if(!(pat
->action
->incol
3007 && pat
->action
->incol
->bg
3008 && pat
->action
->incol
->bg
[0]
3009 && (color
= color_to_asciirgb(pat
->action
->incol
->bg
))
3010 && (color
= peColorStr(color
,wtmp_20k_buf
))))
3013 Tcl_ListObjAppendElement(interp
, colObj
, Tcl_NewStringObj(color
, -1));
3014 Tcl_ListObjAppendElement(interp
, tObj
, colObj
);
3016 Tcl_ListObjAppendElement(interp
, resObj
, tObj
);
3018 tObj
= Tcl_NewListObj(0, NULL
);
3019 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("indexcolors", -1));
3020 Tcl_ListObjAppendElement(interp
, tObj
, resObj
);
3021 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
3023 else return(TCL_ERROR
);
3027 else if(!strcmp(s1
, "scoreextended")){
3029 long rflags
= ROLE_DO_SCORES
| PAT_USE_CHANGED
;
3033 Tcl_Obj
*resObj
= NULL
, *tObj
= NULL
;
3035 if(Tcl_GetIntFromObj(interp
, objv
[2], &fl
) == TCL_ERROR
)
3038 close_every_pattern();
3039 if(any_patterns(rflags
, &pstate
)){
3040 for(pat
= first_pattern(&pstate
), i
= 0;
3042 pat
= next_pattern(&pstate
), i
++);
3047 /* append the pattern ID */
3048 tObj
= Tcl_NewListObj(0, NULL
);
3049 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("id", -1));
3050 pePatAppendID(interp
, tObj
, pat
);
3051 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
3053 /* append the pattern */
3054 tObj
= Tcl_NewListObj(0, NULL
);
3055 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("pattern", -1));
3056 pePatAppendPattern(interp
, tObj
, pat
);
3057 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
3059 /* now append the filter action */
3060 resObj
= Tcl_NewListObj(0, NULL
);
3061 peAppListF(interp
, resObj
, "%s%l", "scoreval", pat
->action
->scoreval
);
3062 if(pat
->action
->scorevalhdrtok
)
3063 hdr
= hdrtok_to_stringform(pat
->action
->scorevalhdrtok
);
3065 peAppListF(interp
, resObj
, "%s%s", "scorehdr", hdr
? hdr
: "");
3068 fs_give((void **) &hdr
);
3070 tObj
= Tcl_NewListObj(0, NULL
);
3071 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("scores", -1));
3072 Tcl_ListObjAppendElement(interp
, tObj
, resObj
);
3073 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
3075 else return(TCL_ERROR
);
3079 else if(!strcmp(s1
, "clextended")){
3080 int cl
, i
, j
= 0, in_folder_spec
= 0;
3081 struct variable
*vtmp
;
3082 char tpath
[MAILTMPLEN
], *p
;
3085 vtmp
= &wps_global
->vars
[V_FOLDER_SPEC
];
3086 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
)
3088 for(i
= 0; i
< cl
&& (vtmp
->is_changed_val
3089 ? (vtmp
->changed_val
.l
3090 && vtmp
->changed_val
.l
[i
])
3091 : (vtmp
->current_val
.l
3092 && vtmp
->current_val
.l
[i
])); i
++);
3093 if(i
== cl
&& (vtmp
->is_changed_val
3094 ? vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]
3095 : vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]))
3098 vtmp
= &wps_global
->vars
[V_NEWS_SPEC
];
3099 for(j
= 0; i
+ j
< cl
&& (vtmp
->is_changed_val
3100 ? (vtmp
->changed_val
.l
3101 && vtmp
->changed_val
.l
[j
])
3102 : (vtmp
->current_val
.l
3103 && vtmp
->current_val
.l
[j
])); j
++);
3105 if(in_folder_spec
|| (i
+ j
== cl
&& (vtmp
->is_changed_val
3106 ? vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
]
3107 : vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
]))){
3108 ctxt
= new_context(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[in_folder_spec
? i
: j
]
3109 : vtmp
->current_val
.l
[in_folder_spec
? i
: j
], NULL
);
3110 Tcl_ListObjAppendElement(interp
,
3111 Tcl_GetObjResult(interp
),
3112 Tcl_NewStringObj(ctxt
->nickname
? ctxt
->nickname
: "", -1));
3113 Tcl_ListObjAppendElement(interp
,
3114 Tcl_GetObjResult(interp
),
3115 Tcl_NewStringObj(ctxt
->label
? ctxt
->label
: "", -1));
3116 Tcl_ListObjAppendElement(interp
,
3117 Tcl_GetObjResult(interp
),
3118 Tcl_NewStringObj(ctxt
->server
? ctxt
->server
: "", -1));
3121 strncpy(tpath
, (ctxt
->context
[0] == '{'
3122 && (p
= strchr(ctxt
->context
, '}')))
3124 : ctxt
->context
, sizeof(tpath
));
3125 tpath
[sizeof(tpath
)-1] = '\0';
3126 if((p
= strstr(tpath
, "%s")) != NULL
)
3129 Tcl_ListObjAppendElement(interp
,
3130 Tcl_GetObjResult(interp
),
3131 Tcl_NewStringObj(tpath
, -1));
3132 Tcl_ListObjAppendElement(interp
,
3133 Tcl_GetObjResult(interp
),
3134 Tcl_NewStringObj(ctxt
->dir
&& ctxt
->dir
->view
.user
3135 ? ctxt
->dir
->view
.user
: "", -1));
3136 free_context(&ctxt
);
3143 else if(!strcmp(s1
, "rawsig")){
3144 struct variable
*vtmp
;
3145 char *cstring_version
, *sig
, *line
;
3149 vtmp
= &wps_global
->vars
[V_LITERAL_SIG
];
3150 if(vtmp
->is_changed_val
? vtmp
->changed_val
.p
3151 : wps_global
->VAR_LITERAL_SIG
){
3153 wtmp_20k_buf
[0] = '\0';
3154 Tcl_ListObjGetElements(interp
, objv
[2], &nSig
, &objSig
);
3155 for(i
= 0; i
< nSig
&& i
< SIG_MAX_LINES
; i
++)
3156 if((line
= Tcl_GetStringFromObj(objSig
[i
], NULL
)) != NULL
)
3157 snprintf(wtmp_20k_buf
+ strlen(wtmp_20k_buf
), SIZEOF_20KBUF
- strlen(wtmp_20k_buf
), "%.*s\n", SIG_MAX_COLS
, line
);
3159 sig
= cpystr(wtmp_20k_buf
);
3161 if((cstring_version
= string_to_cstring(sig
)) != NULL
){
3162 if(vtmp
->changed_val
.p
)
3163 fs_give((void **)&vtmp
->changed_val
.p
);
3164 vtmp
->is_changed_val
= 1;
3165 vtmp
->changed_val
.p
= cstring_version
;
3168 fs_give((void **) &sig
);
3173 for(i
= 0; peTSig
[i
]; i
++)
3174 fs_give((void **)&peTSig
[i
]);
3175 fs_give((void **)&peTSig
);
3177 Tcl_ListObjGetElements(interp
, objv
[2], &nSig
, &objSig
);
3178 peTSig
= (char **)fs_get(sizeof(char)*(nSig
+ 1));
3179 for(i
= 0; i
< nSig
; i
++){
3180 line
= Tcl_GetStringFromObj(objSig
[i
], NULL
);
3181 peTSig
[i
] = cpystr(line
? line
: "");
3187 else if(!strcmp(s1
, "colorget")){
3189 char tvname
[256], hexcolor
[256];
3190 struct variable
*vtmp
;
3191 if(!(varname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
3194 if(strcmp("viewer-hdr-colors", varname
) == 0){
3195 SPEC_COLOR_S
*hcolors
, *thc
;
3197 char hexcolor
[256], *tstr
= NULL
;
3199 if(wps_global
->vars
[V_VIEW_HDR_COLORS
].is_changed_val
)
3200 hcolors
= spec_colors_from_varlist(wps_global
->vars
[V_VIEW_HDR_COLORS
].changed_val
.l
, 0);
3202 hcolors
= spec_colors_from_varlist(wps_global
->VAR_VIEW_HDR_COLORS
, 0);
3203 for(thc
= hcolors
; thc
; thc
= thc
->next
){
3204 resObj
= Tcl_NewListObj(0,NULL
);
3205 Tcl_ListObjAppendElement(interp
, resObj
,
3206 Tcl_NewStringObj(thc
->spec
, -1));
3207 hex_colorstr(hexcolor
, thc
->fg
);
3208 Tcl_ListObjAppendElement(interp
, resObj
,
3209 Tcl_NewStringObj(hexcolor
, -1));
3210 hex_colorstr(hexcolor
, thc
->bg
);
3211 Tcl_ListObjAppendElement(interp
, resObj
,
3212 Tcl_NewStringObj(hexcolor
, -1));
3213 Tcl_ListObjAppendElement(interp
, resObj
,
3214 Tcl_NewStringObj(thc
->val
3215 ? tstr
= pattern_to_string(thc
->val
)
3217 if(tstr
) fs_give((void **)&tstr
);
3218 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
3221 fs_give((void **)&hcolors
);
3227 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-foreground-color");
3229 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
3230 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
3234 if(!vtmp
->name
) return(TCL_ERROR
);
3235 if(vtmp
->is_list
) return(TCL_ERROR
);
3237 colorp
= (vtmp
->is_changed_val
&& vtmp
->changed_val
.p
)
3238 ? vtmp
->changed_val
.p
3239 : (vtmp
->current_val
.p
) ? vtmp
->current_val
.p
3240 : vtmp
->global_val
.p
;
3243 hex_colorstr(hexcolor
, colorp
);
3244 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
3245 Tcl_NewStringObj(hexcolor
, -1));
3248 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
3249 Tcl_NewStringObj("", -1));
3251 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-background-color");
3253 if((vtmp
->name
&& strucmp(vtmp
->name
, tvname
)) || !vtmp
->name
)
3254 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
3255 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
3259 if(!vtmp
->name
) return(TCL_ERROR
);
3260 if(vtmp
->is_list
) return(TCL_ERROR
);
3262 colorp
= (vtmp
->is_changed_val
&& vtmp
->changed_val
.p
)
3263 ? vtmp
->changed_val
.p
3264 : (vtmp
->current_val
.p
) ? vtmp
->current_val
.p
3265 : vtmp
->global_val
.p
;
3268 hex_colorstr(hexcolor
, colorp
);
3269 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
3270 Tcl_NewStringObj(hexcolor
, -1));
3273 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
3274 Tcl_NewStringObj("", -1));
3278 else if(!strcmp(s1
, "cldel")){
3280 struct variable
*vtmp
;
3283 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
)
3285 vtmp
= &wps_global
->vars
[V_FOLDER_SPEC
];
3286 for(i
= 0; i
< cl
&& (vtmp
->is_changed_val
3287 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3288 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
])); i
++);
3289 if(!(i
== cl
&& (vtmp
->is_changed_val
3290 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3291 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
])))){
3292 vtmp
= &wps_global
->vars
[V_NEWS_SPEC
];
3293 for(j
= 0; i
+ j
< cl
&& (vtmp
->is_changed_val
3294 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3295 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
]));
3297 if(!(vtmp
->is_changed_val
3298 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3299 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
])))
3303 for(n
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[n
])
3304 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[n
]); n
++);
3305 newl
= (char **)fs_get(n
*(sizeof(char *)));
3306 for(n
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[n
])
3307 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[n
]); n
++){
3309 newl
[n
] = cpystr(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[n
]
3310 : vtmp
->current_val
.l
[n
]);
3312 newl
[n
-1] = cpystr(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[n
]
3313 : vtmp
->current_val
.l
[n
]);
3316 vtmp
->is_changed_val
= 1;
3317 for(n
= 0; vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[n
]; n
++)
3318 fs_give((void **) &vtmp
->changed_val
.l
[n
]);
3319 if(vtmp
->changed_val
.l
) fs_give((void **)&vtmp
->changed_val
.l
);
3320 vtmp
->changed_val
.l
= newl
;
3324 else if(!strcmp(s1
, "columns")){
3328 if(Tcl_GetIntFromObj(interp
, objv
[2], &n
) != TCL_ERROR
3329 && n
>= MIN_SCREEN_COLS
3330 && n
< (MAX_SCREEN_COLS
- 1)
3331 && wps_global
->ttyo
->screen_cols
!= n
){
3332 clear_index_cache(sp_inbox_stream(), 0);
3333 wps_global
->ttyo
->screen_cols
= n
;
3334 set_variable(V_WP_COLUMNS
, p
= int2string(n
), 0, 0, Main
);
3335 Tcl_SetResult(interp
, p
, TCL_VOLATILE
);
3338 Tcl_SetResult(interp
, int2string(wps_global
->ttyo
->screen_cols
), TCL_VOLATILE
);
3342 else if(!strcmp(s1
, "reset")){
3345 if((p
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
3346 if(!strcmp(p
,"pinerc")){
3347 struct variable
*var
;
3350 /* new pinerc structure, copy location pointers */
3351 prc
= new_pinerc_s(wps_global
->prc
->name
);
3352 prc
->type
= wps_global
->prc
->type
;
3353 prc
->rd
= wps_global
->prc
->rd
;
3354 prc
->outstanding_pinerc_changes
= 1;
3356 /* tie off original pinerc struct and free it */
3357 wps_global
->prc
->rd
= NULL
;
3358 wps_global
->prc
->outstanding_pinerc_changes
= 0;
3359 free_pinerc_s(&wps_global
->prc
);
3361 /* set global->prc to new struct with no pinerc_lines
3362 * and fool write_pinerc into not writing changed vars
3364 wps_global
->prc
= prc
;
3367 * write at least one var into nearly empty pinerc
3368 * and clear user's var settings. clear global cause
3369 * they'll get reset in peInitVars
3371 for(var
= wps_global
->vars
; var
->name
!= NULL
; var
++){
3372 var
->been_written
= ((var
- wps_global
->vars
) != V_LAST_VERS_USED
);
3374 free_list_array(&var
->main_user_val
.l
);
3375 free_list_array(&var
->global_val
.l
);
3378 fs_give((void **)&var
->main_user_val
.p
);
3379 fs_give((void **)&var
->global_val
.p
);
3383 write_pinerc(wps_global
, Main
, WRP_NOUSER
| WRP_PRESERV_WRITTEN
);
3385 peInitVars(wps_global
);
3392 if(!strcmp(s1
, "varset")){
3393 char *varname
= Tcl_GetStringFromObj(objv
[2], NULL
);
3394 struct variable
*vtmp
;
3395 char **tstrlist
= NULL
, *line
, *tline
;
3397 int i
, strlistpos
, numlistvals
;
3399 if(varname
== NULL
) return(TCL_ERROR
);
3400 for(vtmp
= wps_global
->vars
;
3401 vtmp
->name
&& strucmp(vtmp
->name
, varname
);
3405 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
3408 if(Tcl_ListObjGetElements(interp
, objv
[3], &numlistvals
,
3411 vtmp
->is_changed_val
= 1;
3413 if(vtmp
->changed_val
.l
){
3414 for(i
= 0; vtmp
->changed_val
.l
[i
]; i
++)
3415 fs_give((void **)&vtmp
->changed_val
.l
[i
]);
3416 fs_give((void **)&vtmp
->changed_val
.l
);
3419 tstrlist
= (char **)fs_get((numlistvals
+ 1) * sizeof(char *));
3420 for(i
= 0, strlistpos
= 0; i
< numlistvals
; i
++){
3421 if((line
= Tcl_GetStringFromObj(objVal
[i
], 0)) != NULL
){
3422 tline
= cpystr(line
);
3423 removing_leading_and_trailing_white_space(tline
);
3425 tstrlist
[strlistpos
++] = cpystr(tline
);
3426 fs_give((void **) &tline
);
3430 tstrlist
[strlistpos
] = NULL
;
3431 vtmp
->changed_val
.l
= tstrlist
;
3434 if(vtmp
->changed_val
.p
)
3435 fs_give((void **)&vtmp
->changed_val
.p
);
3437 if((line
= Tcl_GetStringFromObj(objVal
[0], 0)) != NULL
){
3438 tline
= cpystr(line
);
3439 if(strucmp(vtmp
->name
, "reply-indent-string"))
3440 removing_leading_and_trailing_white_space(tline
);
3441 if(!strcmp(tline
, "\"\"")){
3444 else if(tline
[0] == '\0'){
3445 fs_give((void **)&tline
);
3448 vtmp
->changed_val
.p
= cpystr(tline
);
3449 fs_give((void **)&tline
);
3453 vtmp
->changed_val
.p
= cpystr("");
3458 else if(!strcmp(s1
, "feature")){
3460 int i
, set
, wasset
= 0;
3466 * ARGS: featurename -
3467 * value - new value to assign flag
3469 * Returns: 1 if named feature set, 0 otherwise
3472 if((featurename
= Tcl_GetStringFromObj(objv
[2], NULL
))
3473 && Tcl_GetIntFromObj(interp
, objv
[3], &set
) != TCL_ERROR
)
3474 for(i
= 0; (feature
= feature_list(i
)); i
++)
3475 if(!strucmp(featurename
, feature
->name
)){
3476 wps_global
->vars
[V_FEATURE_LIST
].is_changed_val
= 1;
3477 wasset
= F_CH_ON(feature
->id
);
3478 F_CH_SET(feature
->id
, set
);
3482 Tcl_SetResult(interp
, int2string(wasset
), TCL_VOLATILE
);
3485 else if(!strcmp(s1
, "clshuff")){
3486 char *dir
, *tstr
, **newl
;
3487 int cl
, up
= 0, fvarn
, nvarn
, icnt
, i
;
3488 struct variable
*fvar
, *nvar
, *vtmp
;
3490 if(!(dir
= Tcl_GetStringFromObj(objv
[2], NULL
)))
3492 if(Tcl_GetIntFromObj(interp
, objv
[3], &cl
) == TCL_ERROR
)
3494 if(!strcmp(dir
, "up"))
3496 else if(!strcmp(dir
, "down"))
3500 fvar
= &wps_global
->vars
[V_FOLDER_SPEC
];
3501 nvar
= &wps_global
->vars
[V_NEWS_SPEC
];
3502 for(fvarn
= 0; fvar
->is_changed_val
? (fvar
->changed_val
.l
&& fvar
->changed_val
.l
[fvarn
])
3503 : (fvar
->current_val
.l
&& fvar
->current_val
.l
[fvarn
]); fvarn
++);
3504 for(nvarn
= 0; nvar
->is_changed_val
? (nvar
->changed_val
.l
&& nvar
->changed_val
.l
[nvarn
])
3505 : (nvar
->current_val
.l
&& nvar
->current_val
.l
[nvarn
]); nvarn
++);
3510 else if(cl
>= fvarn
&& cl
< nvarn
+ fvarn
){
3516 if(vtmp
== nvar
&& icnt
== 0 && up
){
3517 newl
= (char **)fs_get((fvarn
+ 2)*sizeof(char *));
3518 for(i
= 0; fvar
->is_changed_val
? (fvar
->changed_val
.l
&& fvar
->changed_val
.l
[i
])
3519 : (fvar
->current_val
.l
&& fvar
->current_val
.l
[i
]); i
++)
3520 newl
[i
] = cpystr(fvar
->is_changed_val
? fvar
->changed_val
.l
[i
]
3521 : fvar
->current_val
.l
[i
]);
3522 newl
[i
++] = cpystr(nvar
->is_changed_val
? nvar
->changed_val
.l
[0]
3523 : nvar
->current_val
.l
[0]);
3525 fvar
->is_changed_val
= 1;
3526 for(i
= 0; fvar
->changed_val
.l
&& fvar
->changed_val
.l
[i
]; i
++)
3527 fs_give((void **)&fvar
->changed_val
.l
[i
]);
3528 if(fvar
->changed_val
.l
) fs_give((void **)&fvar
->changed_val
.l
);
3529 fvar
->changed_val
.l
= newl
;
3530 newl
= (char **)fs_get(nvarn
*sizeof(char *));
3531 for(i
= 1; nvar
->is_changed_val
? (nvar
->changed_val
.l
&& nvar
->changed_val
.l
[i
])
3532 : (nvar
->current_val
.l
&& nvar
->current_val
.l
[i
]); i
++)
3533 newl
[i
-1] = cpystr(nvar
->is_changed_val
? nvar
->changed_val
.l
[i
]
3534 : nvar
->current_val
.l
[i
]);
3536 nvar
->is_changed_val
= 1;
3537 for(i
= 0; nvar
->changed_val
.l
&& nvar
->changed_val
.l
[i
]; i
++)
3538 fs_give((void **)&nvar
->changed_val
.l
[i
]);
3539 if(nvar
->changed_val
.l
) fs_give((void **)&nvar
->changed_val
.l
);
3540 nvar
->changed_val
.l
= newl
;
3544 else if(vtmp
== fvar
&& icnt
== fvarn
- 1 && !up
){
3545 newl
= (char **)fs_get(fvarn
*sizeof(char *));
3546 for(i
= 0; fvar
->is_changed_val
? (fvar
->changed_val
.l
&& fvar
->changed_val
.l
[i
+1])
3547 : (fvar
->current_val
.l
&& fvar
->current_val
.l
[i
+1]); i
++)
3548 newl
[i
] = cpystr(fvar
->is_changed_val
? fvar
->changed_val
.l
[i
]
3549 : fvar
->current_val
.l
[i
]);
3551 tstr
= cpystr(fvar
->is_changed_val
? fvar
->changed_val
.l
[i
]
3552 : fvar
->current_val
.l
[i
]);
3553 fvar
->is_changed_val
= 1;
3554 for(i
= 0; fvar
->changed_val
.l
&& fvar
->changed_val
.l
[i
]; i
++)
3555 fs_give((void **)&fvar
->changed_val
.l
[i
]);
3556 if(fvar
->changed_val
.l
) fs_give((void **)&fvar
->changed_val
.l
);
3557 fvar
->changed_val
.l
= newl
;
3558 newl
= (char **)fs_get((nvarn
+2)*sizeof(char *));
3560 for(i
= 0; nvar
->is_changed_val
? (nvar
->changed_val
.l
&& nvar
->changed_val
.l
[i
])
3561 : (nvar
->current_val
.l
&& nvar
->current_val
.l
[i
]); i
++)
3562 newl
[i
+1] = cpystr(nvar
->is_changed_val
? nvar
->changed_val
.l
[i
]
3563 : nvar
->current_val
.l
[i
]);
3565 nvar
->is_changed_val
= 1;
3566 for(i
= 0; nvar
->changed_val
.l
&& nvar
->changed_val
.l
[i
]; i
++)
3567 fs_give((void **)&nvar
->changed_val
.l
[i
]);
3568 if(nvar
->changed_val
.l
) fs_give((void **)&nvar
->changed_val
.l
);
3569 nvar
->changed_val
.l
= newl
;
3574 newl
= (char **)fs_get(((vtmp
== fvar
? fvarn
: nvarn
) + 1)*sizeof(char *));
3575 for(i
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3576 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]); i
++)
3577 newl
[i
] = cpystr(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[i
]
3578 : vtmp
->current_val
.l
[i
]);
3580 vtmp
->is_changed_val
= 1;
3581 for(i
= 0; vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]; i
++)
3582 fs_give((void **)&vtmp
->changed_val
.l
[i
]);
3583 if(vtmp
->changed_val
.l
) fs_give((void **)&vtmp
->changed_val
.l
);
3584 vtmp
->changed_val
.l
= newl
;
3587 tstr
= vtmp
->changed_val
.l
[icnt
-1];
3588 vtmp
->changed_val
.l
[icnt
-1] = vtmp
->changed_val
.l
[icnt
];
3589 vtmp
->changed_val
.l
[icnt
] = tstr
;
3592 tstr
= vtmp
->changed_val
.l
[icnt
+1];
3593 vtmp
->changed_val
.l
[icnt
+1] = vtmp
->changed_val
.l
[icnt
];
3594 vtmp
->changed_val
.l
[icnt
] = tstr
;
3600 if(!strcmp(s1
, "cledit") || !strcmp(s1
, "cladd")){
3601 int add
= 0, cl
, quotes_needed
= 0, i
, j
, newn
;
3602 char *nick
, *server
, *path
, *view
, context_buf
[MAILTMPLEN
*4];
3604 struct variable
*vtmp
;
3606 if(!strcmp(s1
, "cladd")) add
= 1;
3608 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
)
3610 if(!(nick
= Tcl_GetStringFromObj(objv
[3], NULL
)))
3612 if(!(server
= Tcl_GetStringFromObj(objv
[4], NULL
)))
3614 if(!(path
= Tcl_GetStringFromObj(objv
[5], NULL
)))
3616 if(!(view
= Tcl_GetStringFromObj(objv
[6], NULL
)))
3618 removing_leading_and_trailing_white_space(nick
);
3619 removing_leading_and_trailing_white_space(server
);
3620 removing_leading_and_trailing_white_space(path
);
3621 removing_leading_and_trailing_white_space(view
);
3622 if(strchr(nick
, ' '))
3624 if(strlen(nick
)+strlen(server
)+strlen(path
)+strlen(view
) >
3625 MAILTMPLEN
* 4 - 20) { /* for good measure */
3626 Tcl_SetResult(interp
, "info too long", TCL_VOLATILE
);
3629 if(3 + strlen(nick
) + strlen(server
) + strlen(path
) +
3630 strlen(view
) > MAILTMPLEN
+ 4){
3631 Tcl_SetResult(interp
, "collection fields too long", TCL_VOLATILE
);
3634 snprintf(context_buf
, sizeof(context_buf
), "%s%s%s%s%s%s[%s]", quotes_needed
?
3635 "\"" : "", nick
, quotes_needed
? "\"" : "",
3636 strlen(nick
) ? " " : "",
3637 server
, path
, view
);
3639 vtmp
= &wps_global
->vars
[V_NEWS_SPEC
];
3640 if(!(vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[0])
3641 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[0])))
3642 vtmp
= &wps_global
->vars
[V_FOLDER_SPEC
];
3643 for(i
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3644 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]); i
++);
3646 newl
= (char **)fs_get((newn
+ 1)*sizeof(char *));
3647 for(i
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3648 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]); i
++)
3649 newl
[i
] = cpystr(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[i
]
3650 : vtmp
->current_val
.l
[i
]);
3651 newl
[i
++] = cpystr(context_buf
);
3655 vtmp
= &wps_global
->vars
[V_FOLDER_SPEC
];
3656 for(i
= 0; i
< cl
&& (vtmp
->is_changed_val
3657 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3658 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
])); i
++);
3659 if(!(i
== cl
&& (vtmp
->is_changed_val
3660 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3661 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
])))){
3662 vtmp
= &wps_global
->vars
[V_NEWS_SPEC
];
3663 for(j
= 0; i
+ j
< cl
&& (vtmp
->is_changed_val
3664 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3665 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
]));
3667 if(!(vtmp
->is_changed_val
3668 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3669 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
])))
3673 for(j
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3674 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
]); j
++);
3675 newl
= (char **)fs_get(j
* sizeof(char *));
3676 for(j
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3677 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
]); j
++){
3679 newl
[j
] = cpystr(context_buf
);
3681 newl
[j
] = cpystr(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[j
]
3682 : vtmp
->current_val
.l
[j
]);
3686 vtmp
->is_changed_val
= 1;
3687 for(j
= 0; vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
]; j
++)
3688 fs_give((void **)&vtmp
->changed_val
.l
[j
]);
3689 if(vtmp
->changed_val
.l
) fs_give((void **)&vtmp
->changed_val
.l
);
3690 vtmp
->changed_val
.l
= newl
;
3695 err
= "PEInfo: Too many arguments";
3697 Tcl_SetResult(interp
, err
, TCL_STATIC
);
3703 peWriteSig(Tcl_Interp
*interp
, char *file
, Tcl_Obj
**objv
)
3705 int try_cache
, e
, i
, n
, nSig
;
3706 char datebuf
[200], *sig
, *line
;
3711 if(!(file
&& IS_REMOTE(file
))){
3712 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote signature file: %s",
3713 file
? file
: "<null>");
3714 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3719 * We could parse the name here to find what type it is. So far we
3720 * only have type RemImap.
3722 rd
= rd_create_remote(RemImap
, file
, (void *)REMOTE_SIG_SUBTYPE
,
3723 NULL
, "Error: ", "Can't fetch remote signature.");
3725 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Can't create stream for sig file: %s", file
);
3726 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3730 try_cache
= rd_read_metadata(rd
);
3732 if(rd
->access
== MaybeRorW
){
3733 if(rd
->read_status
== 'R')
3734 rd
->access
= ReadOnly
;
3736 rd
->access
= ReadWrite
;
3739 if(rd
->access
!= NoExists
){
3741 rd_check_remvalid(rd
, 1L);
3744 * If the cached info says it is readonly but
3745 * it looks like it's been fixed now, change it to readwrite.
3747 if(rd
->read_status
== 'R'){
3749 * We go to this trouble since readonly sigfiles
3750 * are likely a mistake. They are usually supposed to be
3751 * readwrite so we open it and check if it's been fixed.
3753 rd_check_readonly_access(rd
);
3754 if(rd
->read_status
== 'W'){
3755 rd
->access
= ReadWrite
;
3756 rd
->flags
|= REM_OUTOFDATE
;
3759 rd_close_remdata(&rd
);
3760 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Readonly sig file: %s", file
);
3761 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3766 if(rd
->flags
& REM_OUTOFDATE
){
3767 if(rd_update_local(rd
) != 0){
3769 dprint((1, "pinerc_remote_open: rd_update_local failed"));
3771 * Don't give up altogether. We still may be
3772 * able to use a cached copy.
3776 dprint((7, "%s: copied remote to local (%ld)",
3777 rd
->rn
, (long)rd
->last_use
));
3781 if(rd
->access
== ReadWrite
)
3782 rd
->flags
|= DO_REMTRIM
;
3785 /* If we couldn't get to remote folder, try using the cached copy */
3786 if(rd
->access
== NoExists
|| rd
->flags
& REM_OUTOFDATE
){
3787 rd_close_remdata(&rd
);
3788 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Unavailable sig file: %s", file
);
3789 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3796 wtmp_20k_buf
[0] = '\0';
3798 Tcl_ListObjGetElements(interp
, objv
[0], &nSig
, &objSig
);
3799 for(i
= 0; i
< nSig
&& i
< SIG_MAX_LINES
; i
++){
3800 if((line
= Tcl_GetStringFromObj(objSig
[i
], NULL
)) != NULL
)
3801 snprintf(wtmp_20k_buf
+ strlen(wtmp_20k_buf
), SIZEOF_20KBUF
- strlen(wtmp_20k_buf
), "%.*s\n",
3802 SIG_MAX_COLS
, line
);
3806 for(i
= 0; peTSig
[i
] && i
< SIG_MAX_LINES
; i
++) {
3807 snprintf(wtmp_20k_buf
+ strlen(wtmp_20k_buf
), SIZEOF_20KBUF
- strlen(wtmp_20k_buf
), "%.*s\n",
3808 SIG_MAX_COLS
, peTSig
[i
]);
3810 for(i
= 0; peTSig
[i
]; i
++)
3811 fs_give((void **)&peTSig
[i
]);
3812 fs_give((void **)&peTSig
);
3817 sig
= cpystr(wtmp_20k_buf
);
3819 if((fp
= fopen(rd
->lf
, "w")) != NULL
)
3820 n
= fwrite(sig
, strlen(sig
), 1, fp
);
3822 fs_give((void **) &sig
);
3826 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Sig copy failure1: %s: %s",
3827 rd
->lf
, error_description(errno
));
3828 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3829 rd_close_remdata(&rd
);
3837 rd_close_remdata(&rd
);
3838 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Sig copy open failure2: %s: %s",
3839 rd
->lf
, error_description(errno
));
3840 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3846 if(!rd
->t
.i
.stream
){
3849 rd
->t
.i
.stream
= context_open(NULL
, NULL
, rd
->rn
, 0L, &retflags
);
3852 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
3853 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Sig update failure: %s: %s",
3854 rd
->lf
, error_description(errno
));
3855 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3856 rd_close_remdata(&rd
);
3860 rd_update_metadata(rd
, datebuf
);
3861 rd
->read_status
= 'W';
3862 rd_close_remdata(&rd
);
3868 NAMEVAL_S
*sort_key_rules(int index
)
3870 static NAMEVAL_S is_rules
[] = {
3880 {"Arrival/Reverse", 0},
3881 {"Date/Reverse", 0},
3882 {"Subject/Reverse", 0},
3884 {"From/Reverse", 0},
3886 {"size/Reverse", 0},
3887 {"tHread/Reverse", 0},
3888 {"OrderedSubj/Reverse", 0}
3891 return((index
>= 0 && index
< (sizeof(is_rules
)/sizeof(is_rules
[0])))
3892 ? &is_rules
[index
] : NULL
);
3895 NAMEVAL_S
*wp_indexheight_rules(int index
)
3897 static NAMEVAL_S is_rules
[] = {
3898 {"normal font", "24", 0},
3899 {"smallest font", "20", 0},
3900 {"small font", "22", 0},
3901 {"large font", "28", 0},
3902 {"largest font", "30", 0}
3905 return((index
>= 0 && index
< (sizeof(is_rules
)/sizeof(is_rules
[0])))
3906 ? &is_rules
[index
] : NULL
);
3911 * PEDebugCmd - turn on/off and set various debugging options
3914 PEDebugCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
3918 if(!--objc
){ /* only one arg? */
3919 Tcl_WrongNumArgs(interp
, 1, objv
, "?args?");
3921 else if((s
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
3922 if(!strucmp(s
, "level")){
3926 if(Tcl_GetIntFromObj(interp
, objv
[2], &level
) != TCL_OK
)
3934 dprint((1, "Debug level %d", level
));
3937 dprint((1, "PEDebug ending"));
3942 Tcl_SetResult(interp
, int2string(debug
), TCL_VOLATILE
);
3945 else if(!strucmp(s
, "write")){
3946 if(objc
== 2 && (s
= Tcl_GetStringFromObj(objv
[2], NULL
))){
3948 * script debugging has a high priority since
3949 * statements can be added/removed on the fly
3950 * AND are NOT present by default
3952 dprint((SYSDBG_INFO
, "SCRIPT: %s", s
));
3957 else if(!strucmp(s
, "imap")){
3960 if(Tcl_GetIntFromObj(interp
, objv
[2], &level
) != TCL_OK
)
3965 wps_global
->debug_imap
= 0;
3966 if(wps_global
->mail_stream
)
3967 mail_nodebug(wps_global
->mail_stream
);
3970 else if(level
> 0 && level
< 5){
3972 wps_global
->debug_imap
= level
;
3973 if(wps_global
->mail_stream
)
3974 mail_debug(wps_global
->mail_stream
);
3981 Tcl_SetResult(interp
, "Unknown PEDebug request", TCL_STATIC
);
3989 * PESessionCmd - Export TCL Session-wide command set
3992 PESessionCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
3994 char *op
, *err
= "Unknown PESession option";
3995 char *pe_user
, *pe_host
;
3998 dprint((2, "PESessionCmd"));
4000 if((op
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
4001 if(!strcmp(op
, "open")){
4002 char *s
, *pinerc
, *pineconf
= NULL
;
4005 * CMD: open user remote-pinerc local-default-config
4007 * Initiate a session
4009 * Returns: error string on error, nothing otherwise
4012 if(objc
< 4 || objc
> 5){
4013 Tcl_WrongNumArgs(interp
, 1, objv
, "user password pinerc");
4017 if(!(s
= Tcl_GetStringFromObj(objv
[2], &l
))){
4018 Tcl_SetResult(interp
, "Unknown User", TCL_STATIC
);
4024 pe_user
= cpystr(s
);
4026 #if defined(HAVE_SETENV)
4027 rv
= setenv("WPUSER", pe_user
, 1);
4028 #elif defined(HAVE_PUTENV)
4030 static char putenvbuf
[PUTENV_MAX
];
4032 if(l
+ 8 < PUTENV_MAX
){
4033 if(putenvbuf
[0]) /* only called once, but you never know */
4034 snprintf(putenvbuf
+ 7, PUTENV_MAX
- 7, "%s", pe_user
);
4036 snprintf(putenvbuf
, PUTENV_MAX
, "WPUSER=%s", pe_user
);
4038 rv
= putenv(putenvbuf
);
4046 fs_give((void **) &pe_user
);
4047 Tcl_SetResult(interp
, (errno
== ENOMEM
)
4048 ? "Insufficient Environment Space"
4049 : "Cannot set WPUSER in environment", TCL_STATIC
);
4054 if((pinerc
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
4057 if(mail_valid_net_parse(pinerc
, &mb
)){
4058 pe_host
= cpystr(mb
.host
);
4059 pe_alt
= (mb
.sslflag
|| mb
.tlsflag
);
4062 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote Config: %s", pinerc
);
4063 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
4068 Tcl_SetResult(interp
, "Unknown config location", TCL_STATIC
);
4072 if(objc
== 5 && !(pineconf
= Tcl_GetStringFromObj(objv
[4], NULL
))){
4073 Tcl_SetResult(interp
, "Can't determine global config", TCL_STATIC
);
4077 dprint((SYSDBG_INFO
, "session (%s) %s - %s",
4078 pe_user
, pinerc
, pineconf
? pineconf
: "<none>"));
4080 /* credential cache MUST already be seeded */
4082 /* destroy old user context */
4084 /* destroy open stream */
4085 peDestroyStream(wps_global
);
4087 /* destroy old user context */
4088 peDestroyUserContext(&wps_global
);
4091 /* Establish a user context */
4092 if((s
= peCreateUserContext(interp
, pe_user
, pinerc
, pineconf
)) != NULL
){
4093 Tcl_SetResult(interp
, s
, TCL_VOLATILE
);
4097 fs_give((void **) &pe_user
);
4098 fs_give((void **) &pe_host
);
4102 else if(!strcmp(op
, "close")){
4104 /* destroy any open stream */
4105 peDestroyStream(wps_global
);
4107 /* destroy user context */
4108 peDestroyUserContext(&wps_global
);
4111 Tcl_SetResult(interp
, "BYE", TCL_STATIC
);
4114 else if(!strcmp(op
, "creds")){
4119 err
= "creds: insufficient args";
4121 else if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
4122 && (folder
= Tcl_GetStringFromObj(objv
[3], NULL
))){
4127 * CMD: creds <collection-index> <folder> [user passwd]
4129 * Test for valid credentials to access given folder
4131 * Returns: 1 if so, 0 otherwise
4134 for(i
= 0, cp
= wps_global
? wps_global
->context_list
: NULL
;
4135 i
< 1 || cp
!= NULL
;
4139 char tmp
[MAILTMPLEN
], *p
;
4142 if(folder
[0] == '\0'){
4143 if(cp
->use
& CNTXT_INCMNG
)
4146 folder
= "fake-fake";
4148 else if((cp
->use
& CNTXT_INCMNG
)
4149 && (p
= folder_is_nick(folder
, FOLDERS(cp
), FN_NONE
)))
4153 if(!rv
&& context_allowed(context_apply(tmp
, cp
, folder
, sizeof(tmp
)))){
4156 if(mail_valid_net_parse(tmp
, &mb
)){
4157 if(objc
== 4){ /* check creds */
4158 if(!*mb
.user
&& (p
= alpine_get_user(mb
.host
, (mb
.sslflag
|| mb
.tlsflag
))))
4161 if(alpine_have_passwd(mb
.user
, mb
.host
, (mb
.sslflag
|| mb
.tlsflag
)))
4164 else if(objc
== 6){ /* set creds */
4165 char *user
, *passwd
;
4167 if((user
= Tcl_GetStringFromObj(objv
[4], NULL
))
4168 && (passwd
= Tcl_GetStringFromObj(objv
[5], NULL
))){
4169 if(*mb
.user
&& strcmp(mb
.user
, user
)){
4170 err
= "creds: mismatched user names";
4174 alpine_set_passwd(user
, passwd
, mb
.host
,
4177 || (wps_global
? F_ON(F_PREFER_ALT_AUTH
, wps_global
) : 0));
4181 err
= "creds: unable to read credentials";
4186 err
= "creds: invalid args";
4192 (void) Tcl_ListObjAppendElement(interp
,
4193 Tcl_GetObjResult(interp
),
4198 err
= "creds: Unrecognized collection ID";
4201 err
= "creds: failure to acquire folder and collection ID";
4203 else if(!strcmp(op
, "nocred")){
4208 err
= "No Session active";
4211 err
= "nocred: wrong number of args";
4213 else if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
4214 && (folder
= Tcl_GetStringFromObj(objv
[3], NULL
))){
4219 * CMD: nocred <collection-index> <folder>
4221 * Test for valid credentials to access given folder
4223 * Returns: 1 if so, 0 otherwise
4226 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4229 char tmp
[MAILTMPLEN
], *p
;
4231 if((cp
->use
& CNTXT_INCMNG
)
4232 && (p
= folder_is_nick(folder
, FOLDERS(cp
), FN_NONE
)))
4235 if(context_allowed(context_apply(tmp
, cp
, folder
, sizeof(tmp
)))){
4238 if(mail_valid_net_parse(tmp
, &mb
)){
4239 if(!*mb
.user
&& (p
= alpine_get_user(mb
.host
, (mb
.sslflag
|| mb
.tlsflag
))))
4242 alpine_clear_passwd(mb
.user
, mb
.host
);
4246 (void) Tcl_ListObjAppendElement(interp
,
4247 Tcl_GetObjResult(interp
),
4252 err
= "creds: Unrecognized collection ID";
4255 err
= "creds: failure to acquire folder and collection ID";
4257 else if(!strcmp(op
, "acceptcert")){
4261 if((certhost
= Tcl_GetStringFromObj(objv
[2], NULL
))){
4262 for(p
= &peCertHosts
; *p
; p
= &(*p
)->next
)
4265 *p
= new_strlist(certhost
);
4268 err
= "PESession: no server name";
4270 else if(!strcmp(op
, "random")){
4272 err
= "PESession: random <length>";
4277 if(Tcl_GetIntFromObj(interp
,objv
[2],&l
) != TCL_ERROR
){
4279 Tcl_SetResult(interp
, peRandomString(s
,l
,PRS_MIXED_CASE
), TCL_STATIC
);
4283 err
= "PESession: random length too long";
4286 err
= "PESession: can't get random length";
4289 else if(!strcmp(op
, "authdriver")){
4291 err
= "PESession: authdriver {add | remove} drivername";
4295 if((cmd
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
4296 if((driver
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
4297 if(!strcmp(cmd
,"enable")){
4298 err
= "PESession: authdriver enable disabled for the nonce";
4300 else if(!strcmp(cmd
,"disable")){
4301 if(mail_parameters(NULL
, DISABLE_AUTHENTICATOR
, (void *) driver
)){
4302 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Authentication driver %.30s disabled", driver
);
4303 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
4307 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "PESession: Can't disable %.30s", driver
);
4308 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
4313 err
= "PESession: unknown authdriver operation";
4316 err
= "PESession: Can't read driver name";
4319 err
= "PESesions: Can't read authdriver operation";
4322 else if(!strcmp(op
, "abandon")){
4324 * CMD: abandon [timeout]
4330 err
= "PESession: abandon [timeout]";
4334 if(Tcl_GetLongFromObj(interp
, objv
[2], &t
) == TCL_OK
){
4335 /* ten second minimum and max of default */
4336 if(t
> 0 && t
<= PE_INPUT_TIMEOUT
){
4337 gPEAbandonTimeout
= t
;
4341 err
= "unrecognized timeout";
4344 err
= "Can't read timeout";
4347 else if(!strcmp(op
, "noexpunge")){
4349 * CMD: noexpunge <state>
4355 err
= "PESession: noexpunge <state>";
4359 if(Tcl_GetIntFromObj(interp
, objv
[2], &onoff
) == TCL_OK
){
4360 if(onoff
== 0 || onoff
== 1){
4361 wps_global
->noexpunge_on_close
= onoff
;
4365 err
= "unrecognized on/off state";
4368 err
= "Can't read on/off state";
4371 else if(!strcmp(op
, "setpassphrase")){
4376 err
= "PESession: setpassphrase <state>";
4378 else if((passphrase
= Tcl_GetStringFromObj(objv
[2], NULL
))){
4379 if(wps_global
&& wps_global
->smime
){
4380 strncpy((char *) wps_global
->smime
->passphrase
, passphrase
,
4381 sizeof(wps_global
->smime
->passphrase
));
4382 wps_global
->smime
->passphrase
[sizeof(wps_global
->smime
->passphrase
)-1] = '\0';
4383 wps_global
->smime
->entered_passphrase
= 1;
4384 wps_global
->smime
->need_passphrase
= 0;
4390 err
= "S/MIME not configured for this server";
4393 else if(!strcmp(op
, "expungecheck")) {
4395 * Return open folders and how many deleted messages they have
4397 * return looks something like a list of these:
4398 * {folder-name number-deleted isinbox isincoming}
4405 err
= "PESession: expungecheck <type>";
4408 type
= Tcl_GetStringFromObj(objv
[2], NULL
);
4409 if(type
&& (strcmp(type
, "current") == 0 || strcmp(type
, "quit") == 0)){
4411 if(wps_global
->mail_stream
!= sp_inbox_stream()
4412 || strcmp(type
, "current") == 0){
4413 delete_count
= count_flagged(wps_global
->mail_stream
, F_DEL
);
4414 resObj
= Tcl_NewListObj(0, NULL
);
4415 Tcl_ListObjAppendElement(interp
, resObj
,
4416 Tcl_NewStringObj(pretty_fn(wps_global
->cur_folder
), -1));
4417 Tcl_ListObjAppendElement(interp
, resObj
,
4418 Tcl_NewIntObj(delete_count
));
4419 Tcl_ListObjAppendElement(interp
, resObj
,
4420 Tcl_NewIntObj((wps_global
->mail_stream
4421 == sp_inbox_stream())
4423 Tcl_ListObjAppendElement(interp
, resObj
,
4424 Tcl_NewIntObj((wps_global
->context_current
->use
& CNTXT_INCMNG
)
4426 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
4429 if(strcmp(type
, "quit") == 0){
4430 delete_count
= count_flagged(sp_inbox_stream(), F_DEL
);
4431 resObj
= Tcl_NewListObj(0, NULL
);
4432 Tcl_ListObjAppendElement(interp
, resObj
,
4433 Tcl_NewStringObj("INBOX", -1));
4434 Tcl_ListObjAppendElement(interp
, resObj
,
4435 Tcl_NewIntObj(delete_count
));
4436 Tcl_ListObjAppendElement(interp
, resObj
,
4438 Tcl_ListObjAppendElement(interp
, resObj
,
4440 Tcl_ListObjAppendElement(interp
,
4441 Tcl_GetObjResult(interp
), resObj
);
4446 err
= "PESession: expungecheck unknown type";
4449 else if(!strcmp(op
, "mailcheck")) {
4453 * ARGS: reload -- "1" if we're reloading
4454 * (vs. just checking newmail as a side effect
4455 * of building a new page)
4457 * Return list of folders with new or expunged messages
4459 * return looks something like a list of these:
4460 * {new-count newest-uid announcement-msg}
4462 int reload
, force
= UFU_NONE
, rv
;
4463 time_t now
= time(0);
4466 if(objc
< 3 || Tcl_GetIntFromObj(interp
, objv
[2], &reload
) == TCL_ERROR
)
4469 /* minimum 10 second between IMAP pings */
4470 if(!time_of_last_input() || now
- time_of_last_input() > 10){
4476 peED
.interp
= interp
;
4478 /* check for new mail */
4479 new_mail(force
, reload
? GoodTime
: VeryBadTime
, NM_STATUS_MSG
);
4481 if(!reload
){ /* announced */
4482 zero_new_mail_count();
4488 err
= "PESession: mailcheck <reload>";
4492 Tcl_SetResult(interp
, err
, TCL_STATIC
);
4499 * PEFolderChange - create context's directory chain
4500 * corresponding to list of given obj's
4502 * NOTE: caller should call reset_context_folders(cp) to
4503 * clean up data structures this creates before returning
4506 PEFolderChange(Tcl_Interp
*interp
, CONTEXT_S
*cp
, int objc
, Tcl_Obj
*CONST objv
[])
4512 for(i
= 0; i
< objc
; i
++) {
4513 folder
= Tcl_GetStringFromObj(objv
[i
], NULL
);
4515 Tcl_SetResult(interp
, "PEFolderChange: Can't read folder", TCL_VOLATILE
);
4516 reset_context_folders(cp
);
4520 fp
= next_folder_dir(cp
, folder
, 0, NULL
); /* BUG: mail_stream? */
4521 fp
->desc
= folder_lister_desc(cp
, fp
);
4522 fp
->delim
= cp
->dir
->delim
;
4524 fp
->status
|= CNTXT_SUBDIR
;
4532 * PEMakeFolderString:
4535 PEMakeFolderString(Tcl_Interp
*interp
, CONTEXT_S
*cp
, int objc
, Tcl_Obj
*CONST objv
[], char **ppath
)
4538 unsigned long size
,len
;
4539 char *portion
,*path
;
4542 for(i
= 0; i
< objc
; i
++) {
4543 portion
= Tcl_GetStringFromObj(objv
[i
], NULL
);
4545 Tcl_SetResult(interp
, "PEMakeFolderString: Can't read folder",
4550 size
+= strlen(portion
);
4553 path
= (char*) fs_get(size
+ 1);
4555 for(i
= 0; i
< objc
; i
++) {
4556 portion
= Tcl_GetStringFromObj(objv
[i
], NULL
);
4557 len
= strlen(portion
);
4558 if(i
) path
[size
++] = cp
->dir
->delim
;
4559 memcpy(path
+ size
, portion
, len
);
4563 if(ppath
) *ppath
= path
; else fs_give((void**) &path
);
4569 * PEFolderCmd - export various bits of folder information
4572 PEFolderCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
4574 char *op
, errbuf
[256], *err
= "Unknown PEFolder request";
4576 dprint((2, "PEFolderCmd"));
4579 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
4581 else if((op
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
4584 if(!strcmp(op
, "current")){
4591 * Returns: string representing the name of the
4595 for(i
= 0, cp
= wps_global
->context_list
; cp
&& cp
!= wps_global
->context_current
; i
++, cp
= cp
->next
)
4598 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewIntObj(cp
? i
: 0)) == TCL_OK
4599 && Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(wps_global
->cur_folder
,-1)) == TCL_OK
)
4604 else if(!strcmp(op
, "collections")){
4611 * Returns: List of currently configured collections
4613 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
){
4616 objv
[0] = Tcl_NewIntObj(i
);
4617 objv
[1] = Tcl_NewStringObj(cp
->nickname
? cp
->nickname
: "", -1);
4618 objv
[2] = Tcl_NewStringObj(cp
->label
? cp
->label
: "", -1);
4620 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
4621 Tcl_NewListObj(3, objv
));
4626 else if(!strcmp(op
, "defaultcollection")){
4630 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4631 if(cp
->use
& CNTXT_SAVEDFLT
){
4632 Tcl_SetResult(interp
, int2string(i
), TCL_STATIC
);
4636 err
= "PEFolder: isincoming: Invalid collection ID";
4638 else if(!strcmp(op
, "clextended")){
4641 char tpath
[MAILTMPLEN
], *p
;
4646 * Returns: Extended list of current collections
4649 * 0) Collection Number
4652 * 3) Basically this is a flag to say if we can edit
4658 * had to get rid of this cause the args are changed
4660 * if(strcmp("extended",
4661 * Tcl_GetStringFromObj(objv[2], NULL))){
4662 * Tcl_SetResult(interp, "invalid argument", TCL_VOLATILE);
4663 * return(TCL_ERROR);
4666 for(i
= 0, cp
= wps_global
->context_list
; cp
;
4667 i
++, cp
= cp
->next
){
4670 objv
[0] = Tcl_NewIntObj(i
);
4671 objv
[1] = Tcl_NewStringObj(cp
->nickname
?
4672 cp
->nickname
: "", -1);
4673 objv
[2] = Tcl_NewStringObj(cp
->label
?
4674 cp
->label
: "", -1);
4675 objv
[3] = Tcl_NewIntObj(cp
->var
.v
? 1 : 0);
4676 objv
[4] = Tcl_NewStringObj(cp
->server
?
4677 cp
->server
: "", -1);
4680 strncpy(tpath
, (cp
->context
[0] == '{'
4681 && (p
= strchr(cp
->context
, '}')))
4683 : cp
->context
, sizeof(tpath
));
4684 tpath
[sizeof(tpath
)-1] = '\0';
4685 if((p
= strstr(tpath
, "%s")) != NULL
)
4688 objv
[5] = Tcl_NewStringObj(tpath
, -1);
4689 objv
[6] = Tcl_NewStringObj(cp
->dir
&&
4690 cp
->dir
->view
.user
?
4691 cp
->dir
->view
.user
:
4693 Tcl_ListObjAppendElement(interp
,
4694 Tcl_GetObjResult(interp
),
4695 Tcl_NewListObj(7, objv
));
4701 else if(objc
== 3 && !strcmp(op
, "delimiter")){
4703 char delim
[2] = {'\0', '\0'};
4706 if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
4707 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4709 if(cp
->dir
&& cp
->dir
->delim
)
4710 delim
[0] = cp
->dir
->delim
;
4715 Tcl_SetResult(interp
, delim
[0] ? delim
: "/", TCL_VOLATILE
);
4719 err
= "PEFolder: delimiter: Can't read collection ID";
4721 else if(objc
== 3 && !strcmp(op
, "isincoming")){
4725 if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
4726 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4728 Tcl_SetResult(interp
, int2string(((cp
->use
& CNTXT_INCMNG
) != 0)), TCL_STATIC
);
4732 err
= "PEFolder: isincoming: Invalid collection ID";
4735 err
= "PEFolder: isincoming: Can't read collection ID";
4737 else if(objc
== 4 && !strcmp(op
, "unread")){
4738 char *folder
, tmp
[MAILTMPLEN
];
4739 MAILSTREAM
*mstream
;
4741 long colid
, i
, count
= 0, flags
= (F_UNSEEN
| F_UNDEL
);
4746 * Returns: number of unread messages in given
4749 if(Tcl_GetLongFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
4750 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4755 if((folder
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
4756 /* short circuit INBOX */
4757 if(colid
== 0 && !strucmp(folder
, "inbox")){
4758 count
= count_flagged(sp_inbox_stream(), flags
);
4762 * BUG: some sort of caching to prevent open() fore each call?
4763 * does stream cache offset this?
4765 if(!(context_allowed(context_apply(tmp
, cp
, folder
, sizeof(tmp
)))
4766 && (mstream
= same_stream_and_mailbox(tmp
, wps_global
->mail_stream
)))){
4769 wps_global
->noshow_error
= 1;
4771 mstream
= context_open(cp
, NULL
, folder
,
4772 SP_USEPOOL
| SP_TEMPUSE
| OP_READONLY
| OP_SHORTCACHE
,
4774 wps_global
->noshow_error
= 0;
4777 count
= count_flagged(mstream
, flags
);
4780 pine_mail_close(mstream
);
4783 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
4788 err
= "PEFolder: unread: Invalid collection ID";
4791 err
= "PEFolder: unread: Can't read collection ID";
4793 else if(objc
== 5 && !strcmp(op
, "empty")){
4797 * Returns: number of expunge messages
4799 * Arguments: <colnum> <folder> <what>
4800 * where <what> is either <uid>, 'selected', or 'all'
4803 MAILSTREAM
*stream
= NULL
;
4806 int colid
, i
, our_stream
= 0;
4807 long uid
, raw
, count
= 0L;
4808 char *errstr
= NULL
, *what
, *folder
, *p
, tmp
[MAILTMPLEN
];
4810 if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
4811 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4812 if(i
== colid
) break;
4816 if((folder
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
4817 if((what
= Tcl_GetStringFromObj(objv
[4], NULL
)) != NULL
){
4819 if(!((context_allowed(context_apply(tmp
, cp
, folder
, sizeof(tmp
)))
4820 && (stream
= same_stream_and_mailbox(tmp
, wps_global
->mail_stream
)))
4821 || (stream
= same_stream_and_mailbox(tmp
, sp_inbox_stream())))){
4825 stream
= context_open(cp
, NULL
, folder
, SP_USEPOOL
| SP_TEMPUSE
| OP_SHORTCACHE
, &retflags
);
4829 msgmap
= sp_msgmap(stream
);
4831 if(!strucmp(what
, "all")){
4832 if(mn_get_total(msgmap
)){
4833 agg_select_all(stream
, msgmap
, NULL
, 1);
4834 errstr
= peApplyFlag(stream
, msgmap
, 'd', 0, &count
);
4836 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
4840 /* little complicated since we don't display deleted state and
4841 * don't want to expunge what's not intended.
4842 * remember what's deleted and restore state on the ones left
4843 * when we're done. shouldn't happen much.
4844 * NOTE: "uid" is NOT a UID in this loop
4846 for(uid
= 1L; uid
<= mn_get_total(msgmap
); uid
++){
4847 raw
= mn_m2raw(msgmap
, uid
);
4848 if(!get_lflag(stream
, msgmap
, uid
, MN_EXLD
)
4849 && (mc
= mail_elt(stream
, raw
)) != NULL
4851 set_lflag(stream
, msgmap
, uid
, MN_STMP
, 1);
4852 mail_flag(stream
, long2string(raw
), "\\DELETED", 0L);
4855 set_lflag(stream
, msgmap
, uid
, MN_STMP
, 0);
4858 if(!strucmp(what
,"selected")){
4859 if(any_lflagged(msgmap
, MN_SLCT
)){
4860 if(!(errstr
= peApplyFlag(stream
, msgmap
, 'd', 0, &count
)))
4861 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
4868 for(p
= what
; *p
; p
++)
4869 if(isdigit((unsigned char) *p
)){
4870 uid
= (uid
* 10) + (*p
- '0');
4873 errstr
= "Invalid uid value";
4878 /* uid is a UID here */
4879 mail_flag(stream
, long2string(uid
), "\\DELETED", ST_SET
| ST_UID
);
4880 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
4885 /* restore deleted on what didn't get expunged */
4886 for(uid
= 1L; uid
<= mn_get_total(msgmap
); uid
++){
4887 raw
= mn_m2raw(msgmap
, uid
);
4888 if(get_lflag(stream
, msgmap
, uid
, MN_STMP
)){
4889 set_lflag(stream
, msgmap
, uid
, MN_STMP
, 0);
4890 mail_flag(stream
, long2string(raw
), "\\DELETED", ST_SET
);
4896 pine_mail_close(stream
);
4899 errstr
= "no stream";
4902 errstr
= "Cannot get which ";
4905 errstr
= "Cannot get folder";
4908 errstr
= "Invalid collection";
4911 Tcl_SetResult(interp
, errstr
, TCL_VOLATILE
);
4915 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
4918 else if(!strcmp(op
, "export")){
4922 * Returns: success or failure after writing given
4923 * folder to given local file.
4926 * 0) Collection Number
4928 * 2) Destination file
4936 char *folder
, *dfile
, seq
[64], tmp
[MAILTMPLEN
];
4939 if(Tcl_GetLongFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
4940 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4945 if((folder
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
4946 if((dfile
= Tcl_GetStringFromObj(objv
[4], NULL
)) != NULL
){
4947 if(mail_parameters(NULL
, ENABLE_DRIVER
, "unix")){
4949 snprintf(tmp
, sizeof(tmp
), "#driver.unix/%s", dfile
);
4951 if(pine_mail_create(NULL
, tmp
)){
4953 err
= NULL
; /* reset error condition */
4956 * if not current folder, open a stream, setup the
4957 * stuff to write the raw header/text by hand
4958 * with berkeley delimiters since we don't want
4959 * a local mailbox driver lunk in.
4962 * - BUG: what about logins?
4965 if(!(context_allowed(context_apply(tmp
, cp
, folder
, sizeof(tmp
)))
4966 && (src
= same_stream_and_mailbox(tmp
, wps_global
->mail_stream
)))){
4970 src
= context_open(cp
, NULL
, folder
,
4971 SP_USEPOOL
| SP_TEMPUSE
| OP_READONLY
| OP_SHORTCACHE
,
4975 if(src
&& src
->nmsgs
){
4979 pkg
.msgmax
= src
->nmsgs
;
4980 pkg
.flags
= pkg
.date
= NIL
;
4983 snprintf (seq
,sizeof(seq
),"1:%lu",src
->nmsgs
);
4984 mail_fetchfast (src
, seq
);
4986 wps_global
->noshow_error
= 1;
4987 if(!mail_append_multiple (NULL
, dfile
,
4988 peAppendMsg
, (void *) &pkg
)){
4989 snprintf(err
= errbuf
, sizeof(errbuf
), "PEFolder: export: %.200s",
4990 wps_global
->c_client_error
);
4993 wps_global
->noshow_error
= 0;
4996 pine_mail_close(src
);
4999 err
= "PEFolder: export: can't open mail folder";
5005 err
= "PEFolder: export: can't create destination";
5007 if(!mail_parameters(NULL
, DISABLE_DRIVER
, "unix"))
5008 err
= "PEFolder: export: can't disable driver";
5011 err
= "PEFolder: export: can't enable driver";
5014 err
= "PEFolder: export: can't read file name";
5017 err
= "PEFolder: export: can't read folder name";
5020 err
= "PEFolder: export: Invalid collection ID";
5023 err
= "PEFolder:export: Can't read collection ID";
5026 err
= "PEFolder: export <colid> <folder> <file>";
5028 else if(!strcmp(op
, "import")){
5032 * Returns: success or failure after writing given
5033 * folder to given local file.
5037 * 1) destination collection number
5038 * 2) destination folder
5042 MAILSTREAM
*src
, *dst
;
5046 char *folder
, *sfile
, seq
[64];
5048 /* get source file with a little sanity check */
5049 if((sfile
= Tcl_GetStringFromObj(objv
[2], NULL
))
5050 && *sfile
== '/' && !strstr(sfile
, "..")){
5051 if(mail_parameters(NULL
, ENABLE_DRIVER
, "unix")){
5053 wps_global
->noshow_error
= 1; /* don't queue error msg */
5054 err
= NULL
; /* reset error condition */
5056 /* make sure sfile contains valid mail */
5057 if((src
= mail_open(NULL
, sfile
, 0L)) != NULL
){
5059 if(Tcl_GetLongFromObj(interp
,objv
[3],&colid
) != TCL_ERROR
){
5060 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
5065 if((folder
= Tcl_GetStringFromObj(objv
[4], NULL
)) != NULL
){
5068 if(context_create(cp
, NULL
, folder
)
5069 && (dst
= context_open(cp
, NULL
, folder
, SP_USEPOOL
| SP_TEMPUSE
, &retflags
))){
5075 pkg
.msgmax
= src
->nmsgs
;
5076 pkg
.flags
= pkg
.date
= NIL
;
5079 snprintf (seq
,sizeof(seq
),"1:%lu",src
->nmsgs
);
5080 mail_fetchfast (src
, seq
);
5082 if(!context_append_multiple(cp
, dst
, folder
,
5083 peAppendMsg
, (void *) &pkg
,
5084 wps_global
->mail_stream
)){
5085 snprintf(err
= errbuf
, sizeof(errbuf
), "PEFolder: import: %.200s",
5086 wps_global
->c_client_error
);
5091 pine_mail_close(dst
);
5094 snprintf(err
= errbuf
, sizeof(errbuf
), "PEFolder: import: %.200s",
5095 wps_global
->c_client_error
);
5098 err
= "PEFolder: import: can't read folder name";
5101 err
= "PEFolder:import: invalid collection id";
5104 err
= "PEFolder: import: can't read collection id";
5110 snprintf(err
= errbuf
, sizeof(errbuf
), "PEFolder: import: %.200s",
5111 wps_global
->c_client_error
);
5113 wps_global
->noshow_error
= 0;
5115 if(!mail_parameters(NULL
, DISABLE_DRIVER
, "unix") && !err
)
5116 err
= "PEFolder: import: can't disable driver";
5122 err
= "PEFolder: import: can't enable driver";
5125 err
= "PEFolder: import: can't read file name";
5128 err
= "PEFolder: import <file> <colid> <folder>";
5136 * 3 or more arguments, 3rd is the collection ID, rest
5140 if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
5141 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
5142 if(i
== colid
) break;
5144 else if((colstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
5145 if(!strcmp("default", colstr
))
5146 cp
= default_save_context(wps_global
->context_list
);
5154 if(!strcmp(op
, "list")){
5155 int i
, fcount
, bflags
= BFL_NONE
;
5157 if(PEFolderChange(interp
, cp
, objc
- 3, objv
+ 3) == TCL_ERROR
)
5160 if(cp
->use
& CNTXT_NEWS
)
5163 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
5165 pePrepareForAuthException();
5167 build_folder_list(NULL
, cp
, "*", NULL
, bflags
);
5169 if((aes
= peAuthException()) != NULL
){
5170 Tcl_SetResult(interp
, aes
, TCL_VOLATILE
);
5171 reset_context_folders(cp
);
5175 if((fcount
= folder_total(FOLDERS(cp
))) != 0){
5176 for(i
= 0; i
< fcount
; i
++){
5178 FOLDER_S
*f
= folder_entry(i
, FOLDERS(cp
));
5184 if(f
->hasnochildren
&& !f
->haschildren
)
5190 || (cp
->use
& CNTXT_INCMNG
))
5195 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", type
,
5196 f
->nickname
? f
->nickname
: f
->name
);
5200 reset_context_folders(cp
);
5203 else if(!strucmp(op
, "exists")){
5204 char *folder
, *errstr
= NULL
;
5208 Tcl_SetResult(interp
, "PEFolder exists: No folder specified", TCL_VOLATILE
);
5211 folder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
);
5213 Tcl_SetResult(interp
, "PEFolder exists: Can't read folder", TCL_VOLATILE
);
5217 if(PEFolderChange(interp
, cp
, objc
- 4, objv
+ 3) == TCL_ERROR
)
5220 wps_global
->c_client_error
[0] = '\0';
5221 pePrepareForAuthException();
5223 rv
= folder_name_exists(cp
, folder
, NULL
);
5226 if((errstr
= peAuthException()) == NULL
){
5227 if(wps_global
->c_client_error
[0])
5228 errstr
= wps_global
->c_client_error
;
5230 errstr
= "Indeterminate Error";
5234 Tcl_SetResult(interp
, errstr
? errstr
: int2string((int)(rv
& FEX_ISFILE
)), TCL_VOLATILE
);
5235 return(errstr
? TCL_ERROR
: TCL_OK
);
5237 else if(!strucmp(op
, "fullname")){
5238 char *folder
, *fullname
;
5241 Tcl_SetResult(interp
, "PEFolder fullname: No folder specified", TCL_VOLATILE
);
5244 folder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
);
5246 Tcl_SetResult(interp
, "PEFolder fullname: Can't read folder", TCL_VOLATILE
);
5250 if(PEFolderChange(interp
, cp
, objc
- 4, objv
+ 3) == TCL_ERROR
)
5254 Tcl_Obj
*obj
= Tcl_NewStringObj((fullname
= folder_is_nick(folder
, FOLDERS(cp
)))
5255 ? fullname
: folder
, -1);
5256 (void) Tcl_ListObjAppendElement(interp
,
5257 Tcl_GetObjResult(interp
),
5260 Tcl_SetResult(interp
,
5261 (fullname
= folder_is_nick(folder
, FOLDERS(cp
), FN_NONE
)) ? fullname
: folder
,
5267 else if(!strucmp(op
, "create")){
5270 folder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
);
5272 Tcl_SetResult(interp
, "PEFolder create: Can't read folder", TCL_VOLATILE
);
5276 if(PEFolderChange(interp
, cp
, objc
- 4, objv
+ 3) == TCL_ERROR
)
5279 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
5280 pePrepareForAuthException();
5282 if(!context_create(cp
, NULL
, folder
)){
5283 if((aes
= peAuthException()) != NULL
){
5284 Tcl_SetResult(interp
, aes
, TCL_VOLATILE
);
5287 Tcl_SetResult(interp
,
5288 (wps_global
->last_error
[0])
5289 ? wps_global
->last_error
5290 : (wps_global
->c_client_error
[0])
5291 ? wps_global
->c_client_error
5292 : "Unable to create folder",
5296 reset_context_folders(cp
);
5300 Tcl_SetResult(interp
, "OK", TCL_STATIC
);
5301 reset_context_folders(cp
);
5304 else if(!strucmp(op
, "delete")){
5305 int fi
, readonly
, close_opened
= 0;
5306 char *folder
, *fnamep
, *target
= NULL
, *aes
;
5307 MAILSTREAM
*del_stream
= NULL
, *strm
= NULL
;
5309 PINERC_S
*prc
= NULL
;
5312 folder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
);
5314 Tcl_SetResult(interp
, "PEFolder delete: Can't read folder", TCL_VOLATILE
);
5318 if(PEFolderChange(interp
, cp
, objc
- 4, objv
+ 3) == TCL_ERROR
)
5321 /* so we can check for folder's various properties */
5322 build_folder_list(NULL
, cp
, folder
, NULL
, BFL_NONE
);
5324 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
5326 pePrepareForAuthException();
5328 /* close open folder, then delete */
5330 if((fi
= folder_index(folder
, cp
, FI_FOLDER
)) < 0
5331 || (fp
= folder_entry(fi
, FOLDERS(cp
))) == NULL
){
5332 Tcl_SetResult(interp
, "Cannot find folder to delete", TCL_STATIC
);
5333 reset_context_folders(cp
);
5337 if(!((cp
->use
& CNTXT_INCMNG
) && fp
->name
5338 && check_for_move_mbox(fp
->name
, NULL
, 0, &target
))){
5342 dprint((4, "=== delete_folder(%s) ===\n", folder
? folder
: "?"));
5344 ew
= config_containing_inc_fldr(fp
);
5345 if(wps_global
->restricted
)
5350 prc
= wps_global
->prc
;
5353 prc
= wps_global
->post_prc
;
5359 readonly
= prc
? prc
->readonly
: 1;
5362 if(prc
&& prc
->quit_to_edit
&& (cp
->use
& CNTXT_INCMNG
)){
5363 Tcl_SetResult(interp
, "Must Exit Alpine to Change Configuration", TCL_STATIC
);
5364 reset_context_folders(cp
);
5368 if(cp
== wps_global
->context_list
5369 && !(cp
->dir
&& cp
->dir
->ref
)
5370 && strucmp(folder
, wps_global
->inbox_name
) == 0){
5371 Tcl_SetResult(interp
, "Cannot delete special folder", TCL_STATIC
);
5372 reset_context_folders(cp
);
5375 else if(readonly
&& (cp
->use
& CNTXT_INCMNG
)){
5376 Tcl_SetResult(interp
, "Folder not in editable config file", TCL_STATIC
);
5377 reset_context_folders(cp
);
5381 && (strm
=context_already_open_stream(cp
,fp
->name
,AOS_NONE
)))
5384 && (strm
=context_already_open_stream(NULL
,target
,AOS_NONE
)))){
5385 if(strm
== wps_global
->mail_stream
)
5388 else if(fp
->isdir
|| fp
->isdual
){ /* NO DELETE if directory isn't EMPTY */
5389 FDIR_S
*fdirp
= next_folder_dir(cp
,folder
,TRUE
,NULL
);
5394 else if(fp
->hasnochildren
)
5397 ret
= folder_total(fdirp
->folders
) > 0;
5398 free_fdir(&fdirp
, 1);
5402 Tcl_SetResult(interp
, "Cannot delete non-empty directory", TCL_STATIC
);
5403 reset_context_folders(cp
);
5408 * Folder by the same name exist, so delete both...
5410 Tcl_SetResult(interp, "Cannot delete: folder is also a directory", TCL_STATIC);
5411 reset_context_folders(cp);
5417 if(cp
->use
& CNTXT_INCMNG
){
5418 Tcl_SetResult(interp
, "Cannot delete incoming folder", TCL_STATIC
);
5419 reset_context_folders(cp
);
5423 dprint((2,"deleting \"%s\" (%s) in context \"%s\"\n",
5424 fp
->name
? fp
->name
: "?",
5425 fp
->nickname
? fp
->nickname
: "",
5426 cp
->context
? cp
->context
: "?"));
5429 * Close it, NULL the pointer, and let do_broach_folder fixup
5432 pine_mail_actually_close(strm
);
5434 do_broach_folder(wps_global
->inbox_name
,
5435 wps_global
->context_list
,
5436 NULL
, DB_INBOXWOCNTXT
);
5441 * Use fp->name since "folder" may be a nickname...
5443 if(wps_global
->mail_stream
5444 && context_same_stream(cp
, fp
->name
, wps_global
->mail_stream
))
5445 del_stream
= wps_global
->mail_stream
;
5449 if(!context_delete(cp
, del_stream
, fnamep
)){
5450 if((aes
= peAuthException()) != NULL
){
5451 Tcl_SetResult(interp
, aes
, TCL_VOLATILE
);
5454 Tcl_SetResult(interp
,
5455 (wps_global
->last_error
[0])
5456 ? wps_global
->last_error
5457 : (wps_global
->c_client_error
[0])
5458 ? wps_global
->c_client_error
5459 : "Unable to delete folder",
5463 reset_context_folders(cp
);
5468 Tcl_SetResult(interp
, "OK", TCL_STATIC
);
5469 reset_context_folders(cp
);
5473 * must be at least 5 arguments for the next set of commands
5476 Tcl_SetResult(interp
, "PEFolder: not enough arguments", TCL_VOLATILE
);
5479 else if(!strucmp(op
, "rename")){
5480 char *folder
,*newfolder
, *aes
;
5482 folder
= Tcl_GetStringFromObj(objv
[objc
- 2], NULL
);
5484 Tcl_SetResult(interp
, "PEFolder rename: Can't read folder", TCL_VOLATILE
);
5488 newfolder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
);
5490 Tcl_SetResult(interp
, "PEFolder rename: Can't read folder", TCL_VOLATILE
);
5494 if(PEFolderChange(interp
, cp
, objc
- 5, objv
+ 3) == TCL_ERROR
)
5497 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
5498 pePrepareForAuthException();
5500 if(!context_rename(cp
, NULL
, folder
, newfolder
)){
5501 if((aes
= peAuthException()) != NULL
){
5502 Tcl_SetResult(interp
, aes
, TCL_VOLATILE
);
5505 Tcl_SetResult(interp
,
5506 (wps_global
->last_error
[0])
5507 ? wps_global
->last_error
5508 : (wps_global
->c_client_error
[0])
5509 ? wps_global
->c_client_error
5510 : "Unable to rename folder",
5513 reset_context_folders(cp
);
5516 Tcl_SetResult(interp
, "OK", TCL_STATIC
);
5517 reset_context_folders(cp
);
5522 err
= "PEFolder: Unrecognized collection ID";
5526 err
= "No User Context Established";
5529 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
5535 * PEMailboxCmd - export various bits of mailbox information
5538 PEMailboxCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
5540 char *op
, errbuf
[256], *err
= "Unknown PEMailbox operation";
5542 dprint((5, "PEMailboxCmd"));
5545 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
5547 else if((op
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
5548 if(!strucmp(op
, "open")){
5553 peED
.uid
= 0; /* forget cached embedded data */
5556 * CMD: open <context-index> <folder>
5561 Tcl_SetResult(interp
, (!sp_dead_stream(wps_global
->mail_stream
)) ? "0" : "1", TCL_VOLATILE
);
5565 if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
5566 if((folder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
)) != NULL
) {
5567 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
5569 if(PEMakeFolderString(interp
, cp
, objc
- 3, objv
+ 3,
5573 dprint((1, "* PEMailbox open dir=%s folder=%s",cp
->dir
->ref
,folder
));
5575 return(peCreateStream(interp
, cp
, folder
, FALSE
));
5578 err
= "open: Unrecognized collection ID";
5581 err
= "open: Can't read folder";
5584 err
= "open: Can't get collection ID";
5586 else if(!strcmp(op
, "indexformat")){
5590 * Returns: list of lists where:
5591 * * the first element is the name of the
5592 * field which may be "From", "Subject"
5593 * "Date" or the empty string.
5594 * * the second element which is either
5595 * the percentage width or empty string
5598 return(peIndexFormat(interp
));
5600 else if(wps_global
&& wps_global
->mail_stream
){
5601 if(!strcmp(op
, "select")){
5602 return(peSelect(interp
, objc
- 2, &((Tcl_Obj
**) objv
)[2], MN_SLCT
));
5604 else if(!strcmp(op
, "search")){
5605 return(peSelect(interp
, objc
- 2, &((Tcl_Obj
**) objv
)[2], MN_SRCH
));
5607 else if(!strucmp(op
, "apply")){
5608 return(peApply(interp
, objc
- 2, &((Tcl_Obj
**) objv
)[2]));
5610 else if(!strcmp(op
, "expunge")){
5614 * Returns: OK after having removed deleted messages
5616 char *streamstr
= NULL
;
5620 if(objc
== 3) streamstr
= Tcl_GetStringFromObj(objv
[2], NULL
);
5622 || (streamstr
&& (strcmp(streamstr
, "current") == 0))){
5623 stream
= wps_global
->mail_stream
;
5624 msgmap
= sp_msgmap(stream
);
5626 else if(streamstr
&& (strcmp(streamstr
, "inbox") == 0)){
5627 stream
= sp_inbox_stream();
5628 msgmap
= sp_msgmap(stream
);
5630 else return(TCL_ERROR
);
5631 wps_global
->last_error
[0] = '\0';
5634 msgno_exclude_deleted(stream
, msgmap
, NULL
);
5635 clear_index_cache(sp_inbox_stream(), 0);
5638 * This is kind of surprising at first. For most sort
5639 * orders, if the whole set is sorted, then any subset
5640 * is also sorted. Not so for OrderedSubject sort.
5641 * If you exclude the first message of a subject group
5642 * then you change the date that group is to be sorted on.
5644 if(mn_get_sort(msgmap
) == SortSubject2
)
5645 refresh_sort(wps_global
->mail_stream
, msgmap
, FALSE
);
5648 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
5650 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
5653 else if(!strcmp(op
, "trashdeleted")){
5657 * Returns: OK after moving deleted messages to Trash and expunging
5663 char *streamstr
= NULL
, tmp
[MAILTMPLEN
];
5664 long n
, tomove
= 0L;
5666 if(objc
== 3) streamstr
= Tcl_GetStringFromObj(objv
[2], NULL
);
5668 || (streamstr
&& (strcmp(streamstr
, "current") == 0))){
5669 stream
= wps_global
->mail_stream
;
5670 msgmap
= sp_msgmap(stream
);
5672 else if(streamstr
&& (strcmp(streamstr
, "inbox") == 0)){
5673 stream
= sp_inbox_stream();
5674 msgmap
= sp_msgmap(stream
);
5676 else return(TCL_ERROR
);
5678 wps_global
->last_error
[0] = '\0';
5679 if(IS_NEWS(stream
) && stream
->rdonly
){
5680 msgno_exclude_deleted(stream
, msgmap
, NULL
);
5681 clear_index_cache(sp_inbox_stream(), 0);
5684 * This is kind of surprising at first. For most sort
5685 * orders, if the whole set is sorted, then any subset
5686 * is also sorted. Not so for OrderedSubject sort.
5687 * If you exclude the first message of a subject group
5688 * then you change the date that group is to be sorted on.
5690 if(mn_get_sort(msgmap
) == SortSubject2
)
5691 refresh_sort(wps_global
->mail_stream
, msgmap
, FALSE
);
5694 if(!(cp
= default_save_context(wps_global
->context_list
)))
5695 cp
= wps_global
->context_list
;
5697 /* copy to trash if we're not in trash */
5698 if(wps_global
->VAR_TRASH_FOLDER
5699 && wps_global
->VAR_TRASH_FOLDER
[0]
5700 && context_allowed(context_apply(tmp
, cp
, wps_global
->VAR_TRASH_FOLDER
, sizeof(tmp
)))
5701 && !same_stream_and_mailbox(tmp
, stream
)){
5703 /* save real selected set, and */
5704 for(n
= 1L; n
<= mn_get_total(msgmap
); n
++){
5705 set_lflag(stream
, msgmap
, n
, MN_STMP
, get_lflag(stream
, msgmap
, n
, MN_SLCT
));
5706 /* select deleted */
5707 if(!get_lflag(stream
, msgmap
, n
, MN_EXLD
)
5708 && (mc
= mail_elt(stream
, mn_m2raw(msgmap
,n
))) != NULL
&& mc
->deleted
){
5710 set_lflag(stream
, msgmap
, n
, MN_SLCT
, 1);
5713 set_lflag(stream
, msgmap
, n
, MN_SLCT
, 0);
5716 if(tomove
&& pseudo_selected(stream
, msgmap
)){
5718 /* save deleted to Trash */
5719 n
= save(wps_global
, stream
,
5720 cp
, wps_global
->VAR_TRASH_FOLDER
,
5721 msgmap
, SV_FOR_FILT
| SV_FIX_DELS
);
5723 /* then remove them */
5725 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
5728 restore_selected(msgmap
);
5731 /* restore selected set */
5732 for(n
= 1L; n
<= mn_get_total(msgmap
); n
++)
5733 set_lflag(stream
, msgmap
, n
, MN_SLCT
,
5734 get_lflag(stream
, msgmap
, n
, MN_STMP
));
5738 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
5741 else if(!strcmp(op
, "nextvector")){
5742 long msgno
, count
, countdown
;
5744 char *errstr
= NULL
, *s
;
5745 Tcl_Obj
*rvObj
, *vObj
, *avObj
, **aObj
;
5750 * ARGS: msgno - message number "next" is relative to
5751 * count - how many msgno slots to return
5752 * attrib - (optional) attributes to be returned with each message in vector
5754 * Returns: vector containing next <count> messagenumbers (and optional attributes)
5756 if(objc
== 4 || objc
== 5){
5757 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) == TCL_OK
){
5758 if(Tcl_GetLongFromObj(interp
, objv
[3], &count
) == TCL_OK
){
5760 /* set index range for efficiency */
5761 if(msgno
> 0L && msgno
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
))){
5766 if(objc
== 4 || Tcl_ListObjGetElements(interp
, objv
[4], &aObjN
, &aObj
) == TCL_OK
){
5768 if((rvObj
= Tcl_NewListObj(0, NULL
)) != NULL
&& count
> 0
5769 && !(msgno
< 1L || msgno
> mn_get_total(sp_msgmap(wps_global
->mail_stream
)))){
5770 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
5772 for(countdown
= count
; countdown
> 0; countdown
--){
5773 imapuid_t uid
= mail_uid(wps_global
->mail_stream
, mn_m2raw(sp_msgmap(wps_global
->mail_stream
), msgno
));
5776 if((vObj
= Tcl_NewListObj(0, NULL
)) != NULL
){
5777 Tcl_ListObjAppendElement(interp
, vObj
, Tcl_NewLongObj(msgno
));
5778 peAppListF(interp
, vObj
, "%lu", uid
);
5781 if((avObj
= Tcl_NewListObj(0, NULL
)) != NULL
){
5782 for(i
= 0; i
< aObjN
; i
++){
5783 if((s
= Tcl_GetStringFromObj(aObj
[i
], NULL
)) != NULL
){
5784 if(!strcmp(s
, "statusbits")){
5785 char *s
= peMsgStatBitString(wps_global
, wps_global
->mail_stream
,
5786 sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
),
5787 gPeITop
, gPeICount
, &fetched
);
5788 Tcl_ListObjAppendElement(interp
, avObj
, Tcl_NewStringObj(s
, -1));
5790 else if(!strcmp(s
, "statuslist")){
5791 Tcl_Obj
*nObj
= peMsgStatNameList(interp
, wps_global
, wps_global
->mail_stream
,
5792 sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
),
5793 gPeITop
, gPeICount
, &fetched
);
5794 Tcl_ListObjAppendElement(interp
, avObj
, nObj
);
5796 else if(!strcmp(s
, "status")){
5801 raw
= peSequenceNumber(uid
);
5803 if(!((mc
= mail_elt(wps_global
->mail_stream
, raw
)) && mc
->valid
)){
5804 mail_fetch_flags(wps_global
->mail_stream
,
5805 ulong2string(uid
), FT_UID
);
5806 mc
= mail_elt(wps_global
->mail_stream
, raw
);
5809 stat
[0] = mc
->deleted
? '1' : '0';
5810 stat
[1] = mc
->recent
? '1' : '0';
5811 stat
[2] = mc
->seen
? '1' : '0';
5813 Tcl_ListObjAppendElement(interp
, avObj
, Tcl_NewStringObj(stat
,3));
5815 else if(!strcmp(s
, "indexparts")){
5818 if((iObj
= Tcl_NewListObj(0, NULL
)) != NULL
5819 && peAppendIndexParts(interp
, uid
, iObj
, &fetched
) == TCL_OK
5820 && Tcl_ListObjAppendElement(interp
, avObj
, iObj
) == TCL_OK
){
5825 else if(!strucmp(s
, "indexcolor")){
5826 if(peAppendIndexColor(interp
, uid
, avObj
, &fetched
) != TCL_OK
)
5831 errstr
= "nextvector: can't read attributes";
5836 Tcl_ListObjAppendElement(interp
, vObj
, avObj
);
5839 errstr
= "nextvector: can't allocate attribute return vector";
5845 errstr
= "nextvector: can't allocate new vector";
5849 Tcl_ListObjAppendElement(interp
, rvObj
, vObj
);
5851 for(++msgno
; msgno
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)) && msgline_hidden(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), msgno
, MN_NONE
); msgno
++)
5854 if(msgno
> mn_get_total(sp_msgmap(wps_global
->mail_stream
)))
5860 /* append result vector */
5861 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), rvObj
);
5862 /* Everything is coerced to UTF-8 */
5863 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
5864 Tcl_NewStringObj("UTF-8", -1));
5869 errstr
= "nextvector: can't read attribute list";
5872 errstr
= "nextvector: can't read count";
5875 errstr
= "nextvector: can't read message number";
5878 errstr
= "nextvector: Incorrect number of arguments";
5881 Tcl_SetResult(interp
, errstr
, TCL_STATIC
);
5886 if(!strcmp(op
, "messagecount")){
5890 * Returns: count of messages in open mailbox
5892 Tcl_SetResult(interp
,
5893 long2string(mn_get_total(sp_msgmap(wps_global
->mail_stream
))),
5897 else if(!strcmp(op
, "firstinteresting")){
5899 * CMD: firstinteresting
5901 * Returns: message number associated with
5902 * "incoming-startup-rule" which had better
5903 * be the "current" message since it was set
5904 * in do_broach_folder and shouldn't have been
5905 * changed otherwise (expunged screw us?)
5907 Tcl_SetResult(interp
,
5908 long2string(mn_get_cur(sp_msgmap(wps_global
->mail_stream
))),
5912 else if(!strcmp(op
, "selected")){
5916 * Returns: count of selected messages in open mailbox
5919 Tcl_SetResult(interp
,
5920 long2string(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SLCT
)),
5924 else if(!strcmp(op
, "searched")){
5928 * Returns: count of searched messages in open mailbox
5931 Tcl_SetResult(interp
,
5932 long2string(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SRCH
)),
5936 else if(!strcmp(op
, "mailboxname")){
5940 * Returns: string representing the name of the
5943 Tcl_SetResult(interp
, wps_global
->cur_folder
, TCL_VOLATILE
);
5946 else if(!strcmp(op
, "close")){
5950 * Returns: with global mail_stream closed
5952 peDestroyStream(wps_global
);
5955 else if(!strcmp(op
, "newmailreset")){
5957 zero_new_mail_count();
5958 sp_set_mail_box_changed(wps_global
->mail_stream
, 0);
5959 sp_set_expunge_count(wps_global
->mail_stream
, 0L);
5963 else if(!strcmp(op
, "newmailstatmsg")){
5965 char subject
[500], subjtxt
[500], from
[500], intro
[500], *s
= "";
5968 * CMD: newmailstatmsg
5972 * Returns: text for new mail message
5976 if(sp_mail_box_changed(wps_global
->mail_stream
)
5977 && (count
= sp_mail_since_cmd(wps_global
->mail_stream
))){
5979 for(newest
= wps_global
->mail_stream
->nmsgs
; newest
> 1L; newest
--)
5980 if(!get_lflag(wps_global
->mail_stream
, NULL
, newest
, MN_EXLD
))
5984 format_new_mail_msg(NULL
, count
,
5985 pine_mail_fetchstructure(wps_global
->mail_stream
,
5987 intro
, from
, subject
, subjtxt
, sizeof(subject
));
5989 snprintf(s
= wtmp_20k_buf
, SIZEOF_20KBUF
, "%s %s %s", intro
, from
, subjtxt
);
5993 Tcl_SetResult(interp
, s
, TCL_VOLATILE
);
5996 else if(!strcmp(op
, "savedefault")){
5997 return(peSaveDefault(interp
, 0L, 0, NULL
));
5999 else if(!strcmp(op
, "gotodefault")){
6000 return(peGotoDefault(interp
, 0L, NULL
));
6002 else if(!strcmp(op
, "zoom")){
6003 Tcl_SetResult(interp
,
6004 long2string((any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
) > 0L)
6005 ? any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SLCT
) : 0L),
6009 else if(!strcmp(op
, "focus")){
6010 Tcl_SetResult(interp
,
6011 long2string((any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
) > 0L)
6012 ? any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SRCH
) : 0L),
6016 else if(!strcmp(op
, "first")){
6017 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
)){
6020 for(n
= 1L; n
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); n
++)
6021 if(!get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_HIDE
)){
6022 Tcl_SetResult(interp
, long2string(n
), TCL_VOLATILE
);
6026 unzoom_index(wps_global
, wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
));
6030 Tcl_SetResult(interp
, int2string(1), TCL_VOLATILE
);
6033 else if(!strucmp(op
, "current")){
6035 unsigned long u
= 0;
6042 * Returns: list of current msg {<sequence> <uid>}
6045 if(mn_total_cur(sp_msgmap(wps_global
->mail_stream
)) <= 0
6046 || ((n
= mn_get_cur(sp_msgmap(wps_global
->mail_stream
))) > 0
6047 && (u
= mail_uid(wps_global
->mail_stream
, mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
))) > 0)){
6048 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(long2string(n
), -1));
6049 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(ulong2string(u
), -1));
6053 err
= "Cannot get current";
6055 else if(!strcmp(op
, "last")){
6056 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
)){
6059 for(n
= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); n
> 0L; n
--)
6060 if(!get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_HIDE
)){
6061 Tcl_SetResult(interp
, long2string(n
), TCL_VOLATILE
);
6066 Tcl_SetResult(interp
, long2string(mn_get_total(sp_msgmap(wps_global
->mail_stream
))), TCL_VOLATILE
);
6070 Tcl_SetResult(interp
, "Can't set last message number", TCL_STATIC
);
6073 else if(!strucmp(op
, "sortstyles")){
6078 * Returns: list of supported sort styles
6081 for(i
= 0; wps_global
->sort_types
[i
] != EndofList
; i
++)
6082 if(Tcl_ListObjAppendElement(interp
,
6083 Tcl_GetObjResult(interp
),
6084 Tcl_NewStringObj(sort_name(wps_global
->sort_types
[i
]), -1)) != TCL_OK
)
6089 else if(!strucmp(op
, "sort")){
6090 return(peAppendCurrentSort(interp
));
6092 else if(!strucmp(op
, "state")){
6093 if(!wps_global
->mail_stream
|| sp_dead_stream(wps_global
->mail_stream
))
6094 Tcl_SetResult(interp
, "closed", TCL_STATIC
);
6095 else if(wps_global
->mail_stream
->rdonly
&& !IS_NEWS(wps_global
->mail_stream
))
6096 Tcl_SetResult(interp
, "readonly", TCL_STATIC
);
6098 Tcl_SetResult(interp
, "ok", TCL_STATIC
);
6102 else if(!strucmp(op
, "excludedeleted")){
6103 msgno_exclude_deleted(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), NULL
);
6108 if(!strcmp(op
, "uid")){
6112 * Return uid of given message number
6114 * CMD: uid <msgnumber>
6117 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) != TCL_OK
)
6118 return(TCL_ERROR
); /* conversion problem? */
6120 if((raw
= mn_m2raw(sp_msgmap(wps_global
->mail_stream
), msgno
)) > 0L){
6121 raw
= mail_uid(wps_global
->mail_stream
, raw
);
6122 Tcl_SetResult(interp
, long2string(raw
), TCL_VOLATILE
);
6126 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Invalid UID for message %ld", msgno
);
6127 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
6130 else if(!strcmp(op
, "newmail")){
6131 int reload
, force
= UFU_NONE
, rv
;
6132 time_t now
= time(0);
6137 * ARGS: reload -- "1" if we're reloading
6138 * (vs. just checking newmail as a side effect
6139 * of building a new page)
6144 if(Tcl_GetIntFromObj(interp
, objv
[2], &reload
) == TCL_ERROR
)
6147 /* minimum 10 second between IMAP pings */
6148 if(!time_of_last_input() || now
- time_of_last_input() > 10){
6153 /* check for new mail */
6154 new_mail(force
, reload
? GoodTime
: VeryBadTime
, NM_NONE
);
6156 rv
= peNewMailResult(interp
);
6158 if(!reload
) /* announced */
6159 zero_new_mail_count();
6163 else if(!strcmp(op
, "flagcount")){
6176 * Returns: count - number of message thusly flagged
6179 if(Tcl_ListObjGetElements(interp
, objv
[2], &objlc
, &objlv
) == TCL_OK
){
6181 if((flag
= Tcl_GetStringFromObj(*objlv
++, NULL
)) != NULL
){
6182 if(!strucmp(flag
, "deleted")){
6185 if(!strucmp(flag
, "undeleted")){
6188 else if(!strucmp(flag
, "seen")){
6191 else if(!strucmp(flag
, "unseen")){
6194 else if(!strucmp(flag
, "flagged")){
6197 else if(!strucmp(flag
, "unflagged")){
6200 else if(!strucmp(flag
, "answered")){
6203 else if(!strucmp(flag
, "unanswered")){
6206 else if(!strucmp(flag
, "recent")){
6209 else if(!strucmp(flag
, "unrecent")){
6210 flags
|= F_UNRECENT
;
6215 count
= count_flagged(wps_global
->mail_stream
, flags
);
6218 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
6221 else if(!strcmp(op
, "zoom")){
6223 long n
, zoomed
= 0L;
6228 * Set/clear HID bits of non SLCT messages as requested.
6229 * PEMailbox [first | last | next] are sensitive to these flags.
6231 * ARGS: newstate - 1 or 0
6233 * Returns: count of zoomed messages
6236 if(Tcl_GetIntFromObj(interp
, objv
[2], &newstate
) != TCL_ERROR
){
6238 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
) != (mn_get_total(sp_msgmap(wps_global
->mail_stream
)) - (n
= any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SLCT
)))){
6239 zoom_index(wps_global
, wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MN_SLCT
);
6244 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
))
6245 unzoom_index(wps_global
, wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
));
6249 Tcl_SetResult(interp
, long2string(zoomed
), TCL_VOLATILE
);
6252 else if(!strcmp(op
, "focus")){
6254 long n
, zoomed
= 0L;
6259 * Set/clear HID bits of non MN_SRCH messages as requested.
6260 * PEMailbox [first | last | next] are sensitive to MN_HIDE flag
6262 * ARGS: newstate - 1 or 0
6264 * Returns: count of zoomed messages
6267 if(Tcl_GetIntFromObj(interp
, objv
[2], &newstate
) != TCL_ERROR
){
6269 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
) != (mn_get_total(sp_msgmap(wps_global
->mail_stream
)) - (n
= any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SRCH
))))
6270 zoom_index(wps_global
, wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MN_SRCH
);
6275 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
))
6276 unzoom_index(wps_global
, wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
));
6280 Tcl_SetResult(interp
, long2string(zoomed
), TCL_VOLATILE
);
6283 else if(!strcmp(op
, "next")){
6289 * ARGS: msgno - message number "next" is relative to
6291 * Returns: previous state
6294 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) != TCL_ERROR
){
6295 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
6296 mn_inc_cur(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MH_NONE
);
6297 Tcl_SetResult(interp
, long2string(mn_get_cur(sp_msgmap(wps_global
->mail_stream
))), TCL_VOLATILE
);
6301 Tcl_SetResult(interp
, "next can't read message number", TCL_STATIC
);
6306 if(!strucmp(op
, "sort")){
6307 int i
, reversed
= 0;
6311 * CMD: sort sortstyle reversed
6313 * Returns: OK with the side-effect of message
6314 * numbers now reflecting the requested
6318 if((sort
= Tcl_GetStringFromObj(objv
[2], NULL
))
6319 && Tcl_GetIntFromObj(interp
, objv
[3], &reversed
) != TCL_ERROR
){
6320 /* convert sort string into */
6321 for(i
= 0; wps_global
->sort_types
[i
] != EndofList
; i
++)
6322 if(strucmp(sort_name(wps_global
->sort_types
[i
]), sort
) == 0){
6323 if(sp_unsorted_newmail(wps_global
->mail_stream
)
6324 || !(wps_global
->sort_types
[i
] == mn_get_sort(sp_msgmap(wps_global
->mail_stream
))
6325 && mn_get_revsort(sp_msgmap(wps_global
->mail_stream
)) == reversed
))
6326 sort_folder(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
),
6327 wps_global
->sort_types
[i
],
6334 return(peAppendCurrentSort(interp
));
6336 else if(!strucmp(op
, "selected")){
6337 return(peSelected(interp
, objc
- 2, &((Tcl_Obj
**) objv
)[2], MN_SLCT
));
6339 else if(!strucmp(op
, "searched")){
6340 return(peSelected(interp
, objc
- 2, &((Tcl_Obj
**) objv
)[2], MN_SRCH
));
6342 else if(!strcmp(op
, "next")){
6348 * ARGS: msgno - message number "next" is relative to
6349 * count - how many to increment it
6351 * Returns: previous state
6354 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) != TCL_ERROR
6355 && Tcl_GetLongFromObj(interp
, objv
[3], &count
) != TCL_ERROR
){
6356 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
6359 mn_inc_cur(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MH_NONE
);
6363 mn_dec_cur(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MH_NONE
);
6367 Tcl_SetResult(interp
, long2string(mn_get_cur(sp_msgmap(wps_global
->mail_stream
))), TCL_VOLATILE
);
6371 Tcl_SetResult(interp
, "next can't read message number", TCL_STATIC
);
6374 else if(!strcmp(op
, "x-nextvector")){
6380 * ARGS: msgno - message number "next" is relative to
6381 * count - how many msgno slots to return
6383 * Returns: vector containing next <count> messagenumbers
6386 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) != TCL_ERROR
6387 && Tcl_GetLongFromObj(interp
, objv
[3], &count
) != TCL_ERROR
){
6388 if(count
> 0 && !(msgno
< 1L || msgno
> mn_get_total(sp_msgmap(wps_global
->mail_stream
)))){
6389 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
6392 long n
= mn_get_cur(sp_msgmap(wps_global
->mail_stream
));
6394 if(peAppListF(interp
, Tcl_GetObjResult(interp
),
6395 "%l%l", n
, mail_uid(wps_global
->mail_stream
,
6396 mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
))) != TCL_OK
)
6399 mn_inc_cur(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MH_NONE
);
6401 if(n
== mn_get_cur(sp_msgmap(wps_global
->mail_stream
)))
6409 Tcl_SetResult(interp
, "next can't read message number", TCL_STATIC
);
6412 else if(!strcmp(op
, "messagecount")){
6414 long msgno
, n
, count
= 0L;
6419 * ARGS: [before | after] relative to
6422 * Returns: count of messages before or after given message number
6425 if((relative
= Tcl_GetStringFromObj(objv
[2], NULL
))
6426 && Tcl_GetLongFromObj(interp
, objv
[3], &msgno
) != TCL_ERROR
){
6427 if(msgno
< 1L || msgno
> mn_get_total(sp_msgmap(wps_global
->mail_stream
))){
6428 Tcl_SetResult(interp
, "relative msgno out of range", TCL_STATIC
);
6432 if(!strucmp(relative
, "before")){
6433 for(n
= msgno
- 1; n
> 0L; n
--)
6434 if(!get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_HIDE
))
6437 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
6440 else if(!strucmp(relative
, "after")){
6441 for(n
= msgno
+ 1; n
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); n
++)
6442 if(!get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_HIDE
))
6445 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
6450 Tcl_SetResult(interp
, "can't read range for count", TCL_STATIC
);
6453 else if(!strcmp(op
, "selectvector")){
6459 * ARGS: msgno - message number "next" is relative to
6460 * count - how many msgno slots to return
6462 * Returns: vector containing next <count> messagenumbers
6465 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) != TCL_ERROR
6466 && Tcl_GetLongFromObj(interp
, objv
[3], &count
) != TCL_ERROR
){
6468 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
6470 msgno
= mn_get_cur(sp_msgmap(wps_global
->mail_stream
));
6472 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), msgno
, MN_SLCT
))
6473 if(Tcl_ListObjAppendElement(interp
,
6474 Tcl_GetObjResult(interp
),
6475 Tcl_NewLongObj((long) mail_uid(wps_global
->mail_stream
, msgno
))) != TCL_OK
)
6478 mn_inc_cur(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MH_NONE
);
6480 if(msgno
== mn_get_cur(sp_msgmap(wps_global
->mail_stream
)))
6488 Tcl_SetResult(interp
, "selectvector: no message number", TCL_STATIC
);
6491 else if(!strucmp(op
, "current")){
6493 long x
, n
= 0, u
= 0;
6498 * ARGS: (number|uid) <msgno>
6500 * Returns: list of current msg {<sequence> <uid>}
6502 if((which
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
6503 if(Tcl_GetLongFromObj(interp
, objv
[3], &x
) == TCL_OK
){
6504 if(!strucmp(which
,"uid")){
6506 n
= peMessageNumber(u
);
6508 else if(!strucmp(which
,"number")){
6510 u
= mail_uid(wps_global
->mail_stream
, mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
));
6514 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), n
);
6515 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(long2string(n
), -1));
6516 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(long2string(u
), -1));
6520 err
= "PEMailbox current: invalid number/uid";
6523 err
= "PEMailbox current: cannot get number";
6526 err
= "PEMailbox current: cannot get which";
6530 err
= "PEMailbox: Too many arguments";
6532 else if(!strucmp(op
, "name") || !strcmp(op
, "close")){
6533 Tcl_SetResult(interp
, "", TCL_STATIC
);
6537 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: %s: No open mailbox",
6538 Tcl_GetStringFromObj(objv
[0], NULL
), op
);
6541 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
6547 peAppendCurrentSort(Tcl_Interp
*interp
)
6549 return((Tcl_ListObjAppendElement(interp
,
6550 Tcl_GetObjResult(interp
),
6551 Tcl_NewStringObj(sort_name(mn_get_sort(sp_msgmap(wps_global
->mail_stream
))), -1)) == TCL_OK
6552 && Tcl_ListObjAppendElement(interp
,
6553 Tcl_GetObjResult(interp
),
6554 Tcl_NewStringObj(mn_get_revsort(sp_msgmap(wps_global
->mail_stream
)) ? "1" : "0", 1)) == TCL_OK
)
6555 ? TCL_OK
: TCL_ERROR
);
6560 peAppendDefaultSort(Tcl_Interp
*interp
)
6562 return((Tcl_ListObjAppendElement(interp
,
6563 Tcl_GetObjResult(interp
),
6564 Tcl_NewStringObj(sort_name(wps_global
->def_sort
), -1)) == TCL_OK
6565 && Tcl_ListObjAppendElement(interp
,
6566 Tcl_GetObjResult(interp
),
6567 Tcl_NewStringObj(wps_global
->def_sort_rev
? "1" : "0", 1)) == TCL_OK
)
6568 ? TCL_OK
: TCL_ERROR
);
6573 peSelect(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
6576 long n
, i
, diff
, msgno
;
6579 extern MAILSTREAM
*mm_search_stream
;
6580 extern long mm_search_count
;
6582 hidden
= any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
) > 0L;
6583 mm_search_stream
= wps_global
->mail_stream
;
6584 mm_search_count
= 0L;
6586 for(n
= 1L; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6587 if((mc
= mail_elt(wps_global
->mail_stream
, n
)) != NULL
){
6595 * ARGS: subcmd subcmdargs
6597 * Returns: flip "matchflag" private bit on all or none
6598 * of the messages in the mailbox
6600 if((subcmd
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
){
6601 if(!strucmp(subcmd
, "all")){
6605 if(matchflag
& MN_SLCT
){
6607 return(peSelectError(interp
, subcmd
));
6609 agg_select_all(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), NULL
, 1);
6611 else if(matchflag
& MN_SRCH
){
6612 for(n
= 1L; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6613 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, matchflag
, 1);
6616 Tcl_SetResult(interp
, "All", TCL_VOLATILE
);
6618 else if(!strucmp(subcmd
, "none")){
6624 if(matchflag
& MN_SLCT
){
6626 return(peSelectError(interp
, subcmd
));
6628 agg_select_all(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), &n
, 0);
6630 else if(matchflag
& MN_SRCH
){
6631 for(n
= 1L; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6632 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, matchflag
, 0);
6635 Tcl_SetResult(interp
, long2string(n
), TCL_VOLATILE
);
6637 else if(!strucmp(subcmd
, "searched")){
6641 for(n
= 1L, i
= 0; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6642 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_SRCH
)){
6644 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_SLCT
, 1);
6647 Tcl_SetResult(interp
, long2string(i
), TCL_VOLATILE
);
6649 else if(!strucmp(subcmd
, "unsearched")){
6653 for(n
= 1L, i
= 0; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6654 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_SRCH
)){
6656 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_SLCT
, 0);
6659 Tcl_SetResult(interp
, long2string(i
), TCL_VOLATILE
);
6662 if(!strucmp(subcmd
, "narrow"))
6664 else if(!strucmp(subcmd
, "broad"))
6667 return(peSelectError(interp
, "invalid scope request"));
6669 if(!(subcmd
= Tcl_GetStringFromObj(objv
[1], NULL
)))
6670 return(peSelectError(interp
, "missing subcommand"));
6672 if(!strucmp(subcmd
, "num")){
6673 if((i
= peSelectNumber(interp
, objc
- 2, &objv
[2], matchflag
)) != TCL_OK
)
6676 else if(!strucmp(subcmd
, "date")){
6677 if((i
= peSelectDate(interp
, objc
- 2, &objv
[2], matchflag
)) != TCL_OK
)
6680 else if(!strucmp(subcmd
, "text")){
6681 if((i
= peSelectText(interp
, objc
- 2, &objv
[2], matchflag
)) != TCL_OK
)
6684 else if(!strucmp(subcmd
, "status")){
6685 if((i
= peSelectStatus(interp
, objc
- 2, &objv
[2], matchflag
)) != TCL_OK
)
6688 else if(!strucmp(subcmd
, "compound")){
6690 int nSearchList
, nSearch
;
6691 Tcl_Obj
**oSearchList
, **oSearch
;
6693 /* BUG: should set up one SEARCHPGM to fit criteria and issue single search */
6695 if(Tcl_ListObjGetElements(interp
, objv
[2], &nSearchList
, &oSearchList
) == TCL_OK
){
6696 for(i
= 0; i
< nSearchList
; i
++){
6697 if(Tcl_ListObjGetElements(interp
, oSearchList
[i
], &nSearch
, &oSearch
) == TCL_OK
){
6698 if((s
= Tcl_GetStringFromObj(oSearch
[0], NULL
)) != NULL
){
6699 if(!strucmp(s
,"date")){
6700 if((n
= peSelectDate(interp
, nSearch
- 1, &oSearch
[1], matchflag
)) != TCL_OK
)
6703 else if(!strucmp(s
,"text")){
6704 if((n
= peSelectText(interp
, nSearch
- 1, &oSearch
[1], matchflag
)) != TCL_OK
)
6707 else if(!strucmp(s
,"status")){
6708 if((n
= peSelectStatus(interp
, nSearch
- 1, &oSearch
[1], matchflag
)) != TCL_OK
)
6712 return(peSelectError(interp
, "unknown compound search"));
6714 /* logical AND the results */
6715 mm_search_count
= 0L;
6716 for(n
= 1L; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6717 if((mc
= mail_elt(wps_global
->mail_stream
, n
)) != NULL
){
6718 if(mc
->searched
&& mc
->spare7
)
6721 mc
->searched
= mc
->spare7
= 0;
6725 return(peSelectError(interp
, "malformed compound search"));
6728 return(peSelectError(interp
, "malformed compound search"));
6732 return(peSelectError(interp
, "malformed compound search"));
6735 return(peSelectError(interp
, "cmd cmdargs"));
6738 * at this point all interesting messages should
6739 * have searched bit lit
6742 if(narrow
) /* make sure something was selected */
6743 for(i
= 1L; i
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); i
++)
6744 if(mail_elt(wps_global
->mail_stream
,
6745 mn_m2raw(sp_msgmap(wps_global
->mail_stream
), i
))->searched
){
6746 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
))
6753 if(mm_search_count
){
6755 * loop thru all the messages, adjusting local flag bits
6756 * based on their "searched" bit...
6758 for(i
= 1L, msgno
= 0L; i
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); i
++)
6760 /* turning OFF selectedness if the "searched" bit isn't lit. */
6761 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
)){
6762 if(!mail_elt(wps_global
->mail_stream
,
6763 mn_m2raw(sp_msgmap(wps_global
->mail_stream
), i
))->searched
){
6765 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
, 0);
6767 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, MN_HIDE
, 1);
6769 else if(msgno
< mn_get_cur(sp_msgmap(wps_global
->mail_stream
)))
6773 else if(mail_elt(wps_global
->mail_stream
,mn_m2raw(sp_msgmap(wps_global
->mail_stream
),i
))->searched
){
6774 /* turn ON selectedness if "searched" bit is lit. */
6775 if(!get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
)){
6777 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
, 1);
6779 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, MN_HIDE
, 0);
6783 /* if we're zoomed and the current message was unselected */
6785 && get_lflag(wps_global
->mail_stream
,sp_msgmap(wps_global
->mail_stream
),mn_get_cur(sp_msgmap(wps_global
->mail_stream
)),MN_HIDE
))
6786 mn_reset_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
6789 Tcl_SetResult(interp
, long2string(diff
), TCL_VOLATILE
);
6795 Tcl_SetResult(interp
, "Can't read select option", TCL_STATIC
);
6800 peSelectNumber(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
6803 * Args: [broad | narrow] firstnumber lastnumber
6806 long first
= 0L, last
= 0L, n
;
6809 if(Tcl_GetLongFromObj(interp
, objv
[0], &first
) == TCL_OK
6810 && Tcl_GetLongFromObj(interp
, objv
[1], &last
) == TCL_OK
){
6811 if(last
&& last
< first
){
6817 if(first
>= 1L && first
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
))){
6819 if(last
>= 1L && last
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
))){
6820 for(n
= first
; n
<= last
; n
++)
6821 mm_searched(wps_global
->mail_stream
,
6822 mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
));
6825 return(peSelectError(interp
, "last out of range"));
6828 mm_searched(wps_global
->mail_stream
,
6829 mn_m2raw(sp_msgmap(wps_global
->mail_stream
), first
));
6833 return(peSelectError(interp
, "first out of range"));
6836 return(peSelectError(interp
, "can't read first/last"));
6839 return(peSelectError(interp
, "num first last"));
6845 peSelectDate(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
6848 * Args: [broad | narrow]
6849 * tense - "on", "since", "before"
6850 * year - 4 digit year
6851 * month - abbreviated month "jan", "feb"...
6855 char *tense
, *year
, *month
, *day
, buf
[256];
6858 if((tense
= peSelValTense(objv
[0])) != NULL
){
6859 if((year
= peSelValYear(objv
[1])) != NULL
){
6860 if((month
= peSelValMonth(objv
[2])) != NULL
){
6861 if((day
= peSelValDay(objv
[3])) != NULL
){
6862 snprintf(buf
, sizeof(buf
), "%s %s-%s-%s", tense
, day
, month
, year
);
6863 pine_mail_search_full(wps_global
->mail_stream
, NULL
,
6865 SE_NOPREFETCH
| SE_FREE
);
6868 return(peSelectError(interp
, "<with valid day>"));
6871 return(peSelectError(interp
, "<with valid month>"));
6874 return(peSelectError(interp
, "<with valid year>"));
6877 return(peSelectError(interp
, "<with valid tense>"));
6880 return(peSelectError(interp
, "date tense year monthabbrev daynum"));
6886 peSelectText(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
6889 * Args: [broad | narrow]
6891 * field - to from cc recip partic subj any
6892 * text - free text search string
6898 if((not = peSelValCase(objv
[0])) >= 0){
6899 if((field
= peSelValField(objv
[1])) != '\0'){
6900 if((text
= Tcl_GetStringFromObj(objv
[2], NULL
))
6901 && strlen(text
) < 1024){
6902 /* BUG: fix charset not to be NULL below */
6903 if(agg_text_select(wps_global
->mail_stream
,
6904 sp_msgmap(wps_global
->mail_stream
),
6905 field
, NULL
, not, 0, text
, NULL
, NULL
))
6906 /* BUG: plug in "charset" above? */
6907 return(peSelectError(interp
, "programmer botch"));
6910 return(peSelectError(interp
, "<with search string < 1024>"));
6913 return(peSelectError(interp
, "<with valid field>"));
6916 return(peSelectError(interp
, "<with valid case>"));
6919 return(peSelectError(interp
, "text case field text"));
6925 peSelectStatus(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
6928 * Args: [broad | narrow]
6930 * status - imp new ans del
6936 if((not = peSelValCase(objv
[0])) >= 0){
6937 if((flag
= peSelValFlag(objv
[1])) != '\0'){
6938 if(agg_flag_select(wps_global
->mail_stream
, not, flag
, NULL
))
6939 return(peSelectError(interp
, "programmer botch"));
6942 return(peSelectError(interp
, "<with valid flag>"));
6945 return(peSelectError(interp
, "<with valid case>"));
6948 return(peSelectError(interp
, "status focus case flag"));
6954 peSelValTense(Tcl_Obj
*objp
)
6958 if((tense
= Tcl_GetStringFromObj(objp
, NULL
)) != NULL
){
6959 static char *tenses
[] = {"on", "since", "before", NULL
};
6961 for(pp
= tenses
; *pp
; pp
++)
6962 if(!strucmp(*pp
, tense
))
6971 peSelValYear(Tcl_Obj
*objp
)
6975 return((year
= Tcl_GetStringFromObj(objp
, NULL
))
6976 && strlen(year
) == 4
6977 && isdigit((unsigned char) year
[0])
6978 && isdigit((unsigned char) year
[0])
6979 && isdigit((unsigned char) year
[0])
6986 peSelValMonth(Tcl_Obj
*objp
)
6989 static char *mons
[] = {"jan","feb","mar","apr",
6990 "may","jun","jul","aug",
6991 "sep","oct","nov","dec", NULL
};
6993 if((month
= Tcl_GetStringFromObj(objp
, NULL
)) && strlen(month
) == 3)
6994 for(pp
= mons
; *pp
; pp
++)
6995 if(!strucmp(month
, *pp
))
7003 peSelValDay(Tcl_Obj
*objp
)
7007 return(((day
= Tcl_GetStringFromObj(objp
, NULL
))
7008 && (day
[0] == '0' || day
[0] == '1'
7009 || day
[0] == '2' || day
[0] == '3')
7010 && isdigit((unsigned char) day
[1])
7018 peSelValCase(Tcl_Obj
*objp
)
7022 if((not = Tcl_GetStringFromObj(objp
, NULL
)) != NULL
){
7023 if(!strucmp(not, "ton"))
7025 else if(!strucmp(not, "not"))
7034 peSelValField(Tcl_Obj
*objp
)
7041 } fields
[] = {{"from", 'f'},
7051 if((field
= Tcl_GetStringFromObj(objp
, NULL
)) != NULL
)
7052 for(i
= 0; fields
[i
].field
; i
++)
7053 if(!strucmp(fields
[i
].field
, field
))
7054 return(fields
[i
].type
);
7061 peSelValFlag(Tcl_Obj
*objp
)
7068 } flags
[] = {{"imp", '*'},
7074 if((flag
= Tcl_GetStringFromObj(objp
, NULL
)) != NULL
)
7075 for(i
= 0; flags
[i
].flag
; i
++)
7076 if(!strucmp(flags
[i
].flag
, flag
))
7077 return(flags
[i
].type
);
7083 peSelected(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
7090 * CMD: searched [before | after] #
7092 * Returns: 1 if criteria is true, 0 otherwise
7095 if((range
= Tcl_GetStringFromObj(objv
[0], NULL
))
7096 && Tcl_GetLongFromObj(interp
, objv
[1], &n
) != TCL_ERROR
){
7097 if(!strucmp(range
, "before")){
7098 for(i
= 1L; i
< n
&& i
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); i
++)
7099 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
)){
7104 Tcl_SetResult(interp
, int2string(rv
), TCL_STATIC
);
7107 else if(!strucmp(range
, "after")){
7108 for(i
= n
+ 1L; i
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); i
++)
7109 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
)){
7114 Tcl_SetResult(interp
, int2string(rv
), TCL_STATIC
);
7119 Tcl_SetResult(interp
, "searched test failed", TCL_STATIC
);
7125 peSelectError(Tcl_Interp
*interp
, char *usage
)
7129 snprintf(buf
, sizeof(buf
), "should be select %.128s", usage
);
7130 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
7136 peApply(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
)
7141 if(!(n
= any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SLCT
))){
7142 Tcl_SetResult(interp
, "No messages selected", TCL_STATIC
);
7145 else if((subcmd
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
){
7147 if(!strucmp(subcmd
, "delete")){
7148 /* BUG: is CmdWhere arg always right? */
7149 (void) cmd_delete(wps_global
, sp_msgmap(wps_global
->mail_stream
), MCMD_AGG
| MCMD_SILENT
, NULL
);
7150 Tcl_SetResult(interp
, long2string(n
), TCL_STATIC
);
7153 else if(!strucmp(subcmd
, "undelete")){
7154 (void) cmd_undelete(wps_global
, sp_msgmap(wps_global
->mail_stream
), MCMD_AGG
| MCMD_SILENT
);
7155 Tcl_SetResult(interp
, long2string(n
), TCL_STATIC
);
7160 if(!strucmp(subcmd
, "count")){
7165 long n
, rawno
, count
= 0;
7167 if((flagname
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
7168 for(n
= 1L; n
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); n
++){
7169 rawno
= mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
);
7170 if(get_lflag(wps_global
->mail_stream
, NULL
, rawno
, MN_SLCT
)
7171 && peIsFlagged(wps_global
->mail_stream
,
7172 mail_uid(wps_global
->mail_stream
, rawno
),
7179 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
7184 if(!strucmp(subcmd
, "flag")){
7186 * Args: case - on not
7187 * flag - imp new ans del
7193 if((not = peSelValCase(objv
[1])) >= 0){
7194 if((flag
= peSelValFlag(objv
[2])) != '\0'){
7195 result
= peApplyFlag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), flag
, not, &flagged
);
7197 Tcl_SetResult(interp
, int2string(flagged
), TCL_VOLATILE
);
7201 return(peApplyError(interp
, result
));
7204 return(peApplyError(interp
, "invalid flag"));
7207 return(peApplyError(interp
, "invalid case"));
7209 else if(!strucmp(subcmd
, "save")){
7212 * folder - imp new ans del
7215 int colid
, flgs
= 0, i
;
7219 if(Tcl_GetIntFromObj(interp
, objv
[1], &colid
) != TCL_ERROR
){
7221 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
7223 if((folder
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7224 if(pseudo_selected(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
))){
7226 if(!READONLY_FOLDER(wps_global
->mail_stream
)
7227 && F_OFF(F_SAVE_WONT_DELETE
, wps_global
))
7230 if(colid
== 0 && !strucmp(folder
, "inbox"))
7231 flgs
|= SV_INBOXWOCNTXT
;
7233 i
= save(wps_global
, wps_global
->mail_stream
,
7234 cp
, folder
, sp_msgmap(wps_global
->mail_stream
), flgs
);
7236 err
= (i
== mn_total_cur(sp_msgmap(wps_global
->mail_stream
))) ? NULL
: "problem saving";
7238 restore_selected(sp_msgmap(wps_global
->mail_stream
));
7240 return(peApplyError(interp
, err
));
7242 Tcl_SetResult(interp
, long2string(i
), TCL_VOLATILE
);
7246 return(peApplyError(interp
, "can't select"));
7249 return(peApplyError(interp
, "no folder name"));
7252 return(peApplyError(interp
, "bad colid"));
7255 return(peApplyError(interp
, "invalid case"));
7257 else if(!strucmp(subcmd
, "copy")){
7260 * folder - imp new ans del
7263 int colid
, flgs
= 0, i
;
7267 if(Tcl_GetIntFromObj(interp
, objv
[1], &colid
) != TCL_ERROR
){
7269 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
7271 if((folder
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7272 if(pseudo_selected(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
))){
7274 if(colid
== 0 && !strucmp(folder
, "inbox"))
7275 flgs
|= SV_INBOXWOCNTXT
;
7277 i
= save(wps_global
, wps_global
->mail_stream
,
7278 cp
, folder
, sp_msgmap(wps_global
->mail_stream
), flgs
);
7280 err
= (i
== mn_total_cur(sp_msgmap(wps_global
->mail_stream
))) ? NULL
: "problem copying";
7282 restore_selected(sp_msgmap(wps_global
->mail_stream
));
7284 return(peApplyError(interp
, err
));
7286 Tcl_SetResult(interp
, long2string(i
), TCL_VOLATILE
);
7290 return(peApplyError(interp
, "can't select"));
7293 return(peApplyError(interp
, "no folder name"));
7296 return(peApplyError(interp
, "bad colid"));
7299 return(peApplyError(interp
, "invalid case"));
7301 else if(!strucmp(subcmd
, "move")){
7304 * folder - imp new ans del
7307 int colid
, flgs
= 0, i
;
7311 if(Tcl_GetIntFromObj(interp
, objv
[1], &colid
) != TCL_ERROR
){
7313 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
7315 if((folder
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7316 if(pseudo_selected(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
))){
7320 if(colid
== 0 && !strucmp(folder
, "inbox"))
7321 flgs
|= SV_INBOXWOCNTXT
;
7323 i
= save(wps_global
, wps_global
->mail_stream
,
7324 cp
, folder
, sp_msgmap(wps_global
->mail_stream
), flgs
);
7326 err
= (i
== mn_total_cur(sp_msgmap(wps_global
->mail_stream
))) ? NULL
: "problem moving";
7328 restore_selected(sp_msgmap(wps_global
->mail_stream
));
7330 return(peApplyError(interp
, err
));
7332 Tcl_SetResult(interp
, long2string(i
), TCL_VOLATILE
);
7336 return(peApplyError(interp
, "can't select"));
7339 return(peApplyError(interp
, "no folder name"));
7342 return(peApplyError(interp
, "bad colid"));
7345 return(peApplyError(interp
, "invalid case"));
7347 else if(!strucmp(subcmd
, "spam")){
7352 char *spamaddr
, *spamsubj
= NULL
;
7355 if((spamaddr
= Tcl_GetStringFromObj(objv
[1], NULL
))
7356 && (spamsubj
= Tcl_GetStringFromObj(objv
[2], NULL
))){
7357 for(n
= 1L; n
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); n
++){
7358 rawno
= mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
);
7359 if(get_lflag(wps_global
->mail_stream
, NULL
, rawno
, MN_SLCT
)){
7360 char errbuf
[WP_MAX_POST_ERROR
+ 1], *rs
= NULL
;
7362 if((rs
= peSendSpamReport(rawno
, spamaddr
, spamsubj
, errbuf
)) != NULL
){
7363 Tcl_SetResult(interp
, rs
, TCL_VOLATILE
);
7370 Tcl_SetResult(interp
, "OK", TCL_VOLATILE
);
7376 return(peApplyError(interp
, "unknown option"));
7381 peApplyFlag(MAILSTREAM
*stream
, MSGNO_S
*msgmap
, char flag
, int not, long *flagged
)
7383 char *seq
, *flagstr
;
7388 flagstr
= "\\FLAGGED";
7389 flags
= not ? 0L : ST_SET
;
7390 flagid
= not ? F_FLAG
: F_UNFLAG
;
7394 flags
= not ? ST_SET
: 0L;
7395 flagid
= not ? F_UNSEEN
: F_SEEN
;
7398 flagstr
= "\\ANSWERED";
7399 flags
= not ? 0L : ST_SET
;
7400 flagid
= not ? F_ANS
: F_UNANS
;
7403 flagstr
= "\\DELETED";
7404 flags
= not ? 0L : ST_SET
;
7405 flagid
= not ? F_DEL
: F_UNDEL
;
7408 return("unknown flag");
7412 if(pseudo_selected(stream
, msgmap
)){
7413 if((seq
= currentf_sequence(stream
, msgmap
, flagid
, flagged
, 1, NULL
, NULL
)) != NULL
){
7414 mail_flag(stream
, seq
, flagstr
, flags
);
7415 fs_give((void **) &seq
);
7418 restore_selected(msgmap
);
7422 return("can't select");
7427 peApplyError(Tcl_Interp
*interp
, char *usage
)
7431 snprintf(buf
, sizeof(buf
), "apply error: %.128s", usage
);
7432 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
7438 * peIndexFormat - Return with interp's result object set to
7439 * represent the index line's format as a list of
7440 * index-field-name, percentage-width pairs
7443 peIndexFormat(Tcl_Interp
*interp
)
7445 INDEX_COL_S
*cdesc
= NULL
;
7446 char *name
, wbuf
[4], *dname
;
7448 for(cdesc
= wps_global
->index_disp_format
;
7449 cdesc
->ctype
!= iNothing
;
7452 switch(cdesc
->ctype
){
7471 case iDate
: case iSDate
: case iSTime
: case iLDate
:
7472 case iS1Date
: case iS2Date
: case iS3Date
: case iS4Date
: case iDateIso
:
7474 case iSDateIso
: case iSDateIsoS
:
7475 case iSDateS1
: case iSDateS2
:
7476 case iSDateS3
: case iSDateS4
:
7478 case iSDateTimeIso
: case iSDateTimeIsoS
:
7479 case iSDateTimeS1
: case iSDateTimeS2
:
7480 case iSDateTimeS3
: case iSDateTimeS4
:
7482 case iSDateTimeIso24
: case iSDateTimeIsoS24
:
7483 case iSDateTimeS124
: case iSDateTimeS224
:
7484 case iSDateTimeS324
: case iSDateTimeS424
:
7485 case iCurDate
: case iCurDateIso
: case iCurDateIsoS
:
7486 case iCurTime24
: case iCurTime12
:
7491 case iCurDay
: case iCurDay2Digit
:
7492 case iCurDayOfWeek
: case iCurDayOfWeekAbb
:
7496 case iCurMon
: case iCurMon2Digit
:
7497 case iCurMonLong
: case iCurMonAbb
:
7501 case iTime24
: case iTime12
: case iTimezone
:
7506 case iDay2Digit
: case iDayOfWeek
: case iDayOfWeekAbb
:
7510 case iMonAbb
: case iMon2Digit
:
7514 case iYear
: case iYear2Digit
:
7515 case iCurYear
: case iCurYear2Digit
:
7524 case iFromToNotNews
:
7539 name
= "Recipients";
7555 name
= "Attachments";
7567 case iOpeningTextNQ
:
7576 case iShortSubject
:
7577 case iShortSubjKey
:
7578 case iSubjKeyInitText
:
7579 case iShortSubjKeyInit
:
7588 case iNewsAndRecips
:
7589 name
= "News/Recip";
7592 case iRecipsAndNews
:
7593 name
= "Recip/News";
7601 if(cdesc
->width
> 0){
7602 int p
= ((cdesc
->width
* 100) / FAKE_SCREEN_WIDTH
);
7604 snprintf(wbuf
, sizeof(wbuf
), "%d%%", p
);
7609 if(peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s%s", name
, wbuf
, dname
) != TCL_OK
)
7618 peNewMailResult(Tcl_Interp
*interp
)
7620 unsigned long n
, uid
;
7622 if(sp_mail_box_changed(wps_global
->mail_stream
)){
7623 if((n
= sp_mail_since_cmd(wps_global
->mail_stream
)) != 0L){
7624 /* first element is count of new messages */
7625 if(Tcl_ListObjAppendElement(interp
,
7626 Tcl_GetObjResult(interp
),
7627 Tcl_NewLongObj(n
)) != TCL_OK
)
7630 /* second element is UID of most recent message */
7631 for(uid
= wps_global
->mail_stream
->nmsgs
; uid
> 1L; uid
--)
7632 if(!get_lflag(wps_global
->mail_stream
, NULL
, uid
, MN_EXLD
))
7636 Tcl_ResetResult(interp
);
7637 Tcl_SetResult(interp
, "0 0 0", TCL_STATIC
);
7641 uid
= mail_uid(wps_global
->mail_stream
, uid
);
7643 if(Tcl_ListObjAppendElement(interp
,
7644 Tcl_GetObjResult(interp
),
7645 Tcl_NewLongObj(uid
)) != TCL_OK
)
7649 if(Tcl_ListObjAppendElement(interp
,
7650 Tcl_GetObjResult(interp
),
7651 Tcl_NewIntObj(0)) != TCL_OK
)
7654 /* zero is UID of new message */
7655 if(Tcl_ListObjAppendElement(interp
,
7656 Tcl_GetObjResult(interp
),
7657 Tcl_NewIntObj(0)) != TCL_OK
)
7661 /* third element is expunge count */
7662 if(Tcl_ListObjAppendElement(interp
,
7663 Tcl_GetObjResult(interp
),
7664 Tcl_NewLongObj(sp_expunge_count(wps_global
->mail_stream
)
7665 ? sp_expunge_count(wps_global
->mail_stream
)
7671 Tcl_SetResult(interp
, "0 0 0", TCL_STATIC
);
7677 /* * * * * * * * Start of Per-Thread/SubThread access functions * * * * * * * */
7681 * PEThreadCmd - access/manipulate various pieces of thread state
7684 PEThreadCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
7686 char *err
, errbuf
[256], *cmd
, *op
;
7690 dprint((2, "PEThreadCmd"));
7692 snprintf(err
= errbuf
, sizeof(errbuf
), "Unknown %s request",
7693 Tcl_GetStringFromObj(objv
[0], NULL
));
7695 if(!(wps_global
&& wps_global
->mail_stream
)){
7696 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: No open mailbox",
7697 Tcl_GetStringFromObj(objv
[0], NULL
));
7700 Tcl_WrongNumArgs(interp
, 1, objv
, "uid cmd ?args?");
7702 else if(Tcl_GetLongFromObj(interp
, objv
[1], &uidl
) != TCL_OK
){
7703 return(TCL_ERROR
); /* conversion problem? */
7705 else if(!peSequenceNumber(uidl
)){
7706 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: UID %ld doesn't exist",
7707 Tcl_GetStringFromObj(objv
[0], NULL
), uidl
);
7709 else if((cmd
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7712 if(!strucmp(cmd
,"info")){
7713 #define WP_MAX_THRD_PREFIX 256
7716 char tstr
[WP_MAX_THRD_PREFIX
];
7718 if((raw
= peSequenceNumber(uid
)) != 0L){
7720 * translate PINETHRD_S data into
7722 if((pthrd
= msgno_thread_info(wps_global
->mail_stream
, raw
, NULL
, THD_TOP
)) != NULL
){
7725 /* BUG: build tstr form pthrd */
7728 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
7729 Tcl_NewStringObj(tstr
, -1));
7733 Tcl_SetResult(interp
, "0", TCL_STATIC
);
7740 if(!strucmp(cmd
,"flag")){
7741 if((op
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
7742 if(!strucmp(op
,"deleted")){
7745 if(Tcl_GetIntFromObj(interp
, objv
[4], &value
) != TCL_ERROR
){
7751 if(!(n
= peSequenceNumber(uid
))){
7752 Tcl_SetResult(interp
, "Unrecognized UID", TCL_STATIC
);
7756 flag
= cpystr("\\DELETED");
7757 mail_flag(wps_global
->mail_stream
, long2string(n
), flag
, (value
? ST_SET
: 0L));
7758 fs_give((void **) &flag
);
7760 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
7761 Tcl_NewStringObj(ulong2string(uid
), -1));
7763 if(++n
<= wps_global
->mail_stream
->nmsgs
){
7764 uid
= mail_uid(wps_global
->mail_stream
, n
);
7769 if((pthrd
= msgno_thread_info(wps_global
->mail_stream
, n
, NULL
,THD_TOP
)) != NULL
){
7781 Tcl_SetResult(interp
, err
, TCL_STATIC
);
7787 /* * * * * * * * Start of Per-Message access functions * * * * * * * */
7791 static struct _message_cmds
{
7796 int (*f
)(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
7798 } message_cmds
[] = {
7799 {"size", 1, {{3, peMessageSize
}}},
7800 {"date", 2, {{3, peMessageDate
}, {4, peMessageDate
}}},
7801 {"subject", 1, {{3, peMessageSubject
}}},
7802 {"fromaddr", 1, {{3, peMessageFromAddr
}}},
7803 {"toaddr", 1, {{3, peMessageToAddr
}}},
7804 {"ccaddr", 1, {{3, peMessageCcAddr
}}},
7805 {"status", 1, {{3, peMessageStatus
}}},
7806 {"statusbits", 1, {{3, peMessageStatusBits
}}},
7807 {"charset", 1, {{3, peMessageCharset
}}},
7808 {"number", 1, {{3, peMsgnoFromUID
}}},
7811 {"text", 1, {{3, peMessageText
}}},
7812 {"header", 1, {{3, peMessageHeader
}}},
7813 {"attachments", 1, {{3, peMessageAttachments
}}},
7814 {"body", 3, {{3, peMessageBody
}, {4, peMessageBody
}}},
7815 {"cid", 1, {{4, peMessagePartFromCID
}}},
7816 {"flag", 2, {{4, peGetFlag
}, {5, peSetFlag
}}},
7817 {"replyheaders", 2, {{3, peReplyHeaders
},{4, peReplyHeaders
}}},
7818 {"replytext", 2, {{4, peReplyText
}, {5, peReplyText
}}},
7819 {"forwardheaders", 2, {{3, peForwardHeaders
}, {4, peForwardHeaders
}}},
7820 {"forwardtext", 2, {{3, peForwardText
}, {4, peForwardText
}}},
7822 {"select", 2, {{3, peMsgSelect
}, {4, peMsgSelect
}}},
7823 {"detach", 1, {{5, peDetach
}}},
7824 {"attachinfo", 1, {{4, peAttachInfo
}}},
7825 {"savedefault", 1, {{3, peSaveDefault
}}},
7826 {"save", 1, {{5, peSave
}}},
7827 {"copy", 1, {{5, peCopy
}}},
7828 {"move", 1, {{5, peMove
}}},
7829 {"takeaddr", 1, {{3, peTakeaddr
}}},
7830 {"takefrom", 1, {{3, peTakeFrom
}}},
7831 {"replyquote", 1, {{3, peReplyQuote
}}},
7832 {"bounce", 2, {{4, peMessageBounce
},{5, peMessageBounce
}}},
7833 {"spam", 1, {{5, peMessageSpamNotice
}}},
7834 {"needpasswd", 1, {{3, peMessageNeedPassphrase
}}},
7842 * PEMessageCmd - export various bits of message information
7844 * NOTE: all exported commands are of the form:
7846 * PEMessage <uid> <cmd> <args>
7849 PEMessageCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
7851 char *err
, errbuf
[256], *cmd
;
7856 dprint((5, "PEMessageCmd"));
7858 snprintf(err
= errbuf
, sizeof(errbuf
), "Unknown %s request",
7859 Tcl_GetStringFromObj(objv
[0], NULL
));
7861 if(!(wps_global
&& wps_global
->mail_stream
)){
7862 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: No open mailbox",
7863 Tcl_GetStringFromObj(objv
[0], NULL
));
7866 Tcl_WrongNumArgs(interp
, 0, objv
, "PEMessage <uid> cmd ?args?");
7868 else if(Tcl_GetLongFromObj(interp
, objv
[1], &uidl
) != TCL_OK
){
7869 return(TCL_ERROR
); /* conversion problem? */
7871 else if(!peMessageNumber(uidl
)){
7872 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: UID %ld doesn't exist",
7873 Tcl_GetStringFromObj(objv
[0], NULL
), uidl
);
7875 else if((cmd
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7877 for(i
= 0; message_cmds
[i
].cmd
; i
++)
7878 if(!strcmp(cmd
, message_cmds
[i
].cmd
)){
7879 for(j
= 0; j
< message_cmds
[i
].hcount
; j
++)
7880 if(message_cmds
[i
].h
[j
].argcount
== objc
)
7881 return((*message_cmds
[i
].h
[j
].f
)(interp
, uid
, objc
- 3,
7882 &((Tcl_Obj
**)objv
)[3]));
7884 snprintf(err
= errbuf
, sizeof(errbuf
),
7885 "PEMessage: %s: mismatched argument count", cmd
);
7890 Tcl_SetResult(interp
, err
, TCL_STATIC
);
7896 * return the uid's ordinal number within the CURRENT SORT
7899 peMessageNumber(imapuid_t uid
)
7901 return(mn_raw2m(sp_msgmap(wps_global
->mail_stream
), peSequenceNumber(uid
)));
7905 * return the uid's RAW message number (for c-client reference, primarily)
7908 peSequenceNumber(imapuid_t uid
)
7910 return(mail_msgno(wps_global
->mail_stream
, uid
));
7915 peMessageSize(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7919 if((raw
= peSequenceNumber(uid
))
7920 && pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
)){
7921 Tcl_SetResult(interp
,
7922 long2string(mail_elt(wps_global
->mail_stream
,
7927 Tcl_SetResult(interp
, "0", TCL_STATIC
);
7934 peMessageDate(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7941 if((raw
= peSequenceNumber(uid
))
7942 && (env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
))){
7943 if(objc
== 1 && objv
[0]){
7944 if(mail_parse_date(&mc
, env
->date
)){
7945 if((cmd
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
){
7946 if(!strucmp(cmd
,"day")){
7947 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%02d", mc
.day
);
7948 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
7951 else if(!strucmp(cmd
,"month")){
7952 Tcl_SetResult(interp
, month_abbrev(mc
.month
), TCL_VOLATILE
);
7955 else if(!strucmp(cmd
,"year")){
7956 Tcl_SetResult(interp
, int2string(mc
.year
+ BASEYEAR
), TCL_VOLATILE
);
7960 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "peMessageDate cmd: %.20s", cmd
);
7961 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
7965 Tcl_SetResult(interp
, "peMessageDate: can't get command", TCL_STATIC
);
7968 Tcl_SetResult(interp
, "peMessageDate: can't parse date", TCL_STATIC
);
7971 Tcl_SetResult(interp
, env
->date
? (char *) env
->date
: "", TCL_VOLATILE
);
7976 Tcl_SetResult(interp
, "Can't get message structure", TCL_STATIC
);
7983 peMessageFromAddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7985 return(peMessageField(interp
, uid
, "from"));
7990 peMessageToAddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7992 return(peMessageField(interp
, uid
, "to"));
7997 peMessageCcAddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7999 return(peMessageField(interp
, uid
, "cc"));
8004 peMessageSubject(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8006 return(peMessageField(interp
, uid
, "subject"));
8011 peMessageField(Tcl_Interp
*interp
, imapuid_t uid
, char *field
)
8017 if((raw
= peSequenceNumber(uid
))
8018 && (env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
))){
8019 if(!strucmp(field
, "from")){
8020 if(env
->from
&& env
->from
->mailbox
)
8021 snprintf(s
= wtmp_20k_buf
, SIZEOF_20KBUF
, "%.256s%s%.256s", env
->from
->mailbox
,
8022 (env
->from
->host
) ? "@" : "", (env
->from
->host
) ? env
->from
->host
: "");
8024 else if(!strucmp(field
, "to")){
8025 if(env
->to
&& env
->to
->mailbox
)
8026 snprintf(s
= wtmp_20k_buf
, SIZEOF_20KBUF
, "%.256s%s%.256s", env
->to
->mailbox
,
8027 (env
->to
->host
) ? "@" : "", (env
->to
->host
) ? env
->to
->host
: "");
8029 else if(!strucmp(field
, "cc")){
8030 if(env
->cc
&& env
->cc
->mailbox
)
8031 snprintf(s
= wtmp_20k_buf
, SIZEOF_20KBUF
, "%.256s%s%.256s", env
->cc
->mailbox
,
8032 (env
->cc
->host
) ? "@" : "", (env
->cc
->host
) ? env
->cc
->host
: "");
8034 else if(!strucmp(field
, "subject")){
8036 snprintf(s
= wtmp_20k_buf
, SIZEOF_20KBUF
, "%.256s", env
->subject
);
8039 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Unknown message field: %.20s", field
);
8040 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
8044 Tcl_SetResult(interp
, s
, TCL_VOLATILE
);
8048 Tcl_SetResult(interp
, "Can't read message envelope", TCL_STATIC
);
8054 peMessageStatus(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8059 if((raw
= peSequenceNumber(uid
)) != 0L){
8060 if(!((mc
= mail_elt(wps_global
->mail_stream
, raw
))
8062 mail_fetch_flags(wps_global
->mail_stream
,
8063 ulong2string(uid
), FT_UID
);
8064 mc
= mail_elt(wps_global
->mail_stream
, raw
);
8068 Tcl_ListObjAppendElement(interp
,
8069 Tcl_GetObjResult(interp
),
8070 Tcl_NewStringObj("Deleted", -1));
8073 Tcl_ListObjAppendElement(interp
,
8074 Tcl_GetObjResult(interp
),
8075 Tcl_NewStringObj("Answered", -1));
8078 Tcl_ListObjAppendElement(interp
,
8079 Tcl_GetObjResult(interp
),
8080 Tcl_NewStringObj("New", -1));
8083 Tcl_ListObjAppendElement(interp
,
8084 Tcl_GetObjResult(interp
),
8085 Tcl_NewStringObj("Important", -1));
8093 peMessageCharset(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8095 /* everything coming out of pith better be utf-8 */
8096 Tcl_SetResult(interp
, "UTF-8", TCL_STATIC
);
8102 peMessageNeedPassphrase(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8105 return((wps_global
&& wps_global
->smime
&& wps_global
->smime
->need_passphrase
) ? TCL_OK
: TCL_ERROR
);
8113 peMsgnoFromUID(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8115 Tcl_SetResult(interp
, long2string(peMessageNumber(uid
)), TCL_VOLATILE
);
8121 * peInterpWritec - collect filtered output, appending to the
8122 * command's result list on each EOL
8125 peInterpWritec(int c
)
8127 unsigned char ch
= (unsigned char) (0xff & c
);
8130 return(peInterpFlush() == TCL_OK
);
8132 so_writec(ch
, peED
.store
);
8139 * peInterpFlush - write accumulated line to result object mapping
8140 * embedded data into exportable tcl list members
8146 char *line
, *p
, *tp
, *tp2
, col1
[32], col2
[32];
8147 Tcl_Obj
*lobjp
, *objColor
, *objPair
;
8149 line
= (char *) so_text(peED
.store
);
8151 if((lobjp
= Tcl_NewListObj(0, NULL
)) != NULL
){
8152 if((p
= strindex(line
, TAG_EMBED
)) != NULL
){
8157 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", line
);
8166 for(n
= 0, i
= *++p
; i
> 0; i
--)
8167 n
= (n
* 10) + (*++p
- '0');
8169 line
= ++p
; /* prepare for next section of line */
8174 if((h
= get_handle(peED
.handles
, n
)) != NULL
)
8178 Tcl_Obj
*llObj
, *rObj
;
8180 llObj
= Tcl_NewListObj(0, NULL
);
8181 Tcl_ListObjAppendElement(peED
.interp
, llObj
, Tcl_NewStringObj("img", -1));
8183 rObj
= Tcl_NewListObj(0, NULL
);
8184 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.img
.src
? h
->h
.img
.src
: "", -1));
8185 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.img
.alt
? h
->h
.img
.alt
: "", -1));
8187 Tcl_ListObjAppendElement(peED
.interp
, llObj
, rObj
);
8189 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, llObj
);
8197 Tcl_Obj
*llObj
, *rObj
;
8199 llObj
= Tcl_NewListObj(0, NULL
);
8200 Tcl_ListObjAppendElement(peED
.interp
, llObj
, Tcl_NewStringObj("urlstart", -1));
8202 rObj
= Tcl_NewListObj(0, NULL
);
8203 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.url
.path
? h
->h
.url
.path
: "", -1));
8204 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.url
.name
? h
->h
.url
.name
: "", -1));
8206 Tcl_ListObjAppendElement(peED
.interp
, llObj
, rObj
);
8208 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, llObj
);
8215 Tcl_Obj
*alObj
, *rObj
, *tObj
, *stObj
, *fnObj
, *eObj
;
8217 alObj
= Tcl_NewListObj(0, NULL
);
8218 Tcl_ListObjAppendElement(peED
.interp
, alObj
, Tcl_NewStringObj("attach", -1));
8220 peGetMimeTyping(mail_body(wps_global
->mail_stream
,
8221 peSequenceNumber(peED
.uid
),
8222 (unsigned char *) h
->h
.attach
->number
),
8223 &tObj
, &stObj
, &fnObj
, &eObj
);
8226 rObj
= Tcl_NewListObj(0, NULL
);
8227 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewLongObj(peED
.uid
));
8228 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.attach
->number
, -1));
8229 Tcl_ListObjAppendElement(peED
.interp
, rObj
, tObj
);
8230 Tcl_ListObjAppendElement(peED
.interp
, rObj
, stObj
);
8231 Tcl_ListObjAppendElement(peED
.interp
, rObj
, fnObj
);
8232 Tcl_ListObjAppendElement(peED
.interp
, rObj
, eObj
);
8234 Tcl_ListObjAppendElement(peED
.interp
, alObj
, rObj
);
8236 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, alObj
);
8250 if((tp
= peColorStr(++p
, col1
)) && (strcmp(tp
, peED
.color
.fg
) || strcmp(tp
, peED
.color
.fgdef
))){
8252 if(p
[11] == TAG_EMBED
8253 && p
[12] == TAG_BGCOLOR
8254 && (tp2
= peColorStr(p
+ 13, col2
))){
8255 objColor
= Tcl_NewListObj(0, NULL
);
8256 objPair
= Tcl_NewListObj(0, NULL
);
8257 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8258 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8259 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp2
, -1));
8260 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8261 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8262 strcpy(peED
.color
.bg
, tp2
);
8265 else if(strcmp(peED
.color
.bg
, peED
.color
.bgdef
)){
8266 objColor
= Tcl_NewListObj(0, NULL
);
8267 objPair
= Tcl_NewListObj(0, NULL
);
8268 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8269 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8270 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(peED
.color
.bgdef
, -1));
8271 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8272 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8273 strcpy(peED
.color
.bg
, peED
.color
.bgdef
);
8276 peAppListF(peED
.interp
, lobjp
, "%s%s", "fgcolor", tp
);
8278 strcpy(peED
.color
.fg
, tp
);
8285 if((tp
= peColorStr(++p
, col1
)) && (strcmp(tp
, peED
.color
.bg
) || strcmp(tp
, peED
.color
.bgdef
))){
8287 if(p
[11] == TAG_EMBED
8288 && p
[12] == TAG_FGCOLOR
8289 && (tp2
= peColorStr(p
+ 13, col2
))){
8290 objColor
= Tcl_NewListObj(0, NULL
);
8291 objPair
= Tcl_NewListObj(0, NULL
);
8292 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8293 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp2
, -1));
8294 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8295 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8296 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8297 strcpy(peED
.color
.fg
, tp2
);
8300 else if(strcmp(peED
.color
.fg
, peED
.color
.fgdef
)){
8301 objColor
= Tcl_NewListObj(0, NULL
);
8302 objPair
= Tcl_NewListObj(0, NULL
);
8303 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8304 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(peED
.color
.fgdef
, -1));
8305 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8306 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8307 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8308 strcpy(peED
.color
.fg
, peED
.color
.fgdef
);
8311 peAppListF(peED
.interp
, lobjp
, "%s%s", "bgcolor", tp
);
8313 strcpy(peED
.color
.bg
, tp
);
8320 peAppListF(peED
.interp
, lobjp
, "%s%s", "italic", "on");
8324 case TAG_ITALICOFF
:
8325 peAppListF(peED
.interp
, lobjp
, "%s%s", "italic", "off");
8330 peAppListF(peED
.interp
, lobjp
, "%s%s", "bold", "on");
8335 peAppListF(peED
.interp
, lobjp
, "%s%s", "bold", "off");
8340 peAppListF(peED
.interp
, lobjp
, "%s%s", "underline", "on");
8345 peAppListF(peED
.interp
, lobjp
, "%s%s", "underline", "off");
8350 peAppListF(peED
.interp
, lobjp
, "%s%s", "strikethru", "on");
8354 case TAG_STRIKEOFF
:
8355 peAppListF(peED
.interp
, lobjp
, "%s%s", "strikethru", "off");
8360 peAppListF(peED
.interp
, lobjp
, "%s%s", "bigfont", "on");
8365 peAppListF(peED
.interp
, lobjp
, "%s%s", "bigfont", "off");
8370 peAppListF(peED
.interp
, lobjp
, "%s%s", "smallfont", "on");
8375 peAppListF(peED
.interp
, lobjp
, "%s%s", "smallfont", "off");
8380 case TAG_HANDLEOFF
:
8382 peAppListF(peED
.interp
, lobjp
, "%s%s", "urlend", "");
8385 /* fall thru and advance "line" */
8393 while((p
= strindex(line
, TAG_EMBED
)) != NULL
);
8396 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", line
);
8399 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", line
);
8402 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", "");
8404 if(Tcl_ListObjAppendElement(peED
.interp
, peED
.obj
, lobjp
) == TCL_OK
){
8405 so_truncate(peED
.store
, 0L);
8415 * peInterpWritec - collect filtered output, appending to the
8416 * command's result list on each EOL
8426 peColorStr(char *s
, char *b
)
8434 for(j
= 0; j
< 3; j
++, s
++)
8435 if(isdigit((unsigned char) *s
))
8436 color
= (color
* 10) + (*s
- '0');
8438 s
++; /* advance past ',' */
8440 sprintf(b
+ strlen(b
), "%2.2x", color
);
8454 * returns a list of elements
8457 peMessageHeader(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8461 int flags
, rv
= TCL_OK
;
8468 * ONLY full header mode (raw) output should get written to the
8469 * writec function we pass format_header. If there's something
8470 * in the store after formatting ,we'll write it to the Tcl result
8471 * then, not as its accumulated
8473 peED
.interp
= interp
;
8474 peED
.obj
= Tcl_NewStringObj("", -1);
8477 so_seek(peED
.store
, 0L, 0);
8479 peED
.store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
8481 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_NOHTMLREL
| FM_HTMLRELATED
;
8484 peED
.color
.fg
[0] = '\0';
8485 if((color
= pico_get_last_fg_color()) && (color
= color_to_asciirgb(color
))){
8486 peInterpWritec(TAG_EMBED
);
8487 peInterpWritec(TAG_FGCOLOR
);
8488 gf_puts(color
, peInterpWritec
);
8489 strcpy(peED
.color
.fgdef
, peColorStr(color
, wtmp_20k_buf
));
8492 peED
.color
.bg
[0] = '\0';
8493 if((color
= pico_get_last_bg_color()) && (color
= color_to_asciirgb(color
))){
8494 peInterpWritec(TAG_EMBED
);
8495 peInterpWritec(TAG_BGCOLOR
);
8496 gf_puts(color
, peInterpWritec
);
8497 strcpy(peED
.color
.bgdef
, peColorStr(color
,wtmp_20k_buf
));
8503 raw
= peSequenceNumber(uid
);
8504 if(peED
.uid
!= uid
){
8508 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
8509 if(!((peED
.env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, &peED
.body
))
8510 && (mc
= mail_elt(wps_global
->mail_stream
, raw
)))){
8513 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
8514 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate");
8516 dprint((1, "ERROR fetching %s of msg %ld: %s",
8517 peED
.env
? "elt" : "env", mn_get_cur(sp_msgmap(wps_global
->mail_stream
)),
8518 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate"));
8520 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8524 zero_atmts(wps_global
->atmts
);
8526 if(wps_global
&& wps_global
->smime
&& wps_global
->smime
->need_passphrase
)
8527 wps_global
->smime
->need_passphrase
= 0;
8529 fiddle_smime_message(peED
.body
, raw
);
8531 describe_mime(peED
.body
, "", 1, 1, 0, flags
);
8535 /* NO HANDLES init_handles(&peED.handles);*/
8538 * Collect header pieces into lists via the passed custom formatter. Collect
8539 * everything else in the storage object passed. The latter should only end up
8540 * with raw header data.
8542 * BUG: DEAL WITH COLORS
8545 HD_INIT(&h
, wps_global
->VAR_VIEW_HEADERS
, wps_global
->view_all_except
, FE_DEFAULT
);
8546 if(format_header(wps_global
->mail_stream
, raw
, NULL
, peED
.env
, &h
,
8547 NULL
, NULL
, flags
, peFormatEnvelope
, peInterpWritec
) != 0){
8550 snprintf(buf
, sizeof(buf
), "Error formatting header %ld", peMessageNumber(uid
));
8553 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8559 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "%s%s%o", "raw", "", peED
.obj
);
8561 so_give(&peED
.store
);
8566 peFormatEnvelope(MAILSTREAM
*s
, long int n
, char *sect
, ENVELOPE
*e
, gf_io_t pc
, long int which
, char *oacs
, int flags
)
8568 char *p2
, buftmp
[MAILTMPLEN
];
8574 if((which
& FE_DATE
) && e
->date
) {
8575 if((objHdr
= Tcl_NewListObj(0, NULL
)) != NULL
){
8576 snprintf(buftmp
, sizeof(buftmp
), "%s", (char *) e
->date
);
8577 buftmp
[sizeof(buftmp
)-1] = '\0';
8578 p2
= (char *)rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
, SIZEOF_20KBUF
, buftmp
);
8579 peFormatEnvelopeText("Date", p2
);
8581 /* BUG: how does error feedback bubble back up? */
8584 if((which
& FE_FROM
) && e
->from
)
8585 peFormatEnvelopeAddress(s
, n
, sect
, "From", e
->from
, flags
, oacs
, pc
);
8587 if((which
& FE_REPLYTO
) && e
->reply_to
&& (!e
->from
|| !address_is_same(e
->reply_to
, e
->from
)))
8588 peFormatEnvelopeAddress(s
, n
, sect
, "Reply-To", e
->reply_to
, flags
, oacs
, pc
);
8590 if((which
& FE_TO
) && e
->to
)
8591 peFormatEnvelopeAddress(s
, n
, sect
, "To", e
->to
, flags
, oacs
, pc
);
8593 if((which
& FE_CC
) && e
->cc
)
8594 peFormatEnvelopeAddress(s
, n
, sect
, "Cc", e
->cc
, flags
, oacs
, pc
);
8596 if((which
& FE_BCC
) && e
->bcc
)
8597 peFormatEnvelopeAddress(s
, n
, sect
, "Bcc", e
->bcc
, flags
, oacs
, pc
);
8599 if((which
& FE_RETURNPATH
) && e
->return_path
)
8600 peFormatEnvelopeAddress(s
, n
, sect
, "Return-Path", e
->return_path
, flags
, oacs
, pc
);
8602 if((which
& FE_NEWSGROUPS
) && e
->newsgroups
)
8603 peFormatEnvelopeNewsgroups("Newsgroups", e
->newsgroups
, flags
, pc
);
8605 if((which
& FE_FOLLOWUPTO
) && e
->followup_to
)
8606 peFormatEnvelopeNewsgroups("Followup-To", e
->followup_to
, flags
, pc
);
8608 if((which
& FE_SUBJECT
) && e
->subject
&& e
->subject
[0]){
8609 if((objHdr
= Tcl_NewListObj(0, NULL
)) != NULL
){
8610 char *freeme
= NULL
;
8612 p2
= iutf8ncpy((char *)(wtmp_20k_buf
+10000),
8613 (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf
, 10000, e
->subject
),
8614 SIZEOF_20KBUF
-10000);
8616 if(flags
& FM_DISPLAY
8617 && (wps_global
->display_keywords_in_subject
8618 || wps_global
->display_keywordinits_in_subject
)){
8620 /* don't bother if no keywords are defined */
8621 if(some_user_flags_defined(s
))
8622 p2
= freeme
= prepend_keyword_subject(s
, n
, p2
,
8623 wps_global
->display_keywords_in_subject
? KW
: KWInit
,
8624 NULL
, wps_global
->VAR_KW_BRACES
);
8627 peFormatEnvelopeText("Subject", p2
);
8630 fs_give((void **) &freeme
);
8634 if((which
& FE_SENDER
) && e
->sender
&& (!e
->from
|| !address_is_same(e
->sender
, e
->from
)))
8635 peFormatEnvelopeAddress(s
, n
, sect
, "Sender", e
->sender
, flags
, oacs
, pc
);
8637 if((which
& FE_MESSAGEID
) && e
->message_id
){
8638 p2
= iutf8ncpy((char *)(wtmp_20k_buf
+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf
, 10000, e
->message_id
), SIZEOF_20KBUF
-10000);
8639 peFormatEnvelopeText("Message-ID", p2
);
8642 if((which
& FE_INREPLYTO
) && e
->in_reply_to
){
8643 p2
= iutf8ncpy((char *)(wtmp_20k_buf
+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf
, 10000, e
->in_reply_to
), SIZEOF_20KBUF
-10000);
8644 peFormatEnvelopeText("In-Reply-To", p2
);
8647 if((which
& FE_REFERENCES
) && e
->references
) {
8648 p2
= iutf8ncpy((char *)(wtmp_20k_buf
+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf
, 10000, e
->references
), SIZEOF_20KBUF
-10000);
8649 peFormatEnvelopeText("References", p2
);
8655 * appends caller's result with: {"text" field_name {field_value}}
8658 peFormatEnvelopeText(char *field_name
, char *field_value
)
8660 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "%s%s%s", "text", field_name
, field_value
);
8665 * appends caller's result with: {"addr" field_name {{{personal} {mailbox}} ... }}
8666 * {"rawaddr" field_name {{raw_address} ... }}
8669 peFormatEnvelopeAddress(MAILSTREAM
*stream
, long int msgno
, char *section
, char *field_name
,
8670 struct mail_address
*addr
, int flags
, char *oacs
, gf_io_t pc
)
8672 char *ptmp
, *mtmp
, *atype
= "addr";
8675 Tcl_Obj
*objAddrList
= NULL
;
8678 extern const char *rspecials
;
8679 extern const char *rspecials_minus_quote_and_dot
;
8685 * quickly run down address list to make sure none are patently bogus.
8686 * If so, just blat raw field out.
8688 for(atmp
= addr
; stream
&& atmp
; atmp
= atmp
->next
)
8689 if(atmp
->host
&& atmp
->host
[0] == '.'){
8690 char *field
, *fields
[2];
8693 if((objAddrList
= Tcl_NewListObj(0,NULL
)) == NULL
)
8694 return; /* BUG: handle list creation failure */
8697 fields
[0] = cpystr(field_name
);
8698 if((ptmp
= strchr(fields
[0], ':')) != NULL
)
8701 if((field
= pine_fetchheader_lines(stream
, msgno
, section
, fields
)) != NULL
){
8704 for(t
= h
= field
; *h
; t
++)
8705 if(*t
== '\015' && *(t
+1) == '\012'){
8706 *t
= '\0'; /* tie off line */
8708 Tcl_ListObjAppendElement(peED
.interp
, objAddrList
, Tcl_NewStringObj(h
,-1));
8710 if(!*(h
= (++t
) + 1)) /* set new h and skip CRLF */
8711 break; /* no more to write */
8713 else if(!*t
){ /* shouldn't happen much */
8715 Tcl_ListObjAppendElement(peED
.interp
, objAddrList
, Tcl_NewStringObj(h
,-1));
8720 fs_give((void **)&field
);
8723 fs_give((void **)&fields
[0]);
8727 if((objAddrList
= Tcl_NewListObj(0,NULL
)) == NULL
|| (tso
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
)
8728 return; /* BUG: handle list creation failure */
8730 gf_set_so_writec(&tpc
, tso
);
8734 atmp
= addr
->next
; /* remember what's next */
8736 if(!addr
->host
&& addr
->mailbox
){
8737 mtmp
= addr
->mailbox
;
8738 addr
->mailbox
= cpystr((char *)rfc1522_decode_to_utf8(
8739 (unsigned char *)wtmp_20k_buf
,
8740 SIZEOF_20KBUF
, addr
->mailbox
));
8743 ptmp
= addr
->personal
; /* RFC 1522 personal name? */
8744 addr
->personal
= iutf8ncpy((char *)wtmp_20k_buf
, (char *)rfc1522_decode_to_utf8((unsigned char *)(wtmp_20k_buf
+10000), SIZEOF_20KBUF
-10000, addr
->personal
), 10000);
8745 wtmp_20k_buf
[10000-1] = '\0';
8748 /* Logic taken from: pine_rfc822_write_address_noquote(addr, pc, &group); */
8749 if (addr
->host
) { /* ordinary address? */
8750 if (!(addr
->personal
|| addr
->adl
)){
8751 so_seek(tso
, 0L, 0);
8752 pine_rfc822_address (addr
, tpc
);
8753 peAppListF(peED
.interp
, objAddrList
, "%s%o", "", Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
)));
8755 else { /* no, must use phrase <route-addr> form */
8758 if (addr
->personal
){
8759 so_seek(tso
, 0L, 0);
8760 pine_rfc822_cat (addr
->personal
, rspecials_minus_quote_and_dot
, tpc
);
8761 objTmp
= Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
));
8764 so_seek(tso
, 0L, 0);
8765 pine_rfc822_address(addr
, tpc
);
8766 peAppListF(peED
.interp
, objAddrList
, "%o%o", objTmp
, Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
)));
8772 else if (addr
->mailbox
) { /* start of group? */
8773 so_seek(tso
, 0L, 0);
8774 /* yes, write group name */
8775 pine_rfc822_cat (addr
->mailbox
, rspecials
, tpc
);
8776 peAppListF(peED
.interp
, objAddrList
, "%o%s", Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
)), "");
8777 group
= 1; /* in a group */
8779 else if (group
) { /* must be end of group (but be paranoid) */
8780 peAppListF(peED
.interp
, objAddrList
, "%s%s", "", ";");
8781 group
= 0; /* no longer in that group */
8784 addr
->personal
= ptmp
; /* restore old personal ptr */
8785 if(!addr
->host
&& addr
->mailbox
){
8786 fs_give((void **)&addr
->mailbox
);
8787 addr
->mailbox
= mtmp
;
8794 gf_clear_so_writec(tso
);
8798 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "%s%s%o", atype
, field_name
, objAddrList
);
8803 * appends caller's result with: {"news" field_name {{newsgroup1} {newsgroup2} ... }}
8806 peFormatEnvelopeNewsgroups(char *field_name
, char *newsgrps
, int flags
, gf_io_t pc
)
8808 char buf
[MAILTMPLEN
];
8811 Tcl_Obj
*objNewsgroups
;
8813 /* BUG: handle list creation failure */
8814 if(!newsgrps
|| !*newsgrps
|| (objNewsgroups
= Tcl_NewListObj(0,NULL
)) == NULL
)
8817 llen
= strlen(field_name
);
8819 for(next_ng
= newsgrps
; *next_ng
&& *next_ng
!= ','; next_ng
++)
8822 strncpy(buf
, newsgrps
, MIN(next_ng
- newsgrps
, sizeof(buf
)-1));
8823 buf
[MIN(next_ng
- newsgrps
, sizeof(buf
)-1)] = '\0';
8825 Tcl_ListObjAppendElement(peED
.interp
, objNewsgroups
, Tcl_NewStringObj(buf
,-1));
8832 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "news", field_name
, objNewsgroups
);
8837 peMessageAttachments(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8842 Tcl_Obj
*objAtt
, *tObj
, *stObj
, *fnObj
;
8843 int flags
, rv
= TCL_OK
;
8846 peED
.interp
= interp
;
8847 peED
.obj
= Tcl_GetObjResult(interp
);
8849 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_HTML
| FM_NOHTMLREL
| FM_HTMLRELATED
| FM_HIDESERVER
;
8851 raw
= peSequenceNumber(uid
);
8853 if(peED
.uid
!= uid
){
8854 memset(&peED
, 0, sizeof(peED
));
8858 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
8859 if(!((peED
.env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, &peED
.body
))
8860 && (mc
= mail_elt(wps_global
->mail_stream
, raw
)))){
8863 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
8864 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate");
8866 dprint((1, "ERROR fetching %s of msg %ld: %s",
8867 peED
.env
? "elt" : "env", mn_get_cur(sp_msgmap(wps_global
->mail_stream
)),
8868 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate"));
8870 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8874 zero_atmts(wps_global
->atmts
);
8876 if(wps_global
&& wps_global
->smime
&& wps_global
->smime
->need_passphrase
)
8877 wps_global
->smime
->need_passphrase
= 0;
8879 fiddle_smime_message(peED
.body
, raw
);
8881 describe_mime(peED
.body
, "", 1, 1, 0, flags
);
8885 /* package up attachment list */
8886 for(a
= wps_global
->atmts
; rv
== TCL_OK
&& a
->description
!= NULL
; a
++)
8887 if((objAtt
= Tcl_NewListObj(0, NULL
)) != NULL
8888 && (body
= mail_body(wps_global
->mail_stream
, raw
, (unsigned char *) a
->number
)) != NULL
){
8889 peGetMimeTyping(body
, &tObj
, &stObj
, &fnObj
, NULL
);
8891 if(!(peAppListF(interp
, objAtt
, "%s", a
->number
? a
->number
: "") == TCL_OK
8892 && peAppListF(interp
, objAtt
, "%s", a
->shown
? "shown" : "") == TCL_OK
8893 && Tcl_ListObjAppendElement(interp
, objAtt
, tObj
) == TCL_OK
8894 && Tcl_ListObjAppendElement(interp
, objAtt
, stObj
) == TCL_OK
8895 && Tcl_ListObjAppendElement(interp
, objAtt
, fnObj
) == TCL_OK
8896 && peAppListF(interp
, objAtt
, "%s", a
->body
->description
) == TCL_OK
8897 && Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAtt
) == TCL_OK
))
8908 peMessageBody(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8911 int flags
, rv
= TCL_OK
;
8915 peED
.interp
= interp
;
8916 peED
.obj
= Tcl_GetObjResult(interp
);
8919 so_seek(peED
.store
, 0L, 0);
8921 peED
.store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
8923 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_NOHTMLREL
| FM_HTMLRELATED
;
8925 if(objc
== 1 && objv
[0]){ /* flags */
8930 Tcl_ListObjGetElements(interp
, objv
[0], &nFlags
, &objFlags
);
8931 for(i
= 0; i
< nFlags
; i
++){
8932 if((flagstr
= Tcl_GetStringFromObj(objFlags
[i
], NULL
)) == NULL
){
8936 if(!strucmp(flagstr
, "html"))
8937 flags
|= (FM_HTML
| FM_HIDESERVER
);
8938 else if(!strucmp(flagstr
, "images"))
8939 flags
|= (FM_HTMLIMAGES
);
8943 peED
.color
.fg
[0] = '\0';
8944 if((color
= pico_get_last_fg_color()) && (color
= color_to_asciirgb(color
))){
8945 peInterpWritec(TAG_EMBED
);
8946 peInterpWritec(TAG_FGCOLOR
);
8947 gf_puts(color
, peInterpWritec
);
8948 strcpy(peED
.color
.fgdef
, peColorStr(color
, wtmp_20k_buf
));
8951 peED
.color
.bg
[0] = '\0';
8952 if((color
= pico_get_last_bg_color()) && (color
= color_to_asciirgb(color
))){
8953 peInterpWritec(TAG_EMBED
);
8954 peInterpWritec(TAG_BGCOLOR
);
8955 gf_puts(color
, peInterpWritec
);
8956 strcpy(peED
.color
.bgdef
, peColorStr(color
,wtmp_20k_buf
));
8961 init_handles(&peED
.handles
);
8963 raw
= peSequenceNumber(uid
);
8965 if(peED
.uid
!= uid
){
8969 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
8970 if(!((peED
.env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, &peED
.body
))
8971 && (mc
= mail_elt(wps_global
->mail_stream
, raw
)))){
8974 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
8975 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate");
8977 dprint((1, "ERROR fetching %s of msg %ld: %s",
8978 peED
.env
? "elt" : "env", mn_get_cur(sp_msgmap(wps_global
->mail_stream
)),
8979 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate"));
8981 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8985 zero_atmts(wps_global
->atmts
);
8987 if(wps_global
&& wps_global
->smime
&& wps_global
->smime
->need_passphrase
)
8988 wps_global
->smime
->need_passphrase
= 0;
8990 fiddle_smime_message(peED
.body
, raw
);
8992 describe_mime(peED
.body
, "", 1, 1, 0, flags
);
8996 /* format message body */
9001 HD_INIT(&h
, wps_global
->VAR_VIEW_HEADERS
, wps_global
->view_all_except
, FE_DEFAULT
);
9003 /* kind of a hack, the description maybe shouldn't be in the editorial stuff */
9004 if(wps_global
->smime
&& wps_global
->smime
->need_passphrase
)
9005 flags
&= ~FM_NOEDITORIAL
;
9007 if((errstr
= format_body(raw
, peED
.body
, &peED
.handles
, &h
, flags
, FAKE_SCREEN_WIDTH
, peInterpWritec
)) != NULL
){
9008 gf_puts(errstr
, peInterpWritec
);
9015 so_give(&peED
.store
);
9016 free_handles(&peED
.handles
);
9022 peMessageText(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9031 memset(&peED
, 0, sizeof(peED
));
9032 peED
.interp
= interp
;
9033 peED
.obj
= Tcl_GetObjResult(interp
);
9034 peED
.store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
9036 peED
.color
.fg
[0] = '\0';
9037 if((color
= pico_get_last_fg_color()) && (color
= color_to_asciirgb(color
))){
9038 peInterpWritec(TAG_EMBED
);
9039 peInterpWritec(TAG_FGCOLOR
);
9040 gf_puts(color
, peInterpWritec
);
9041 strcpy(peED
.color
.fgdef
, peColorStr(color
, wtmp_20k_buf
));
9044 peED
.color
.bg
[0] = '\0';
9045 if((color
= pico_get_last_bg_color()) && (color
= color_to_asciirgb(color
))){
9046 peInterpWritec(TAG_EMBED
);
9047 peInterpWritec(TAG_BGCOLOR
);
9048 gf_puts(color
, peInterpWritec
);
9049 strcpy(peED
.color
.bgdef
, peColorStr(color
,wtmp_20k_buf
));
9052 raw
= peSequenceNumber(peED
.uid
= uid
);
9054 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
9055 if(!((env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, &body
))
9056 && (mc
= mail_elt(wps_global
->mail_stream
, raw
)))){
9059 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
9060 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate");
9062 dprint((1, "ERROR fetching %s of msg %ld: %s",
9063 env
? "elt" : "env", mn_get_cur(sp_msgmap(wps_global
->mail_stream
)),
9064 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate"));
9066 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
9070 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_NOHTMLREL
| FM_HTMLRELATED
;
9072 init_handles(&peED
.handles
);
9074 (void) format_message(raw
, env
, body
, &peED
.handles
, flags
, peInterpWritec
);
9078 so_give(&peED
.store
);
9079 free_handles(&peED
.handles
);
9085 * peMessagePartFromCID - return part number assoc'd with given uid and CID
9088 peMessagePartFromCID(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9090 char *cid
, sect_buf
[256];
9095 raw
= peSequenceNumber(peED
.uid
= uid
);
9096 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
9098 if(objv
[0] && (cid
= Tcl_GetStringFromObj(objv
[0], NULL
)) && *cid
!= '\0'){
9099 if((env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, &body
)) != NULL
){
9101 if(peLocateBodyByCID(cid
, sect_buf
, body
)){
9102 Tcl_SetResult(interp
, sect_buf
, TCL_VOLATILE
);
9106 Tcl_SetResult(interp
, wps_global
->last_error
[0] ? wps_global
->last_error
: "Error getting CID", TCL_VOLATILE
);
9116 peLocateBodyByCID(char *cid
, char *section
, BODY
*body
)
9118 if(body
->type
== TYPEMULTIPART
){
9119 char subsection
[256], *subp
;
9121 PART
*part
= body
->nested
.part
;
9123 if(!(part
= body
->nested
.part
))
9127 if(section
&& *section
){
9129 n
< sizeof(subsection
)-20 && (*subp
= section
[n
]); n
++, subp
++)
9137 sprintf(subp
, "%d", n
++);
9138 if(peLocateBodyByCID(cid
, subsection
, &part
->body
)){
9139 strcpy(section
, subsection
);
9143 while((part
= part
->next
) != NULL
);
9148 return((body
&& body
->id
) ? !strcmp(cid
, body
->id
) : 0);
9153 * peGetFlag - Return 1 or 0 based on requested flags current state
9155 * Params: argv[0] == flagname
9158 peGetFlag(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9162 Tcl_SetResult(interp
,
9163 int2string(((flagname
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
)
9164 ? peIsFlagged(wps_global
->mail_stream
, uid
, flagname
)
9172 peIsFlagged(MAILSTREAM
*stream
, imapuid_t uid
, char *flagname
)
9175 long raw
= peSequenceNumber(uid
);
9177 if(!((mc
= mail_elt(stream
, raw
)) && mc
->valid
)){
9178 mail_fetch_flags(stream
, ulong2string(uid
), FT_UID
);
9179 mc
= mail_elt(stream
, raw
);
9182 if(!strucmp(flagname
, "deleted"))
9183 return(mc
->deleted
);
9185 if(!strucmp(flagname
, "new"))
9188 if(!strucmp(flagname
, "important"))
9189 return(mc
->flagged
);
9191 if(!strucmp(flagname
, "answered"))
9192 return(mc
->answered
);
9194 if(!strucmp(flagname
, "recent"))
9202 * peSetFlag - Set requested flags value to 1 or 0
9204 * Params: abjv[0] == flagname
9205 * objv[1] == newvalue
9208 peSetFlag(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9210 char *flagname
, *flagstr
= NULL
;
9213 if((flagname
= Tcl_GetStringFromObj(objv
[0], NULL
))
9214 && Tcl_GetIntFromObj(interp
, objv
[1], &value
) != TCL_ERROR
){
9215 if(!strucmp(flagname
, "deleted")){
9216 flagstr
= "\\DELETED";
9218 else if(!strucmp(flagname
, "new")){
9222 else if(!strucmp(flagname
, "important")){
9223 flagstr
= "\\FLAGGED";
9225 else if(!strucmp(flagname
, "answered")){
9226 flagstr
= "\\ANSWERED";
9228 else if(!strucmp(flagname
, "recent")){
9229 flagstr
= "\\RECENT";
9233 wps_global
->c_client_error
[0] = '\0';
9234 mail_flag(wps_global
->mail_stream
,
9236 flagstr
, (value
? ST_SET
: 0L) | ST_UID
);
9237 if(wps_global
->c_client_error
[0] != '\0'){
9238 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "peSetFlag: %.40s",
9239 wps_global
->c_client_error
);
9240 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
9246 Tcl_SetResult(interp
, value
? "1" : "0", TCL_STATIC
);
9252 * peMsgSelect - Return 1 or 0 based on whether given UID is selected
9254 * Params: argv[0] == selected
9257 peMsgSelect(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9261 if(objc
== 1 && objv
[0]){
9262 if(Tcl_GetIntFromObj(interp
, objv
[0], &value
) != TCL_ERROR
){
9264 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
),
9265 peMessageNumber(uid
), MN_SLCT
, 1);
9266 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
),
9267 peMessageNumber(uid
), MN_HIDE
, 0);
9269 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
),
9270 peMessageNumber(uid
), MN_SLCT
, 0);
9271 /* if zoomed, lite hidden bit */
9272 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
))
9273 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
),
9274 peMessageNumber(uid
), MN_HIDE
, 1);
9279 Tcl_SetResult(interp
, "peMsgSelect: can't get value", TCL_STATIC
);
9284 Tcl_SetResult(interp
,
9285 (get_lflag(wps_global
->mail_stream
, NULL
,
9286 peSequenceNumber(uid
),
9295 * peAppendIndexParts - append list of digested index pieces to given object
9301 peAppendIndexParts(Tcl_Interp
*interp
, imapuid_t uid
, Tcl_Obj
*aObj
, int *fetched
)
9303 Tcl_Obj
*objField
, *objElement
, *objp
;
9309 if((h
= build_header_work(wps_global
, wps_global
->mail_stream
,
9310 sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
),
9311 gPeITop
, gPeICount
, fetched
)) != NULL
){
9312 for(f
= h
->ifield
; f
; f
= f
->next
){
9314 if((objField
= Tcl_NewListObj(0, NULL
)) == NULL
)
9317 for(ie
= f
->ielem
; ie
; ie
= ie
->next
){
9319 if((objElement
= Tcl_NewListObj(0, NULL
)) == NULL
)
9324 #if INTERNAL_INDEX_TRUNCATE
9327 ep
= (char *) fs_get((ie
->datalen
+ 1) * sizeof(char));
9328 sprintf(ep
, "%.*s", ie
->wid
, ie
->data
);
9330 /* and other stuff to pack trunc'd element into a new object */
9333 objp
= Tcl_NewStringObj(ie
->data
, ie
->datalen
);
9336 objp
= Tcl_NewStringObj("", -1);
9338 if(Tcl_ListObjAppendElement(interp
, objElement
, objp
) != TCL_OK
)
9345 if((objp
= Tcl_NewListObj(0, NULL
)) == NULL
)
9348 hex_colorstr(hexcolor
, ie
->color
->fg
);
9349 objColor
= Tcl_NewStringObj(hexcolor
, -1);
9350 if(Tcl_ListObjAppendElement(interp
, objp
, objColor
) != TCL_OK
)
9353 hex_colorstr(hexcolor
, ie
->color
->bg
);
9354 objColor
= Tcl_NewStringObj(hexcolor
, -1);
9355 if(Tcl_ListObjAppendElement(interp
, objp
, objColor
) != TCL_OK
)
9359 objp
= Tcl_NewStringObj("", -1);
9361 if(Tcl_ListObjAppendElement(interp
, objElement
, objp
) != TCL_OK
)
9365 * IF we ever want to map the thread characters into nice
9366 * graphical symbols or take advantage of features like clicking
9367 * on a thread element to collapse and such, we need to have
9368 * element tagging. That's what the object creation and append
9369 * are placeholders for
9373 objp
= Tcl_NewStringObj("threadinfo", -1);
9379 objp
= Tcl_NewStringObj(int2string(ie
->type
), -1);
9383 if(objp
&& Tcl_ListObjAppendElement(interp
, objElement
, objp
) != TCL_OK
)
9386 if(Tcl_ListObjAppendElement(interp
, objField
, objElement
) != TCL_OK
)
9390 if(Tcl_ListObjAppendElement(interp
, aObj
, objField
) != TCL_OK
){
9401 * peAppendIndexColor - append index line's foreground/background color
9407 peAppendIndexColor(Tcl_Interp
*interp
, imapuid_t uid
, Tcl_Obj
*aObj
, int *fetched
)
9409 char hexfg
[32], hexbg
[32];
9412 if((h
= build_header_work(wps_global
, wps_global
->mail_stream
,
9413 sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
),
9414 gPeITop
, gPeICount
, fetched
))
9415 && h
->color_lookup_done
9418 hex_colorstr(hexfg
, h
->linecolor
->fg
);
9419 hex_colorstr(hexbg
, h
->linecolor
->bg
);
9421 return(peAppListF(interp
, aObj
, "%s%s", hexfg
, hexbg
));
9424 return(peAppListF(interp
, aObj
, "%s", ""));
9429 * peMessageStatusBits - return list flags indicating pine status bits
9433 * Returns: list of lists where:
9434 * * the first element is the list of
9435 * field elements data
9436 * * the second element is a two element
9437 * list containing the lines foreground
9438 * and background colors
9441 peMessageStatusBits(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9443 Tcl_SetResult(interp
,
9444 peMsgStatBitString(wps_global
, wps_global
->mail_stream
,
9445 sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
),
9446 gPeITop
, gPeICount
, NULL
),
9453 peMsgStatBitString(struct pine
*state
,
9461 static char buf
[36];
9467 raw
= mn_m2raw(msgmap
, msgno
);
9468 if((h
= build_header_work(state
, stream
, msgmap
,
9469 msgno
, top_msgno
, msgcount
, fetched
))
9470 && (mc
= mail_elt(stream
, raw
))){
9471 /* return a string representing a bit field where:
9485 buf
[i
++] = (mc
->seen
) ? '0' : '1';
9486 buf
[i
++] = (mc
->deleted
) ? '1' : '0';
9487 buf
[i
++] = (mc
->answered
) ? '1' : '0';
9488 buf
[i
++] = (mc
->flagged
) ? '1' : '0';
9489 buf
[i
++] = (h
->to_us
) ? '1' : '0';
9490 buf
[i
++] = (h
->cc_us
) ? '1' : '0';
9491 buf
[i
++] = (mc
->recent
) ? '1' : '0';
9492 buf
[i
++] = (user_flag_is_set(stream
, raw
, FORWARDED_FLAG
)) ? '1' : '0';
9499 return("100000000");
9504 peMsgStatNameList(Tcl_Interp
*interp
,
9518 objList
= Tcl_NewListObj(0, NULL
);
9519 raw
= mn_m2raw(msgmap
, msgno
);
9520 if((h
= build_header_work(state
, stream
, msgmap
,
9521 msgno
, top_msgno
, msgcount
, fetched
))
9522 && (mc
= mail_elt(stream
, raw
))){
9524 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("new", -1));
9527 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("deleted", -1));
9530 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("answered", -1));
9533 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("flagged", -1));
9536 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("to_us", -1));
9539 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("cc_us", -1));
9542 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("recent", -1));
9544 if(user_flag_is_set(stream
, raw
, FORWARDED_FLAG
))
9545 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("forwarded", -1));
9547 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), msgno
, MN_SLCT
))
9548 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("selected", -1));
9556 * peReplyHeaders - return subject used in reply to given message
9560 * Returns: list of header value pairs where headers are:
9561 * In-Reply-To:, Subject:, Cc:
9565 peReplyHeaders(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9568 int flags
= RSF_FORCE_REPLY_TO
| RSF_FORCE_REPLY_ALL
, err
= FALSE
;
9569 char *errmsg
= NULL
, *fcc
= NULL
, *sect
= NULL
;
9570 ENVELOPE
*env
, *outgoing
;
9572 ADDRESS
*saved_from
, *saved_to
, *saved_cc
, *saved_resent
;
9574 saved_from
= (ADDRESS
*) NULL
;
9575 saved_to
= (ADDRESS
*) NULL
;
9576 saved_cc
= (ADDRESS
*) NULL
;
9577 saved_resent
= (ADDRESS
*) NULL
;
9579 raw
= peSequenceNumber(uid
);
9581 /* if we're given a valid section number that
9582 * corresponds to a valid msg/rfc822 body part
9583 * then set up headers in attached message.
9585 if(objc
== 1 && objv
[0]
9586 && (sect
= Tcl_GetStringFromObj(objv
[0], NULL
)) && *sect
!= '\0'
9587 && (body
= mail_body(wps_global
->mail_stream
, raw
, (unsigned char *) sect
))
9588 && body
->type
== TYPEMESSAGE
9589 && !strucmp(body
->subtype
, "rfc822")){
9590 env
= body
->nested
.msg
->env
;
9594 env
= mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
);
9598 if(!reply_harvest(wps_global
, raw
, sect
, env
,
9599 &saved_from
, &saved_to
, &saved_cc
,
9600 &saved_resent
, &flags
)){
9602 Tcl_SetResult(interp
, "", TCL_STATIC
);
9606 outgoing
= mail_newenvelope();
9608 reply_seed(wps_global
, outgoing
, env
,
9609 saved_from
, saved_to
, saved_cc
, saved_resent
,
9610 &fcc
, flags
, &errmsg
);
9613 q_status_message1(SM_ORDER
, 3, 3, "%.200s", errmsg
);
9616 fs_give((void **)&errmsg
);
9619 env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
);
9621 outgoing
->subject
= reply_subject(env
->subject
, NULL
, 0);
9622 outgoing
->in_reply_to
= reply_in_reply_to(env
);
9624 err
= !(peAppListF(interp
, Tcl_GetObjResult(interp
),
9625 "%s%a", "to", outgoing
->to
) == TCL_OK
9626 && peAppListF(interp
, Tcl_GetObjResult(interp
),
9627 "%s%a", "cc", outgoing
->cc
) == TCL_OK
9628 && peAppListF(interp
, Tcl_GetObjResult(interp
),
9629 "%s%s", "in-reply-to", outgoing
->in_reply_to
) == TCL_OK
9630 && peAppListF(interp
, Tcl_GetObjResult(interp
),
9632 rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
,
9633 SIZEOF_20KBUF
, outgoing
->subject
)) == TCL_OK
9634 && (fcc
? peFccAppend(interp
, Tcl_GetObjResult(interp
), fcc
, -1) : TRUE
));
9637 /* Fill in x-reply-uid data and append it */
9638 if(!err
&& wps_global
->mail_stream
->uid_validity
){
9639 char *prefix
= reply_quote_str(env
);
9641 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "(%lu %s)(1 %lu %lu)%s",
9642 strlen(prefix
), prefix
,
9643 wps_global
->mail_stream
->uid_validity
, uid
,
9644 wps_global
->mail_stream
->mailbox
);
9646 fs_give((void **) &prefix
);
9648 err
= peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s",
9649 "x-reply-uid", wtmp_20k_buf
) != TCL_OK
;
9652 mail_free_envelope(&outgoing
);
9658 Tcl_SetResult(interp
, "", TCL_VOLATILE
);
9666 * peReplyText - return subject used in reply to given message
9674 peReplyText(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9677 char *prefix
, *sect
= NULL
;
9680 BODY
*body
= NULL
, *orig_body
;
9682 REDRAFT_POS_S
*redraft_pos
= NULL
;
9683 Tcl_Obj
*objBody
= NULL
, *objAttach
= NULL
;
9685 msgno
= peSequenceNumber(uid
);
9687 if((msgtext
= (void *) so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
9688 Tcl_SetResult(interp
, "Unable to create storage for reply text", TCL_VOLATILE
);
9692 /*--- Grab current envelope ---*/
9693 /* if we're given a valid section number that
9694 * corresponds to a valid msg/rfc822 body part
9695 * then set up to reply the attached message's
9698 if(objc
== 2 && objv
[1]
9699 && (sect
= Tcl_GetStringFromObj(objv
[1], NULL
)) && *sect
!= '\0'
9700 && (body
= mail_body(wps_global
->mail_stream
, msgno
, (unsigned char *) sect
))
9701 && body
->type
== TYPEMESSAGE
9702 && !strucmp(body
->subtype
, "rfc822")){
9703 env
= body
->nested
.msg
->env
;
9704 orig_body
= body
->nested
.msg
->body
;
9708 env
= mail_fetchstructure(wps_global
->mail_stream
, msgno
, &orig_body
);
9709 if(!(env
&& orig_body
)){
9710 Tcl_SetResult(interp
, "Unable to fetch message parts", TCL_VOLATILE
);
9715 if((prefix
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
)
9716 prefix
= cpystr(prefix
);
9718 prefix
= reply_quote_str(env
);
9721 * BUG? Should there be some way to signal to reply_bddy
9722 * that we'd like it to produced format=flowed body text?
9723 * right now it's hardwired to in pine/reply.c
9726 if((body
= reply_body(wps_global
->mail_stream
, env
, orig_body
,
9727 msgno
, sect
, msgtext
, prefix
,
9728 TRUE
, NULL
, TRUE
, &redraft_pos
)) != NULL
){
9730 objBody
= Tcl_NewListObj(0, NULL
);
9732 peSoStrToList(interp
, objBody
, msgtext
);
9734 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objBody
);
9736 /* sniff for attachments */
9737 objAttach
= peMsgAttachCollector(interp
, body
);
9739 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
9742 pine_free_body(&body
);
9745 Tcl_SetResult(interp
, "Can't create body text", TCL_VOLATILE
);
9749 fs_give((void **) &prefix
);
9756 peSoStrToList(Tcl_Interp
*interp
, Tcl_Obj
*obj
, STORE_S
*so
)
9761 for(ep
= (char *) so_text(so
); *ep
; ep
++){
9764 while(*ep
&& *ep
!= '\n')
9767 objp
= Tcl_NewStringObj(sp
, ep
- sp
);
9769 if(Tcl_ListObjAppendElement(interp
, obj
, objp
) != TCL_OK
)
9778 * peForwardHeaders - return subject used in forward of given message
9786 peForwardHeaders(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9791 char *tmp
, *sect
= NULL
;
9795 raw
= peSequenceNumber(uid
);
9797 /* if we're given a valid section number that
9798 * corresponds to a valid msg/rfc822 body part
9799 * then set up headers in attached message.
9801 if(objc
== 1 && objv
[0]
9802 && (sect
= Tcl_GetStringFromObj(objv
[0], NULL
)) && *sect
!= '\0'
9803 && (body
= mail_body(wps_global
->mail_stream
, raw
, (unsigned char *) sect
))
9804 && body
->type
== TYPEMESSAGE
9805 && !strucmp(body
->subtype
, "rfc822")){
9806 env
= body
->nested
.msg
->env
;
9810 env
= mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
);
9814 tmp
= forward_subject(env
, FS_NONE
);
9815 result
= peAppListF(interp
, Tcl_GetObjResult(interp
),
9816 "%s%s", "subject", tmp
);
9817 fs_give((void **) &tmp
);
9819 /* Fill in x-reply-uid data and append it */
9820 if(result
== TCL_OK
&& wps_global
->mail_stream
->uid_validity
){
9821 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "()(1 %lu %lu)%s",
9822 wps_global
->mail_stream
->uid_validity
, uid
,
9823 wps_global
->mail_stream
->mailbox
);
9824 result
= peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s",
9825 "x-reply-uid", wtmp_20k_buf
) != TCL_OK
;
9831 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
9838 * peForwardText - return body of message used in
9839 * forward of given message
9847 peForwardText(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9850 char *bodtext
, *p
, *sect
= NULL
;
9853 BODY
*body
, *orig_body
;
9855 Tcl_Obj
*objBody
= NULL
, *objAttach
= NULL
;
9857 msgno
= peSequenceNumber(uid
);
9859 if(objc
== 1 && objv
[0])
9860 sect
= Tcl_GetStringFromObj(objv
[0], NULL
);
9862 if((msgtext
= (void *) so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
9863 Tcl_SetResult(interp
, "Unable to create storage for forward text", TCL_VOLATILE
);
9868 if(F_ON(F_FORWARD_AS_ATTACHMENT
, wps_global
)){
9870 long totalsize
= 0L;
9872 /*---- New Body to start with ----*/
9873 body
= mail_newbody();
9874 body
->type
= TYPEMULTIPART
;
9876 /*---- The TEXT part/body ----*/
9877 body
->nested
.part
= mail_newbody_part();
9878 body
->nested
.part
->body
.type
= TYPETEXT
;
9879 body
->nested
.part
->body
.contents
.text
.data
= (unsigned char *) msgtext
;
9881 pp
= &(body
->nested
.part
->next
);
9883 /*---- The Message body subparts ----*/
9884 env
= pine_mail_fetchstructure(wps_global
->mail_stream
, msgno
, NULL
);
9886 if(forward_mime_msg(wps_global
->mail_stream
, msgno
,
9887 (sect
&& *sect
!= '\0') ? sect
: NULL
, env
, pp
, msgtext
)){
9888 totalsize
= (*pp
)->body
.size
.bytes
;
9889 pp
= &((*pp
)->next
);
9893 /*--- Grab current envelope ---*/
9894 /* if we're given a valid section number that
9895 * corresponds to a valid msg/rfc822 body part
9896 * then set up to forward the attached message's
9900 if(sect
&& *sect
!= '\0'
9901 && (body
= mail_body(wps_global
->mail_stream
, msgno
, (unsigned char *) sect
))
9902 && body
->type
== TYPEMESSAGE
9903 && !strucmp(body
->subtype
, "rfc822")){
9904 env
= body
->nested
.msg
->env
;
9905 orig_body
= body
->nested
.msg
->body
;
9909 env
= mail_fetchstructure(wps_global
->mail_stream
, msgno
, &orig_body
);
9910 if(!(env
&& orig_body
)){
9911 Tcl_SetResult(interp
, "Unable to fetch message parts", TCL_VOLATILE
);
9916 body
= forward_body(wps_global
->mail_stream
, env
, orig_body
,
9917 msgno
, sect
, msgtext
, FWD_NONE
);
9921 bodtext
= (char *) so_text(msgtext
);
9923 objBody
= Tcl_NewListObj(0, NULL
);
9925 for(p
= bodtext
; *p
; p
++){
9929 while(*p
&& *p
!= '\n')
9932 objp
= Tcl_NewStringObj(bodtext
, p
- bodtext
);
9934 Tcl_ListObjAppendElement(interp
, objBody
, objp
);
9937 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objBody
);
9939 /* sniff for attachments */
9940 objAttach
= peMsgAttachCollector(interp
, body
);
9941 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
9943 pine_free_body(&body
);
9946 Tcl_SetResult(interp
, "Can't create body text", TCL_VOLATILE
);
9958 * Params: argv[0] == attachment part number
9959 * argv[1] == directory to hold tmp file
9961 * Returns: list containing:
9963 * 0) response: OK or ERROR
9965 * 1) attachment's mime type
9966 * 2) attachment's mime sub-type
9967 * 3) attachment's size in bytes (decoded)
9968 * 4) attachment's given file name (if any)
9969 * 5) tmp file holding raw attachment data
9972 peDetach(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9974 char *part
, *err
, *tfd
, *tfn
= NULL
, *filename
;
9979 Tcl_Obj
*rvobj
, *tObj
, *stObj
, *fnObj
;
9981 if((part
= Tcl_GetStringFromObj(objv
[0], NULL
))
9982 && (raw
= peSequenceNumber(uid
))
9983 && (body
= mail_body(wps_global
->mail_stream
, raw
, (unsigned char *) part
))){
9985 peGetMimeTyping(body
, &tObj
, &stObj
, &fnObj
, NULL
);
9988 if(!(tfd
= Tcl_GetStringFromObj(objv
[1], NULL
)) || *tfd
== '\0'){
9989 tfn
= temp_nam(tfd
= NULL
, "pd");
9991 else if(is_writable_dir(tfd
) == 0){
9992 tfn
= temp_nam(tfd
, "pd");
9997 filename
= Tcl_GetStringFromObj(fnObj
, NULL
);
9998 dprint((5, "PEDetach(name: %s, tmpfile: %s)",
9999 filename
? filename
: "<null>", tfn
));
10001 if((store
= so_get(FileStar
, tfn
, WRITE_ACCESS
|OWNER_ONLY
)) != NULL
){
10002 gf_set_so_writec(&pc
, store
);
10003 err
= detach(wps_global
->mail_stream
, raw
, part
, 0L, NULL
, pc
, NULL
, 0);
10004 gf_clear_so_writec(store
);
10008 err
= "Can't allocate internal storage";
10011 err
= "Can't get message data";
10017 dprint((1, "PEDetach FAIL: %d: %s", errno
, err
));
10018 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Detach (%d): %s", errno
, err
);
10019 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
10023 /* package up response */
10024 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10025 Tcl_NewListObj(1, &tObj
));
10027 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10028 Tcl_NewListObj(1, &stObj
));
10030 rvobj
= Tcl_NewLongObj(name_file_size(tfn
));
10031 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10032 Tcl_NewListObj(1, &rvobj
));
10033 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10034 Tcl_NewListObj(1, &fnObj
));
10035 rvobj
= Tcl_NewStringObj(tfn
, -1);
10036 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10037 Tcl_NewListObj(1, &rvobj
));
10046 * Params: argv[0] == attachment part number
10048 * Returns: list containing:
10050 * 0) response: OK or ERROR
10052 * 1) attachment's mime type
10053 * 2) attachment's mime sub-type
10054 * 3) attachment's size in bytes (decoded)
10055 * 4) attachment's given file name (if any)
10056 * 5) tmp file holding raw attachment data
10059 peAttachInfo(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10065 Tcl_Obj
*tObj
, *stObj
, *fnObj
;
10067 if((part
= Tcl_GetStringFromObj(objv
[0], NULL
))
10068 && (raw
= peSequenceNumber(uid
))
10069 && (body
= mail_body(wps_global
->mail_stream
, raw
, (unsigned char *) part
))){
10071 peGetMimeTyping(body
, &tObj
, &stObj
, &fnObj
, NULL
);
10074 Tcl_SetResult(interp
, "Can't get message data", TCL_STATIC
);
10078 /* package up response */
10081 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), fnObj
);
10084 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
10087 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), stObj
);
10090 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10091 Tcl_NewStringObj((body
->encoding
< ENCMAX
)
10092 ? body_encodings
[body
->encoding
]
10096 if((plist
= rfc2231_newparmlist(body
->parameter
)) != NULL
){
10097 Tcl_Obj
*lObj
= Tcl_NewListObj(0, NULL
);
10100 while(rfc2231_list_params(plist
)){
10101 pObj
[0] = Tcl_NewStringObj(plist
->attrib
, -1);
10102 pObj
[1] = Tcl_NewStringObj(plist
->value
, -1);
10103 Tcl_ListObjAppendElement(interp
, lObj
,
10104 Tcl_NewListObj(2, pObj
));
10107 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), lObj
);
10108 rfc2231_free_parmlist(&plist
);
10111 /* size guesstimate */
10112 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10113 Tcl_NewStringObj(comatose((body
->encoding
== ENCBASE64
)
10114 ? ((body
->size
.bytes
* 3)/4)
10115 : body
->size
.bytes
), -1));
10122 * peSaveDefault - Default saved file name for the given message
10123 * specified collection/folder
10127 * Returns: name of saved message folder or empty string
10131 peSaveDefault(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10134 CONTEXT_S
*cntxt
, *cp
;
10140 if(!(env
= pine_mail_fetchstructure(wps_global
->mail_stream
,
10141 rawno
= peSequenceNumber(uid
),
10143 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
10150 if(!(folder
= save_get_default(wps_global
, env
, rawno
, NULL
, &cntxt
))){
10151 Tcl_SetResult(interp
, "Message expunged!", TCL_VOLATILE
);
10152 return(TCL_ERROR
); /* message expunged! */
10155 for(colid
= 0, cp
= wps_global
->context_list
; cp
&& cp
!= cntxt
; colid
++, cp
= cp
->next
)
10161 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10162 Tcl_NewIntObj(colid
));
10163 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10164 Tcl_NewStringObj(folder
, -1));
10170 * peSaveWork - Save message with given UID in current folder to
10171 * specified collection/folder
10173 * Params: argv[0] == destination context number
10174 * argv[1] == testination foldername
10179 peSaveWork(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
, long sflags
)
10181 int flgs
= 0, i
, colid
;
10182 char *folder
, *err
= NULL
;
10185 if(Tcl_GetIntFromObj(interp
, objv
[0], &colid
) != TCL_ERROR
){
10186 if((folder
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
10187 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
));
10188 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
10193 if(!READONLY_FOLDER(wps_global
->mail_stream
)
10194 && (sflags
& PSW_COPY
) != PSW_COPY
10195 && ((sflags
& PSW_MOVE
) == PSW_MOVE
|| F_OFF(F_SAVE_WONT_DELETE
, wps_global
)))
10198 if(colid
== 0 && !strucmp(folder
, "inbox"))
10199 flgs
|= SV_INBOXWOCNTXT
;
10201 if(sflags
& (PSW_COPY
| PSW_MOVE
))
10202 flgs
|= SV_FIX_DELS
;
10204 i
= save(wps_global
, wps_global
->mail_stream
,
10205 cp
, folder
, sp_msgmap(wps_global
->mail_stream
), flgs
);
10207 if(i
== mn_total_cur(sp_msgmap(wps_global
->mail_stream
))){
10208 if(mn_total_cur(sp_msgmap(wps_global
->mail_stream
)) <= 1L){
10209 if(wps_global
->context_list
->next
10210 && context_isambig(folder
)){
10211 char *tag
= (cp
->nickname
&& strlen(cp
->nickname
)) ? cp
->nickname
: (cp
->label
&& strlen(cp
->label
)) ? cp
->label
: "Folders";
10212 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
,
10213 "Message %s %s to \"%.15s%s\" in <%.15s%s>",
10214 long2string(mn_get_cur(sp_msgmap(wps_global
->mail_stream
))),
10215 (sflags
& PSW_MOVE
) ? "moved" : "copied",
10217 (strlen(folder
) > 15) ? "..." : "",
10219 (strlen(tag
) > 15) ? "..." : "");
10222 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
,
10223 "Message %s %s to folder \"%.27s%s\"",
10224 long2string(mn_get_cur(sp_msgmap(wps_global
->mail_stream
))),
10225 (sflags
& PSW_MOVE
) ? "moved" : "copied",
10227 (strlen(folder
) > 27) ? "..." : "");
10230 /* with mn_set_cur above, this *should not* happen */
10231 Tcl_SetResult(interp
, "TOO MANY MESSAGES COPIED", TCL_VOLATILE
);
10235 if(sflags
== PSW_NONE
&& (flgs
& SV_DELETE
)){
10236 strncat(wtmp_20k_buf
, " and deleted", SIZEOF_20KBUF
-strlen(wtmp_20k_buf
)-1);
10237 wtmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
10240 q_status_message(SM_ORDER
, 0, 3, wtmp_20k_buf
);
10244 err
= wps_global
->last_error
;
10247 err
= "open: Unrecognized collection ID";
10250 err
= "open: Can't read folder";
10253 err
= "open: Can't get collection ID";
10255 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
10260 * peSave - Save message with given UID in current folder to
10261 * specified collection/folder
10263 * Params: argv[0] == destination context number
10264 * argv[1] == testination foldername
10266 * NOTE: just a wrapper around peSaveWork
10269 peSave(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10271 return(peSaveWork(interp
, uid
, objc
, objv
, PSW_NONE
));
10276 * peCopy - Copy message with given UID in current folder to
10277 * specified collection/folder
10279 * Params: argv[0] == destination context number
10280 * argv[1] == testination foldername
10282 * NOTE: just a wrapper around peSaveWork that makes sure
10283 * delete-on-save is NOT set
10286 peCopy(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10288 return(peSaveWork(interp
, uid
, objc
, objv
, PSW_COPY
));
10293 * peMove - Move message with given UID in current folder to
10294 * specified collection/folder
10296 * Params: argv[0] == destination context number
10297 * argv[1] == testination foldername
10299 * NOTE: just a wrapper around peSaveWork that makes sure
10300 * delete-on-save IS set so it can be expunged
10303 peMove(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10305 return(peSaveWork(interp
, uid
, objc
, objv
, PSW_MOVE
));
10310 * peGotoDefault - Default Goto command file name for the given message
10311 * specified collection/folder
10315 * Returns: name of Goto command default folder or empty string
10319 peGotoDefault(Tcl_Interp
*interp
, imapuid_t uid
, Tcl_Obj
**objv
)
10321 char *folder
= NULL
;
10322 CONTEXT_S
*cntxt
, *cp
;
10325 cntxt
= broach_get_folder(wps_global
->context_current
, &inbox
, &folder
);
10327 for(colid
= 0, cp
= wps_global
->context_list
; cp
!= cntxt
; colid
++, cp
= cp
->next
)
10333 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10334 Tcl_NewIntObj(colid
));
10335 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10336 Tcl_NewStringObj(folder
? folder
: "", -1));
10344 * Params: argv[0] == attachment part number
10346 * Returns: list containing:
10350 peReplyQuote(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10356 if((env
= pine_mail_fetchstructure(wps_global
->mail_stream
, peSequenceNumber(uid
), NULL
)) != NULL
){
10357 quote
= reply_quote_str(env
);
10358 Tcl_SetResult(interp
, quote
, TCL_VOLATILE
);
10359 fs_give((void **) "e
);
10362 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
10367 Tcl_SetResult(interp
, "> ", TCL_VOLATILE
);
10374 peGetMimeTyping(BODY
*body
, Tcl_Obj
**tObjp
, Tcl_Obj
**stObjp
, Tcl_Obj
**fnObjp
, Tcl_Obj
**extObjp
)
10376 char *ptype
= NULL
, *psubtype
= NULL
, *pfile
= NULL
;
10378 /*------- Figure out suggested file name ----*/
10380 if((pfile
= get_filename_parameter(NULL
, 0, body
, NULL
)) != NULL
){
10382 * if part is generic, see if we can get anything
10383 * more from the suggested filename's extension...
10385 if(body
->type
== TYPEAPPLICATION
10387 || !strucmp(body
->subtype
, "octet-stream"))){
10388 BODY
*fakebody
= mail_newbody();
10390 if(set_mime_type_by_extension(fakebody
, pfile
)){
10391 ptype
= body_type_names(fakebody
->type
);
10392 psubtype
= cpystr(fakebody
->subtype
);
10395 mail_free_body(&fakebody
);
10400 ptype
= body_type_names(body
->type
);
10401 psubtype
= cpystr(body
->subtype
10403 : (body
->type
== TYPETEXT
)
10405 : (body
->type
== TYPEAPPLICATION
)
10411 ptype
= body_type_names(TYPETEXT
);
10412 psubtype
= cpystr("plain");
10416 *extObjp
= Tcl_NewStringObj("", 0);
10418 if(ptype
&& psubtype
&& pfile
){
10421 char extbuf
[32]; /* mailcap.c limits to three */
10423 l
= strlen(ptype
) + strlen(psubtype
) + 1;
10424 mtype
= (char *) fs_get((l
+1) * sizeof(char));
10426 snprintf(mtype
, l
+1, "%s/%s", ptype
, psubtype
);
10428 if(!set_mime_extension_by_type(extbuf
, mtype
)){
10431 for(dotp
= NULL
, p
= pfile
; *p
; p
++)
10436 Tcl_SetStringObj(*extObjp
, dotp
, -1);
10439 Tcl_SetStringObj(*extObjp
, extbuf
, -1);
10441 fs_give((void **) &mtype
);
10446 *tObjp
= Tcl_NewStringObj(ptype
, -1);
10450 *stObjp
= Tcl_NewStringObj(psubtype
, -1);
10452 fs_give((void **) &psubtype
);
10455 *stObjp
= Tcl_NewStringObj("", 0);
10459 *fnObjp
= Tcl_NewStringObj(pfile
, -1);
10461 fs_give((void **) &pfile
);
10464 *fnObjp
= Tcl_NewStringObj("", 0);
10469 * peAppListF - generate a list of elements based on fmt string,
10470 * then append it to the given list object
10474 peAppListF(Tcl_Interp
*interp
, Tcl_Obj
*lobjp
, char *fmt
, ...)
10477 char *p
, *sval
, nbuf
[128];
10481 unsigned long luval
;
10485 Tcl_Obj
*lObj
= NULL
, *sObj
;
10487 if((lObj
= Tcl_NewListObj(0, NULL
)) != NULL
){
10488 va_start(args
, fmt
);
10489 for(p
= fmt
; *p
&& !err
; p
++){
10494 case 'i' : /* int value */
10495 ival
= va_arg(args
, int);
10496 if((sObj
= Tcl_NewIntObj(ival
)) == NULL
)
10501 case 'u' : /* unsigned int value */
10502 uval
= va_arg(args
, unsigned int);
10503 snprintf(nbuf
, sizeof(nbuf
), "%u", uval
);
10504 if((sObj
= Tcl_NewStringObj(nbuf
, -1)) == NULL
)
10509 case 'l' : /* long value */
10512 luval
= va_arg(args
, unsigned long);
10513 snprintf(nbuf
, sizeof(nbuf
), "%lu", luval
);
10514 if((sObj
= Tcl_NewStringObj(nbuf
, -1)) == NULL
)
10518 lval
= va_arg(args
, long);
10519 if((sObj
= Tcl_NewLongObj(lval
)) == NULL
)
10525 case 's' : /* string value */
10526 sval
= va_arg(args
, char *);
10527 sObj
= Tcl_NewStringObj(sval
? sval
: "", -1);
10533 case 'a': /* ADDRESS list */
10534 aval
= va_arg(args
, ADDRESS
*);
10540 len
= est_size(aval
);
10541 tmp
= (char *) fs_get(len
* sizeof(char));
10543 rbuf
.f
= dummy_soutr
;
10547 rbuf
.end
= tmp
+len
-1;
10548 rfc822_output_address_list(&rbuf
, aval
, 0L, NULL
);
10550 p
= (char *) rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
, SIZEOF_20KBUF
, tmp
);
10551 sObj
= Tcl_NewStringObj(p
, strlen(p
));
10552 fs_give((void **) &tmp
);
10555 sObj
= Tcl_NewStringObj("", -1);
10559 case 'p': /* PATTERN_S * */
10560 pval
= va_arg(args
, PATTERN_S
*);
10561 sval
= pattern_to_string(pval
);
10562 sObj
= Tcl_NewStringObj(sval
? sval
: "", -1);
10565 case 'v': /* INTVL_S * */
10566 vval
= va_arg(args
, INTVL_S
*);
10568 for(; vval
!= NULL
; vval
= vval
->next
){
10569 peAppListF(interp
, sObj
, "%l%l", vval
->imin
, vval
->imax
);
10573 sObj
= Tcl_NewListObj(0, NULL
);
10577 case 'o': /* Tcl_Obj * */
10578 sObj
= va_arg(args
, Tcl_Obj
*);
10583 Tcl_ListObjAppendElement(interp
, lObj
, sObj
);
10589 return(lObj
? Tcl_ListObjAppendElement(interp
, lobjp
, lObj
) : TCL_ERROR
);
10593 * pePatAppendID - append list of pattern identity variables to given object
10596 pePatAppendID(Tcl_Interp
*interp
, Tcl_Obj
*patObj
, PAT_S
*pat
)
10600 resObj
= Tcl_NewListObj(0, NULL
);
10601 peAppListF(interp
, resObj
, "%s%s", "nickname", pat
->patgrp
->nick
);
10602 peAppListF(interp
, resObj
, "%s%s", "comment", pat
->patgrp
->comment
);
10603 Tcl_ListObjAppendElement(interp
, patObj
, resObj
);
10608 * pePatAppendPattern - append list of pattern variables to given object
10611 pePatAppendPattern(Tcl_Interp
*interp
, Tcl_Obj
*patObj
, PAT_S
*pat
)
10616 resObj
= Tcl_NewListObj(0, NULL
);
10617 peAppListF(interp
, resObj
, "%s%p", "to", pat
->patgrp
->to
);
10618 peAppListF(interp
, resObj
, "%s%p", "from", pat
->patgrp
->from
);
10619 peAppListF(interp
, resObj
, "%s%p", "sender", pat
->patgrp
->sender
);
10620 peAppListF(interp
, resObj
, "%s%p", "cc", pat
->patgrp
->cc
);
10621 peAppListF(interp
, resObj
, "%s%p", "recip", pat
->patgrp
->recip
);
10622 peAppListF(interp
, resObj
, "%s%p", "partic", pat
->patgrp
->partic
);
10623 peAppListF(interp
, resObj
, "%s%p", "news", pat
->patgrp
->news
);
10624 peAppListF(interp
, resObj
, "%s%p", "subj", pat
->patgrp
->subj
);
10625 peAppListF(interp
, resObj
, "%s%p", "alltext", pat
->patgrp
->alltext
);
10626 peAppListF(interp
, resObj
, "%s%p", "bodytext", pat
->patgrp
->bodytext
);
10627 peAppListF(interp
, resObj
, "%s%p", "keyword", pat
->patgrp
->keyword
);
10628 peAppListF(interp
, resObj
, "%s%p", "charset", pat
->patgrp
->charsets
);
10630 peAppListF(interp
, resObj
, "%s%v", "score", pat
->patgrp
->score
);
10631 peAppListF(interp
, resObj
, "%s%v", "age", pat
->patgrp
->age
);
10632 peAppListF(interp
, resObj
, "%s%v", "size", pat
->patgrp
->size
);
10634 if((ah
= pat
->patgrp
->arbhdr
) != NULL
){
10635 Tcl_Obj
*hlObj
, *hObj
;
10637 hlObj
= Tcl_NewListObj(0, NULL
);
10638 Tcl_ListObjAppendElement(interp
, hlObj
, Tcl_NewStringObj("headers", -1));
10640 for(; ah
; ah
= ah
->next
){
10641 hObj
= Tcl_NewListObj(0, NULL
);
10642 peAppListF(interp
, hObj
, "%s%p", ah
->field
? ah
->field
: "", ah
->p
);
10643 Tcl_ListObjAppendElement(interp
, hlObj
, hObj
);
10646 Tcl_ListObjAppendElement(interp
, resObj
, hlObj
);
10649 switch(pat
->patgrp
->fldr_type
){
10651 peAppListF(interp
, resObj
, "%s%s", "ftype", "any");
10654 peAppListF(interp
, resObj
, "%s%s", "ftype", "news");
10657 peAppListF(interp
, resObj
, "%s%s", "ftype", "email");
10659 case FLDR_SPECIFIC
:
10660 peAppListF(interp
, resObj
, "%s%s", "ftype", "specific");
10664 peAppListF(interp
, resObj
, "%s%p", "folder", pat
->patgrp
->folder
);
10665 peAppListF(interp
, resObj
, "%s%s", "stat_new", pePatStatStr(pat
->patgrp
->stat_new
));
10666 peAppListF(interp
, resObj
, "%s%s", "stat_rec", pePatStatStr(pat
->patgrp
->stat_rec
));
10667 peAppListF(interp
, resObj
, "%s%s", "stat_del", pePatStatStr(pat
->patgrp
->stat_del
));
10668 peAppListF(interp
, resObj
, "%s%s", "stat_imp", pePatStatStr(pat
->patgrp
->stat_imp
));
10669 peAppListF(interp
, resObj
, "%s%s", "stat_ans", pePatStatStr(pat
->patgrp
->stat_ans
));
10670 peAppListF(interp
, resObj
, "%s%s", "stat_8bitsubj", pePatStatStr(pat
->patgrp
->stat_8bitsubj
));
10671 peAppListF(interp
, resObj
, "%s%s", "stat_bom", pePatStatStr(pat
->patgrp
->stat_bom
));
10672 peAppListF(interp
, resObj
, "%s%s", "stat_boy", pePatStatStr(pat
->patgrp
->stat_boy
));
10674 Tcl_ListObjAppendElement(interp
, patObj
, resObj
);
10679 pePatStatStr(int value
)
10682 case PAT_STAT_EITHER
:
10698 * peCreateUserContext - create new wps_global and set it up
10701 peCreateUserContext(Tcl_Interp
*interp
, char *user
, char *config
, char *defconf
)
10704 peDestroyUserContext(&wps_global
);
10706 set_collation(1, 1);
10708 wps_global
= new_pine_struct();
10710 /*----------------------------------------------------------------------
10711 Place any necessary constraints on pith processing
10712 ----------------------------------------------------------------------*/
10714 /* got thru close procedure without expunging */
10715 wps_global
->noexpunge_on_close
= 1;
10717 /* do NOT let user set path to local executable */
10718 wps_global
->vars
[V_SENDMAIL_PATH
].is_user
= 0;
10721 /*----------------------------------------------------------------------
10722 Proceed with reading acquiring user settings
10723 ----------------------------------------------------------------------*/
10724 if(wps_global
->pinerc
)
10725 fs_give((void **) &wps_global
->pinerc
);
10727 if(wps_global
->prc
)
10728 free_pinerc_s(&wps_global
->prc
);
10730 if(!IS_REMOTE(config
)){
10731 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote config: %s", config
);
10732 return(wtmp_20k_buf
);
10735 wps_global
->prc
= new_pinerc_s(config
);
10738 if(wps_global
->pconf
)
10739 free_pinerc_s(&wps_global
->pconf
);
10741 wps_global
->pconf
= new_pinerc_s(defconf
);
10745 * Fake up some user information
10747 wps_global
->ui
.login
= cpystr(user
);
10751 * Prep for IMAP debugging
10753 setup_imap_debug();
10756 /* CHECK FOR AND PASS BACK ANY INIT ERRORS */
10757 return(peLoadConfig(wps_global
));
10763 peDestroyUserContext(struct pine
**pps
)
10766 completely_done_with_adrbks();
10768 free_pinerc_strings(pps
);
10770 imap_flush_passwd_cache(TRUE
);
10772 clear_index_cache(sp_inbox_stream(), 0);
10773 free_newsgrp_cache();
10775 close_patterns(0L);
10777 free_contexts(&wps_global
->context_list
);
10781 free_strlist(&peCertHosts
);
10783 free_pine_struct(pps
);
10788 peLoadConfig(struct pine
*pine_state
)
10791 char *s
, *db
= NULL
;
10792 extern void init_signals(void); /* in signal.c */
10795 return("No global state present");
10798 /*turned off because we don't care about local user*/
10799 /* need home directory early */
10800 get_user_info(&pine_state
->ui
);
10802 pine_state
->home_dir
= cpystr((getenv("HOME") != NULL
)
10804 : pine_state
->ui
.homedir
);
10807 init_pinerc(pine_state
, &db
);
10809 fs_give((void **) &db
);
10812 * Initial allocation of array of stream pool pointers.
10813 * We do this before init_vars so that we can re-use streams used for
10814 * remote config files. These sizes may get changed later.
10816 wps_global
->s_pool
.max_remstream
= 2;
10818 wps_global
->c_client_error
[0] = '\0';
10820 pePrepareForAuthException();
10822 peInitVars(pine_state
);
10824 if((s
= peAuthException()) != NULL
)
10826 else if(wps_global
->c_client_error
[0])
10827 return(wps_global
->c_client_error
);
10829 mail_parameters(NULL
, SET_SENDCOMMAND
, (void *) pine_imap_cmd_happened
);
10830 mail_parameters(NULL
, SET_FREESTREAMSPAREP
, (void *) sp_free_callback
);
10831 mail_parameters(NULL
, SET_FREEELTSPAREP
, (void *) free_pine_elt
);
10834 * Install callback to handle certificate validation failures,
10835 * allowing the user to continue if they wish.
10837 mail_parameters(NULL
, SET_SSLCERTIFICATEQUERY
, (void *) alpine_sslcertquery
);
10838 mail_parameters(NULL
, SET_SSLFAILURE
, (void *) alpine_sslfailure
);
10841 * Set up a c-client read timeout and timeout handler. In general,
10842 * it shouldn't happen, but a server crash or dead link can cause
10843 * pine to appear wedged if we don't set this up...
10845 mail_parameters(NULL
, SET_OPENTIMEOUT
,
10846 (void *)((pine_state
->VAR_TCPOPENTIMEO
10847 && (rv
= atoi(pine_state
->VAR_TCPOPENTIMEO
)) > 4)
10848 ? (long) rv
: 30L));
10849 mail_parameters(NULL
, SET_TIMEOUT
, (void *) alpine_tcptimeout
);
10851 if(pine_state
->VAR_RSHOPENTIMEO
10852 && ((rv
= atoi(pine_state
->VAR_RSHOPENTIMEO
)) == 0 || rv
> 4))
10853 mail_parameters(NULL
, SET_RSHTIMEOUT
, (void *) (long) rv
);
10855 if(pine_state
->VAR_SSHOPENTIMEO
10856 && ((rv
= atoi(pine_state
->VAR_SSHOPENTIMEO
)) == 0 || rv
> 4))
10857 mail_parameters(NULL
, SET_SSHTIMEOUT
, (void *) (long) rv
);
10860 * Tell c-client not to be so aggressive about uid mappings
10862 mail_parameters(NULL
, SET_UIDLOOKAHEAD
, (void *) 20);
10865 * Setup referral handling
10867 mail_parameters(NULL
, SET_IMAPREFERRAL
, (void *) imap_referral
);
10868 mail_parameters(NULL
, SET_MAILPROXYCOPY
, (void *) imap_proxycopy
);
10871 * Install extra headers to fetch along with all the other stuff
10872 * mail_fetch_structure and mail_fetch_overview requests.
10876 if(get_extra_hdrs())
10877 (void) mail_parameters(NULL
, SET_IMAPEXTRAHEADERS
, (void *) get_extra_hdrs());
10879 (void) init_username(pine_state
);
10881 (void) init_hostname(wps_global
);
10884 (void) init_ldap_pname(wps_global
);
10885 #endif /* ENABLE_LDAP */
10887 if(wps_global
->prc
&& wps_global
->prc
->type
== Loc
&&
10888 can_access(wps_global
->pinerc
, ACCESS_EXISTS
) == 0 &&
10889 can_access(wps_global
->pinerc
, EDIT_ACCESS
) != 0)
10890 wps_global
->readonly_pinerc
= 1;
10893 * c-client needs USR2 and we might as well
10894 * do something sensible with HUP and TERM
10898 strncpy(pine_state
->inbox_name
, INBOX_NAME
, sizeof(pine_state
->inbox_name
));
10899 pine_state
->inbox_name
[sizeof(pine_state
->inbox_name
)-1] = '\0';
10901 init_folders(pine_state
); /* digest folder spec's */
10904 * Various options we want to make sure are set OUR way
10906 F_TURN_ON(F_QUELL_IMAP_ENV_CB
, pine_state
);
10907 F_TURN_ON(F_SLCTBL_ITEM_NOBOLD
, pine_state
);
10908 F_TURN_OFF(F_USE_SYSTEM_TRANS
, pine_state
);
10911 * Fake screen dimensions for index formatting and
10912 * message display wrap...
10914 wps_global
->ttyo
= (struct ttyo
*) fs_get(sizeof(struct ttyo
));
10915 wps_global
->ttyo
->screen_rows
= FAKE_SCREEN_LENGTH
;
10916 wps_global
->ttyo
->screen_cols
= FAKE_SCREEN_WIDTH
;
10917 if(wps_global
->VAR_WP_COLUMNS
){
10918 int w
= atoi(wps_global
->VAR_WP_COLUMNS
);
10919 if(w
>= 20 && w
<= 128)
10920 wps_global
->ttyo
->screen_cols
= w
;
10923 wps_global
->ttyo
->header_rows
= 0;
10924 wps_global
->ttyo
->footer_rows
= 0;
10928 if(wps_global
->VAR_NORM_FORE_COLOR
)
10929 pico_nfcolor(wps_global
->VAR_NORM_FORE_COLOR
);
10931 if(wps_global
->VAR_NORM_BACK_COLOR
)
10932 pico_nbcolor(wps_global
->VAR_NORM_BACK_COLOR
);
10934 if(wps_global
->VAR_REV_FORE_COLOR
)
10935 pico_rfcolor(wps_global
->VAR_REV_FORE_COLOR
);
10937 if(wps_global
->VAR_REV_BACK_COLOR
)
10938 pico_rbcolor(wps_global
->VAR_REV_BACK_COLOR
);
10940 pico_set_normal_color();
10947 peCreateStream(Tcl_Interp
*interp
, CONTEXT_S
*context
, char *mailbox
, int do_inbox
)
10949 unsigned long flgs
= 0L;
10952 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
10954 pePrepareForAuthException();
10957 flgs
|= DB_INBOXWOCNTXT
;
10959 if(do_broach_folder(mailbox
, context
, NULL
, flgs
) && wps_global
->mail_stream
){
10960 dprint((SYSDBG_INFO
, "Mailbox open: %s",
10961 wps_global
->mail_stream
->mailbox
? wps_global
->mail_stream
->mailbox
: "<UNKNOWN>"));
10965 Tcl_SetResult(interp
,
10966 (s
= peAuthException())
10968 : (*wps_global
->last_error
)
10969 ? wps_global
->last_error
10977 peDestroyStream(struct pine
*ps
)
10982 cur_is_inbox
= (sp_inbox_stream() == wps_global
->mail_stream
);
10984 /* clean up open streams */
10985 if(ps
->mail_stream
){
10986 expunge_and_close(ps
->mail_stream
, NULL
, EC_NONE
);
10987 wps_global
->mail_stream
= NULL
;
10988 wps_global
->cur_folder
[0] = '\0';
10992 mn_give(&ps
->msgmap
);
10994 if(sp_inbox_stream() && !cur_is_inbox
){
10995 ps
->mail_stream
= sp_inbox_stream();
10996 ps
->msgmap
= sp_msgmap(ps
->mail_stream
);
10997 sp_set_expunge_count(wps_global
->mail_stream
, 0L);
10998 expunge_and_close(sp_inbox_stream(), NULL
, EC_NONE
);
10999 mn_give(&ps
->msgmap
);
11006 * pePrepareForAuthException - set globals to get feedback from bowels of c-client
11009 pePrepareForAuthException(void)
11011 peNoPassword
= peCredentialError
= peCertFailure
= peCertQuery
= 0;
11015 * pePrepareForAuthException - check globals getting feedback from bowels of c-client
11018 peAuthException(void)
11020 static char buf
[CRED_REQ_SIZE
];
11023 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", CERT_QUERY_STRING
, peCredentialRequestor
);
11028 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", CERT_FAILURE_STRING
, peCredentialRequestor
);
11033 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", AUTH_EMPTY_STRING
, peCredentialRequestor
);
11037 if(peCredentialError
){
11038 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", AUTH_FAILURE_STRING
, peCredentialRequestor
);
11047 peInitVars(struct pine
*ps
)
11049 init_vars(ps
, NULL
);
11052 * fix display/keyboard-character-set to utf-8
11057 if(ps
->display_charmap
)
11058 fs_give((void **) &ps
->display_charmap
);
11060 ps
->display_charmap
= cpystr(WP_INTERNAL_CHARSET
);
11062 if(ps
->keyboard_charmap
)
11063 fs_give((void **) &ps
->keyboard_charmap
);
11065 ps
->keyboard_charmap
= cpystr(WP_INTERNAL_CHARSET
);
11067 (void) setup_for_input_output(FALSE
, &ps
->display_charmap
, &ps
->keyboard_charmap
, &ps
->input_cs
, NULL
);;
11073 peMessageBounce(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
11075 char *errstr
= NULL
, *to
, *subj
= NULL
, errbuf
[WP_MAX_POST_ERROR
+ 1];
11077 ENVELOPE
*env
, *outgoing
= NULL
;
11083 rawno
= peSequenceNumber(uid
);
11085 if(objc
> 0 && objv
[0] && (to
= Tcl_GetStringFromObj(objv
[0], NULL
))){
11086 if(objc
== 2 && objv
[1]){
11087 subj
= Tcl_GetStringFromObj(objv
[1], NULL
);
11089 else if((env
= mail_fetchstructure(wps_global
->mail_stream
, rawno
, NULL
)) != NULL
){
11090 subj
= env
->subject
;
11093 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
11097 if((errstr
= bounce_msg_body(wps_global
->mail_stream
, rawno
, NULL
,
11098 &to
, subj
, &outgoing
, &body
, NULL
))){
11099 Tcl_SetResult(interp
, errstr
, TCL_VOLATILE
);
11103 metaenv
= pine_new_env(outgoing
, NULL
, NULL
, custom
= peCustomHdrs());
11105 if(!outgoing
->from
)
11106 outgoing
->from
= generate_from();
11108 rfc822_date(wtmp_20k_buf
);
11109 outgoing
->date
= (unsigned char *) cpystr(wtmp_20k_buf
);
11111 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
11112 if(!outgoing
->message_id
)
11113 outgoing
->message_id
= generate_message_id(NULL
);
11117 if(peDoPost(metaenv
, body
, NULL
, NULL
, errbuf
) != TCL_OK
)
11120 pine_free_body(&body
);
11122 pine_free_env(&metaenv
);
11125 free_customs(custom
);
11127 mail_free_envelope(&outgoing
);
11128 pine_free_body(&body
);
11133 Tcl_SetResult(interp
, (errstr
) ? errstr
: "OK", TCL_VOLATILE
);
11134 return(errstr
? TCL_ERROR
: TCL_OK
);
11139 peMessageSpamNotice(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
11141 char *to
, *subj
= NULL
, errbuf
[WP_MAX_POST_ERROR
+ 1], *rs
= NULL
;
11145 rawno
= peSequenceNumber(uid
);
11147 if(objv
[0] && (to
= Tcl_GetStringFromObj(objv
[0], NULL
)) && strlen(to
)){
11150 subj
= Tcl_GetStringFromObj(objv
[1], NULL
);
11152 rs
= peSendSpamReport(rawno
, to
, subj
, errbuf
);
11156 Tcl_SetResult(interp
, (rs
) ? rs
: "OK", TCL_VOLATILE
);
11157 return(rs
? TCL_ERROR
: TCL_OK
);
11162 peSendSpamReport(long rawno
, char *to
, char *subj
, char *errbuf
)
11164 char *errstr
= NULL
, *tmp_a_string
;
11165 ENVELOPE
*env
, *outgoing
;
11169 static char *fakedomain
= "@";
11173 if((env
= mail_fetchstructure(wps_global
->mail_stream
, rawno
, NULL
)) == NULL
){
11174 return(wps_global
->last_error
);
11177 /* empty subject gets "spam" subject */
11178 if(!(subj
&& *subj
))
11179 subj
= env
->subject
;
11181 /*---- New Body to start with ----*/
11182 body
= mail_newbody();
11183 body
->type
= TYPEMULTIPART
;
11185 /*---- The TEXT part/body ----*/
11186 body
->nested
.part
= mail_newbody_part();
11187 body
->nested
.part
->body
.type
= TYPETEXT
;
11189 if((msgtext
= (void *)so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
11190 pine_free_body(&body
);
11191 return("peSendSpamReport: Can't allocate text");
11194 sprintf(wtmp_20k_buf
,
11195 "The attached message is being reported to <%s> as Spam\n",
11197 so_puts((STORE_S
*) msgtext
, wtmp_20k_buf
);
11198 body
->nested
.part
->body
.contents
.text
.data
= msgtext
;
11201 /*---- Attach the raw message ----*/
11202 if(forward_mime_msg(wps_global
->mail_stream
, rawno
, NULL
, env
,
11203 &(body
->nested
.part
->next
), msgtext
)){
11204 outgoing
= mail_newenvelope();
11205 metaenv
= pine_new_env(outgoing
, NULL
, NULL
, custom
= peCustomHdrs());
11208 pine_free_body(&body
);
11209 return("peSendSpamReport: Can't generate forwarded message");
11212 /* rfc822_parse_adrlist feels free to destroy input so copy */
11213 tmp_a_string
= cpystr(to
);
11214 rfc822_parse_adrlist(&outgoing
->to
, tmp_a_string
,
11215 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, wps_global
))
11216 ? fakedomain
: wps_global
->maildomain
);
11217 fs_give((void **) &tmp_a_string
);
11219 outgoing
->from
= generate_from();
11220 outgoing
->subject
= cpystr(subj
);
11221 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
11222 outgoing
->message_id
= generate_message_id(NULL
);
11224 rfc822_date(wtmp_20k_buf
);
11225 outgoing
->date
= (unsigned char *) cpystr(wtmp_20k_buf
);
11227 /* NO FCC for Spam Reporting */
11229 if(peDoPost(metaenv
, body
, NULL
, NULL
, errbuf
) != TCL_OK
)
11232 pine_free_body(&body
);
11234 pine_free_env(&metaenv
);
11237 free_customs(custom
);
11239 mail_free_envelope(&outgoing
);
11240 pine_free_body(&body
);
11246 /* * * * * * * * * * * * * Start of Composer Routines * * * * * * * * * * * */
11250 * PEComposeCmd - export various bits of alpine state
11253 PEComposeCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
11255 char *err
= "PECompose: Unknown request";
11257 dprint((2, "PEComposeCmd"));
11260 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
11262 else if(!wps_global
){
11263 Tcl_SetResult(interp
, "peCompose: no config present", TCL_STATIC
);
11267 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
11270 if(!strcmp(s1
, "post")){
11271 long flags
= PMC_NONE
;
11272 if(F_ON(F_COMPOSE_REJECTS_UNQUAL
, wps_global
))
11273 flags
|= PMC_FORCE_QUAL
;
11275 return(peMsgCollector(interp
, objc
- 2, (Tcl_Obj
**) &objv
[2], peDoPost
, flags
));
11277 else if(objc
== 2){
11278 if(!strcmp(s1
, "userhdrs")){
11281 PINEFIELD
*custom
, *cp
;
11283 static char *standard
[] = {"To", "Cc", "Bcc", "Fcc", "Attach", "Subject", NULL
};
11285 custom
= peCustomHdrs();
11287 for(i
= 0; standard
[i
]; i
++){
11289 for(cp
= custom
; cp
; cp
= cp
->next
)
11290 if(!strucmp(cp
->name
, standard
[i
]))
11293 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", standard
[i
], p
);
11296 for(cp
= custom
; cp
!= NULL
; cp
= cp
->next
){
11297 if(!strucmp(cp
->name
, "from")){
11298 if(F_OFF(F_ALLOW_CHANGING_FROM
, wps_global
))
11301 if(cp
->textbuf
&& strlen(cp
->textbuf
)){
11307 wtmp_20k_buf
[0] = '\0';
11308 rbuf
.f
= dummy_soutr
;
11310 rbuf
.beg
= wtmp_20k_buf
;
11311 rbuf
.cur
= wtmp_20k_buf
;
11312 rbuf
.end
= wtmp_20k_buf
+SIZEOF_20KBUF
-1;
11313 rfc822_output_address_list(&rbuf
, from
= generate_from(), 0L, NULL
);
11315 mail_free_address(&from
);
11321 for(i
= 0; standard
[i
]; i
++)
11322 if(!strucmp(standard
[i
], cp
->name
))
11329 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", cp
->name
, p
);
11333 free_customs(custom
);
11337 else if(!strcmp(s1
, "syshdrs")){
11339 static char *extras
[] = {"In-Reply-To", "X-Reply-UID", NULL
};
11341 for(i
= 0; extras
[i
]; i
++)
11342 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", extras
[i
], NULL
);
11346 else if(!strcmp(s1
, "composehdrs")){
11349 if((p
= wps_global
->VAR_COMP_HDRS
) && *p
){
11351 Tcl_ListObjAppendElement(interp
,
11352 Tcl_GetObjResult(interp
),
11353 Tcl_NewStringObj(*p
, (q
= strchr(*p
, ':'))
11357 Tcl_SetResult(interp
, "", TCL_STATIC
);
11361 else if(!strcmp(s1
, "fccdefault")){
11363 CONTEXT_S
*c
= default_save_context(wps_global
->context_list
), *c2
;
11365 for(c2
= wps_global
->context_list
; c
&& c
!= c2
; c2
= c2
->next
)
11368 Tcl_ListObjAppendElement(interp
,
11369 Tcl_GetObjResult(interp
),
11370 Tcl_NewIntObj(ci
));
11371 Tcl_ListObjAppendElement(interp
,
11372 Tcl_GetObjResult(interp
),
11373 Tcl_NewStringObj(wps_global
->VAR_DEFAULT_FCC
11374 ? wps_global
->VAR_DEFAULT_FCC
11378 else if(!strcmp(s1
, "noattach")){
11379 peFreeAttach(&peCompAttach
);
11380 Tcl_SetResult(interp
, "OK", TCL_VOLATILE
);
11383 else if(!strcmp(s1
, "from")){
11385 ADDRESS
*from
= generate_from();
11386 wtmp_20k_buf
[0] = '\0';
11387 rbuf
.f
= dummy_soutr
;
11389 rbuf
.beg
= wtmp_20k_buf
;
11390 rbuf
.cur
= wtmp_20k_buf
;
11391 rbuf
.end
= wtmp_20k_buf
+SIZEOF_20KBUF
-1;
11392 rfc822_output_address_list(&rbuf
, from
, 0L, NULL
);
11394 mail_free_address(&from
);
11395 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
11398 else if(!strcmp(s1
, "attachments")){
11400 Tcl_Obj
*objAttach
;
11402 for(p
= peCompAttach
; p
; p
= p
->next
)
11404 objAttach
= Tcl_NewListObj(0, NULL
);
11407 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(p
->id
,-1));
11410 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(p
->l
.f
.remote
,-1));
11413 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewLongObj(p
->l
.f
.size
));
11416 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s", p
->l
.f
.type
, p
->l
.f
.subtype
);
11417 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(wtmp_20k_buf
,-1));
11419 /* append to list */
11420 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
11425 objAttach
= Tcl_NewListObj(0, NULL
);
11428 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(p
->id
,-1));
11431 if((name
= get_filename_parameter(NULL
, 0, p
->l
.b
.body
, NULL
)) != NULL
){
11432 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(name
, -1));
11433 fs_give((void **) &name
);
11436 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj("Unknown", -1));
11439 Tcl_ListObjAppendElement(interp
, objAttach
,
11440 Tcl_NewLongObj((p
->l
.b
.body
->encoding
== ENCBASE64
)
11441 ? ((p
->l
.b
.body
->size
.bytes
* 3)/4)
11442 : p
->l
.b
.body
->size
.bytes
));
11445 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s",
11446 body_type_names(p
->l
.b
.body
->type
),
11447 p
->l
.b
.body
->subtype
? p
->l
.b
.body
->subtype
: "Unknown");
11448 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(wtmp_20k_buf
, -1));
11450 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
11456 else if(objc
== 3){
11457 if(!strcmp(s1
, "unattach")){
11460 if((id
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
11461 if(peClearAttachID(id
)){
11462 Tcl_SetResult(interp
, "OK", TCL_STATIC
);
11466 err
= "Can't access attachment id";
11469 err
= "Can't read attachment id";
11471 else if(!strcmp(s1
, "attachinfo")){
11475 /* return: remote-filename size "type/subtype" */
11476 if((id
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
11477 if((a
= peGetAttachID(id
)) != NULL
){
11480 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(a
->l
.f
.remote
,-1));
11483 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewLongObj(a
->l
.f
.size
));
11486 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s", a
->l
.f
.type
, a
->l
.f
.subtype
);
11487 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(wtmp_20k_buf
,-1));
11490 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
11491 Tcl_NewStringObj((a
->l
.f
.description
) ? a
->l
.f
.description
: "",-1));
11498 if((name
= get_filename_parameter(NULL
, 0, a
->l
.b
.body
, NULL
)) != NULL
){
11499 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(name
, -1));
11500 fs_give((void **) &name
);
11503 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj("Unknown", -1));
11506 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
11507 Tcl_NewLongObj((a
->l
.b
.body
->encoding
== ENCBASE64
)
11508 ? ((a
->l
.b
.body
->size
.bytes
* 3)/4)
11509 : a
->l
.b
.body
->size
.bytes
));
11512 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s",
11513 body_type_names(a
->l
.b
.body
->type
),
11514 a
->l
.b
.body
->subtype
? a
->l
.b
.body
->subtype
: "Unknown");
11516 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(wtmp_20k_buf
, -1));
11519 if(a
->l
.b
.body
->description
){
11520 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%.*s", 256, a
->l
.b
.body
->description
);
11522 else if((s
= parameter_val(a
->l
.b
.body
->parameter
, "description")) != NULL
){
11523 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%.*s", 256, s
);
11524 fs_give((void **) &s
);
11527 wtmp_20k_buf
[0] = '\0';
11529 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(wtmp_20k_buf
, -1));
11534 err
= "Unknown attachment type";
11537 err
= "Can't access attachment id";
11540 err
= "Can't read attachment id";
11543 else if(objc
== 7){
11544 if(!strcmp(s1
, "attach")){
11545 char *file
, *remote
, *type
, *subtype
, *desc
;
11547 if((file
= Tcl_GetStringFromObj(objv
[2], NULL
))
11548 && (type
= Tcl_GetStringFromObj(objv
[3], NULL
))
11549 && (subtype
= Tcl_GetStringFromObj(objv
[4], NULL
))
11550 && (remote
= Tcl_GetStringFromObj(objv
[5], NULL
))){
11553 desc
= Tcl_GetStringFromObj(objv
[6], &dl
);
11556 Tcl_SetResult(interp
, peFileAttachID(file
, type
, subtype
, remote
, desc
, dl
), TCL_VOLATILE
);
11560 err
= "Can't read file description";
11563 err
= "Can't read file name";
11569 Tcl_SetResult(interp
, err
, TCL_STATIC
);
11577 COMPATT_S
*p
= (COMPATT_S
*) fs_get(sizeof(COMPATT_S
));
11578 memset(p
, 0, sizeof(COMPATT_S
));
11584 peFreeAttach(COMPATT_S
**a
)
11587 fs_give((void **) &(*a
)->id
);
11591 fs_give((void **) &(*a
)->l
.f
.type
);
11593 if((*a
)->l
.f
.subtype
)
11594 fs_give((void **) &(*a
)->l
.f
.subtype
);
11596 if((*a
)->l
.f
.remote
)
11597 fs_give((void **) &(*a
)->l
.f
.remote
);
11599 if((*a
)->l
.f
.local
){
11600 (void) unlink((*a
)->l
.f
.local
);
11601 fs_give((void **) &(*a
)->l
.f
.local
);
11604 if((*a
)->l
.f
.description
)
11605 fs_give((void **) &(*a
)->l
.f
.description
);
11607 else if((*a
)->body
){
11608 pine_free_body(&(*a
)->l
.b
.body
);
11611 peFreeAttach(&(*a
)->next
);
11612 fs_give((void **) a
);
11618 peFileAttachID(char *f
, char *t
, char *st
, char *r
, char *d
, int dl
)
11620 COMPATT_S
*ap
= peNewAttach(), *p
;
11624 ap
->l
.f
.local
= cpystr(f
);
11625 ap
->l
.f
.size
= name_file_size(f
);
11627 hval
= line_hash(f
);
11628 while(1) /* collisions? */
11629 if(peGetAttachID(ap
->id
= cpystr(long2string(hval
)))){
11630 fs_give((void **) &ap
->id
);
11636 ap
->l
.f
.remote
= cpystr(r
? r
: "");
11637 ap
->l
.f
.type
= cpystr(t
? t
: "Text");
11638 ap
->l
.f
.subtype
= cpystr(st
? st
: "Plain");
11640 ap
->l
.f
.description
= fs_get(dl
+ 1);
11641 snprintf(ap
->l
.f
.description
, dl
+ 1, "%s", d
);
11643 if((p
= peCompAttach
) != NULL
){
11649 while((p
= p
->next
) != NULL
);
11659 peBodyAttachID(BODY
*b
)
11661 COMPATT_S
*ap
= peNewAttach(), *p
;
11662 unsigned long hval
;
11665 ap
->l
.b
.body
= copy_body(NULL
, b
);
11667 hval
= b
->id
? line_hash(b
->id
) : time(0);
11668 while(1) /* collisions? */
11669 if(peGetAttachID(ap
->id
= cpystr(ulong2string(hval
)))){
11670 fs_give((void **) &ap
->id
);
11676 /* move contents pointer to copy */
11677 peBodyMoveContents(b
, ap
->l
.b
.body
);
11679 if((p
= peCompAttach
) != NULL
){
11685 while((p
= p
->next
) != NULL
);
11695 peBodyMoveContents(BODY
*bs
, BODY
*bd
)
11698 if(bs
->type
== TYPEMULTIPART
&& bd
->type
== TYPEMULTIPART
){
11699 PART
*ps
= bs
->nested
.part
,
11700 *pd
= bd
->nested
.part
;
11701 do /* for each part */
11702 peBodyMoveContents(&ps
->body
, &pd
->body
);
11703 while ((ps
= ps
->next
) && (pd
= pd
->next
)); /* until done */
11705 else if(bs
->contents
.text
.data
){
11706 bd
->contents
.text
.data
= bs
->contents
.text
.data
;
11707 bs
->contents
.text
.data
= NULL
;
11715 peGetAttachID(char *h
)
11719 for(p
= peCompAttach
; p
; p
= p
->next
)
11720 if(!strcmp(p
->id
, h
))
11728 peClearAttachID(char *h
)
11730 COMPATT_S
*pp
, *pt
= NULL
;
11732 for(pp
= peCompAttach
; pp
; pp
= pp
->next
){
11733 if(!strcmp(pp
->id
, h
)){
11735 pt
->next
= pp
->next
;
11737 peCompAttach
= pp
->next
;
11752 * peDoPost - handle preparing header and body text for posting, prepare
11753 * for any Fcc, then call the mailer to send it out
11756 peDoPost(METAENV
*metaenv
, BODY
*body
, char *fcc
, CONTEXT_S
**fcc_cntxtp
, char *errp
)
11758 int rv
= TCL_OK
, recipients
;
11761 if(commence_fcc(fcc
, fcc_cntxtp
, TRUE
)){
11763 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
11764 pePrepareForAuthException();
11766 if((recipients
= (metaenv
->env
->to
|| metaenv
->env
->cc
|| metaenv
->env
->bcc
))
11767 && call_mailer(metaenv
, body
, NULL
, 0, NULL
, NULL
) < 0){
11768 if((s
= peAuthException()) != NULL
){
11771 else if(wps_global
->last_error
[0]){
11772 sprintf(errp
, "Send Error: %.*s", 64, wps_global
->last_error
);
11774 else if(wps_global
->c_client_error
[0]){
11775 sprintf(errp
, "Send Error: %.*s", 64, wps_global
->c_client_error
);
11778 strcpy(errp
, "Sending Failure");
11781 dprint((1, "call_mailer failed!"));
11783 else if(fcc
&& fcc_cntxtp
&& !wrapup_fcc(fcc
, *fcc_cntxtp
, recipients
? NULL
: metaenv
, body
)){
11784 strcpy(errp
, "Fcc Failed!. No message saved.");
11786 dprint((1, "explicit fcc write failed!"));
11790 REPLY_S
*reply
= NULL
;
11792 /* success, now look for x-reply-uid to flip answered flag for? */
11794 for(pf
= metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
11795 if(!strucmp(pf
->name
, "x-reply-uid")){
11797 if((reply
= (REPLY_S
*) build_reply_uid(pf
->textbuf
)) != NULL
){
11799 update_answered_flags(reply
);
11802 fs_give((void **) &reply
->mailbox
);
11805 fs_give((void **) &reply
->prefix
);
11807 if(reply
->data
.uid
.msgs
)
11808 fs_give((void **) &reply
->data
.uid
.msgs
);
11810 fs_give((void **) &reply
);
11819 dprint((1,"can't open fcc, cont"));
11821 strcpy(errp
, "Can't open Fcc");
11831 * pePostponeCmd - export various bits of alpine state
11834 PEPostponeCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
11836 char *err
= "PEPostpone: unknown request";
11840 dprint((2, "PEPostponeCmd"));
11843 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
11845 else if(!wps_global
){
11846 Tcl_SetResult(interp
, "pePostpone: no config present", TCL_STATIC
);
11850 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
11853 if(!strcmp(s1
, "extract")){
11854 if(Tcl_GetLongFromObj(interp
, objv
[2], &uidl
) == TCL_OK
){
11855 Tcl_Obj
*objHdr
= NULL
, *objBod
= NULL
, *objAttach
= NULL
, *objOpts
= NULL
;
11856 MAILSTREAM
*stream
;
11858 ENVELOPE
*env
= NULL
;
11859 PINEFIELD
*custom
= NULL
, *cp
;
11860 REPLY_S
*reply
= NULL
;
11861 ACTION_S
*role
= NULL
;
11865 char *fcc
= NULL
, *lcc
= NULL
;
11866 unsigned flags
= REDRAFT_DEL
| REDRAFT_PPND
;
11869 if(objc
> 3){ /* optional flags */
11871 Tcl_Obj
**objFlags
;
11874 Tcl_ListObjGetElements(interp
, objv
[3], &nFlags
, &objFlags
);
11875 for(i
= 0; i
< nFlags
; i
++){
11876 if((flagstr
= Tcl_GetStringFromObj(objFlags
[i
], NULL
)) == NULL
){
11880 if(!strucmp(flagstr
, "html"))
11881 flags
|= REDRAFT_HTML
;
11884 /* BUG: should probably complain if argc > 4 */
11887 && postponed_stream(&stream
, wps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0)
11889 if((so
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
11890 if((n
= mail_msgno(stream
, uid
)) > 0L){
11891 if(redraft_work(&stream
, n
, &env
, &b
, &fcc
, &lcc
, &reply
,
11892 NULL
, &custom
, &role
, /* should role be NULL? */
11894 char *charset
= NULL
;
11896 /* prepare to package up for caller */
11897 objHdr
= Tcl_NewListObj(0, NULL
);
11899 /* determine body part's charset */
11900 if((charset
= parameter_val(b
->parameter
,"charset")) != NULL
){
11901 objOpts
= Tcl_NewListObj(0, NULL
);
11902 peAppListF(interp
, objOpts
, "%s%s", "charset", charset
);
11903 fs_give((void **) &charset
);
11906 /* body part's MIME subtype */
11907 if(b
->subtype
&& strucmp(b
->subtype
,"plain")){
11909 objOpts
= Tcl_NewListObj(0, NULL
);
11911 peAppListF(interp
, objOpts
, "%s%s", "subtype", b
->subtype
);
11914 peAppListF(interp
, objHdr
, "%s%a", "from",
11915 role
&& role
->from
? role
->from
: env
->from
);
11916 peAppListF(interp
, objHdr
, "%s%a", "to", env
->to
);
11917 peAppListF(interp
, objHdr
, "%s%a", "cc", env
->cc
);
11918 peAppListF(interp
, objHdr
, "%s%a", "bcc", env
->bcc
);
11919 peAppListF(interp
, objHdr
, "%s%s", "in-reply-to", env
->in_reply_to
);
11920 peAppListF(interp
, objHdr
, "%s%s", "subject",
11921 rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
,
11922 SIZEOF_20KBUF
, env
->subject
));
11925 peFccAppend(interp
, objHdr
, fcc
, -1);
11927 for(cp
= custom
; cp
&& cp
->name
; cp
= cp
->next
)
11930 strncpy(wtmp_20k_buf
, cp
->name
, SIZEOF_20KBUF
);
11931 wtmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
11932 peAppListF(interp
, objHdr
, "%s%a",
11933 lcase((unsigned char *) wtmp_20k_buf
), *cp
->addr
);
11941 break; /* ignored */
11944 strncpy(wtmp_20k_buf
, cp
->name
, SIZEOF_20KBUF
);
11945 wtmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
11946 peAppListF(interp
, objHdr
, "%s%s",
11947 lcase((unsigned char *) wtmp_20k_buf
), cp
->textbuf
? cp
->textbuf
: cp
->val
);
11952 /* blat x-Reply-UID: for possible use? */
11954 char uidbuf
[MAILTMPLEN
], *p
;
11957 for(i
= 0L, p
= wtmp_20k_buf
; reply
->data
.uid
.msgs
[i
]; i
++){
11959 sstrncpy(&p
, ",", SIZEOF_20KBUF
-(p
-wtmp_20k_buf
));
11961 sstrncpy(&p
,ulong2string(reply
->data
.uid
.msgs
[i
]), SIZEOF_20KBUF
-(p
-wtmp_20k_buf
));
11964 wtmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
11966 snprintf(uidbuf
, sizeof(uidbuf
), "(%s%s%s)(%ld %lu %s)%s",
11967 reply
->prefix
? int2string(strlen(reply
->prefix
))
11968 : (reply
->forwarded
) ? "" : "0 ",
11969 reply
->prefix
? " " : "",
11970 reply
->prefix
? reply
->prefix
: "",
11971 i
, reply
->data
.uid
.validity
,
11972 wtmp_20k_buf
, reply
->mailbox
);
11974 peAppListF(interp
, objHdr
, "%s%s", "x-reply-uid", uidbuf
);
11977 fs_give((void **) &reply
->mailbox
);
11978 fs_give((void **) &reply
->prefix
);
11979 fs_give((void **) &reply
->data
.uid
.msgs
);
11980 fs_give((void **) &reply
);
11983 objBod
= Tcl_NewListObj(0, NULL
);
11984 peSoStrToList(interp
, objBod
, so
);
11986 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objHdr
);
11987 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objBod
);
11989 objAttach
= peMsgAttachCollector(interp
, b
);
11991 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
11994 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),objOpts
);
11999 fs_give((void **) &fcc
);
12002 fs_give((void **) &lcc
);
12004 mail_free_envelope(&env
);
12005 pine_free_body(&b
);
12006 free_action(&role
);
12008 /* if Drafts got whacked, open INBOX */
12009 if(!wps_global
->mail_stream
)
12010 do_broach_folder(wps_global
->inbox_name
,
12011 wps_global
->context_list
,
12012 NULL
, DB_INBOXWOCNTXT
);
12020 err
= "Unknown UID";
12023 err
= "No internal storage";
12025 /* redraft_work cleaned up the "stream" */
12028 err
= "No Postponed stream";
12031 err
= "Malformed extract request";
12033 else if(objc
== 2){
12034 if(!strcmp(s1
, "any")){
12035 MAILSTREAM
*stream
;
12037 if(postponed_stream(&stream
, wps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 1) && stream
){
12038 Tcl_SetResult(interp
, "1", TCL_STATIC
);
12040 if(stream
!= wps_global
->mail_stream
)
12041 pine_mail_close(stream
);
12044 Tcl_SetResult(interp
, "0", TCL_STATIC
);
12048 else if(!strcmp(s1
, "count")){
12049 MAILSTREAM
*stream
;
12051 if(postponed_stream(&stream
, wps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12052 Tcl_SetResult(interp
, long2string(stream
->nmsgs
), TCL_STATIC
);
12054 if(stream
!= wps_global
->mail_stream
)
12055 pine_mail_close(stream
);
12058 Tcl_SetResult(interp
, "-1", TCL_STATIC
);
12062 else if(!strcmp(s1
, "list")){
12063 MAILSTREAM
*stream
;
12065 Tcl_Obj
*objEnv
= NULL
, *objEnvList
;
12068 if(postponed_stream(&stream
, wps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12069 if(!stream
->nmsgs
){
12070 (void) redraft_cleanup(&stream
, FALSE
, REDRAFT_PPND
);
12071 Tcl_SetResult(interp
, "", TCL_STATIC
);
12075 objEnvList
= Tcl_NewListObj(0, NULL
);
12077 for(n
= 1; n
<= stream
->nmsgs
; n
++){
12078 if((env
= pine_mail_fetchstructure(stream
, n
, NULL
)) != NULL
){
12079 objEnv
= Tcl_NewListObj(0, NULL
);
12081 peAppListF(interp
, objEnv
, "%s%s", "uid",
12082 ulong2string(mail_uid(stream
, n
)));
12084 peAppListF(interp
, objEnv
, "%s%a", "to", env
->to
);
12086 date_str((char *)env
->date
, iSDate
, 1, wtmp_20k_buf
, SIZEOF_20KBUF
, 0);
12088 peAppListF(interp
, objEnv
, "%s%s", "date", wtmp_20k_buf
);
12090 peAppListF(interp
, objEnv
, "%s%s", "subj",
12091 rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
,
12092 SIZEOF_20KBUF
, env
->subject
));
12094 Tcl_ListObjAppendElement(interp
, objEnvList
, objEnv
);
12098 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objEnvList
);
12100 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
12101 Tcl_NewStringObj("utf-8", -1));
12103 if(stream
!= wps_global
->mail_stream
)
12104 pine_mail_close(stream
);
12107 Tcl_SetResult(interp
, "", TCL_STATIC
);
12112 else if(objc
== 3){
12113 if(!strcmp(s1
, "append")){
12116 if((rv
= peMsgCollector(interp
, objc
- 2, (Tcl_Obj
**) &objv
[2], peDoPostpone
, PMC_NONE
)) == TCL_OK
)
12117 Tcl_SetResult(interp
, ulong2string(get_last_append_uid()), TCL_VOLATILE
);
12121 else if(!strcmp(s1
, "draft")){
12124 if((rv
= peMsgCollector(interp
, objc
- 2, (Tcl_Obj
**) &objv
[2], peDoPostpone
, PMC_PRSRV_ATT
)) == TCL_OK
)
12125 Tcl_SetResult(interp
, ulong2string(get_last_append_uid()), TCL_VOLATILE
);
12129 else if(!strcmp(s1
, "delete")){
12130 if(Tcl_GetLongFromObj(interp
, objv
[2], &uidl
) == TCL_OK
){
12131 MAILSTREAM
*stream
;
12135 if(postponed_stream(&stream
, wps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12136 if((rawno
= mail_msgno(stream
, uid
)) > 0L){
12137 mail_flag(stream
, long2string(rawno
), "\\DELETED", ST_SET
);
12138 wps_global
->expunge_in_progress
= 1;
12139 mail_expunge(stream
);
12140 wps_global
->expunge_in_progress
= 0;
12141 if(stream
!= wps_global
->mail_stream
)
12142 pine_mail_actually_close(stream
);
12147 err
= "PEPostpone delete: UID no longer exists";
12150 err
= "PEPostpone delete: No Postponed stream";
12153 err
= "PEPostpone delete: No uid provided";
12159 Tcl_SetResult(interp
, err
, TCL_STATIC
);
12165 * peDoPostpone - handle postponing after message collection
12168 peDoPostpone(METAENV
*metaenv
, BODY
*body
, char *fcc
, CONTEXT_S
**fcc_cntxtp
, char *errp
)
12175 * resolve fcc and store it in fcc custom header field data
12177 if(fcc
&& *fcc
&& fcc_cntxtp
&& *fcc_cntxtp
)
12178 for(pf
= metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
12179 if(!strucmp("fcc", pf
->name
)){
12180 char *name
, *rs
, path_in_context
[MAILTMPLEN
];
12182 if(pf
->textbuf
) /* free old value */
12183 fs_give((void **) &pf
->textbuf
);
12185 /* replace nickname with full name */
12186 if(!(name
= folder_is_nick(fcc
, FOLDERS(*fcc_cntxtp
), FN_NONE
)))
12189 if(context_isambig(name
) && !(((*fcc_cntxtp
)->use
) & CNTXT_SAVEDFLT
)){
12190 context_apply(path_in_context
, *fcc_cntxtp
, name
, sizeof(path_in_context
));
12191 rs
= IS_REMOTE(path_in_context
) ? path_in_context
: NULL
;
12197 pf
->textbuf
= cpystr(rs
);
12198 pf
->text
= &pf
->textbuf
;
12204 au
= mail_parameters(NIL
, GET_APPENDUID
, NIL
);
12205 mail_parameters(NIL
, SET_APPENDUID
, (void *) appenduid_cb
);
12207 rv
= write_postponed(metaenv
, body
);
12209 mail_parameters(NIL
, SET_APPENDUID
, (void *) au
);
12211 return((rv
< 0) ? TCL_ERROR
: TCL_OK
);
12216 * peMsgCollector - Collect message parts and call specified handler
12219 peMsgCollector(Tcl_Interp
*interp
,
12222 int (*postfunc
)(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *),
12225 Tcl_Obj
**objMsg
, **objField
, **objBody
;
12226 int i
, j
, vl
, nMsg
, nField
, nBody
;
12227 char *field
, *value
, *err
= NULL
;
12230 STRLIST_S
*tp
, *lp
;
12231 static char *fakedomain
= "@";
12233 memset(&md
, 0, sizeof(MSG_COL_S
));
12234 md
.postop_fcc_no_attach
= -1;
12235 md
.postfunc
= postfunc
;
12236 md
.qualified_addrs
= ((flags
& PMC_FORCE_QUAL
) == PMC_FORCE_QUAL
);
12239 Tcl_SetResult(interp
, "Malformed message data", TCL_STATIC
);
12242 else if(!wps_global
){
12243 Tcl_SetResult(interp
, "No open folder", TCL_STATIC
);
12247 md
.outgoing
= mail_newenvelope();
12249 md
.metaenv
= pine_new_env(md
.outgoing
, NULL
, NULL
, md
.custom
= peCustomHdrs());
12251 Tcl_ListObjGetElements(interp
, objv
[0], &nMsg
, &objMsg
);
12252 for(i
= 0; i
< nMsg
; i
++){
12253 if(Tcl_ListObjGetElements(interp
, objMsg
[i
], &nField
, &objField
) != TCL_OK
){
12254 err
= ""; /* interp's result object has error message */
12255 return(peMsgCollected(interp
, &md
, err
, flags
));
12258 if(nField
&& (field
= Tcl_GetStringFromObj(objField
[0], NULL
))){
12259 if(!strcmp(field
, "body")){
12261 err
= "Too many bodies";
12262 return(peMsgCollected(interp
, &md
, err
, flags
));
12264 else if((md
.msgtext
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
12265 /* mark storage object as user edited */
12266 (void) so_attr(md
.msgtext
, "edited", "1");
12268 Tcl_ListObjGetElements(interp
, objField
[1], &nBody
, &objBody
);
12269 for(j
= 0; j
< nBody
; j
++){
12270 value
= Tcl_GetStringFromObj(objBody
[j
], &vl
);
12272 so_nputs(md
.msgtext
, value
, vl
);
12273 so_puts(md
.msgtext
, "\n");
12276 err
= "Value read failure";
12277 return(peMsgCollected(interp
, &md
, err
, flags
));
12282 err
= "Can't acquire body storage";
12283 return(peMsgCollected(interp
, &md
, err
, flags
));
12286 else if(!strucmp(field
, "attach")){
12291 && (id
= Tcl_GetStringFromObj(objField
[1], NULL
))
12292 && (a
= peGetAttachID(id
))){
12293 tp
= new_strlist(id
);
12294 if((lp
= md
.attach
) != NULL
){
12300 while((lp
= lp
->next
) != NULL
);
12306 strcpy(err
= wtmp_20k_buf
, "Unknown attachment ID");
12307 return(peMsgCollected(interp
, &md
, err
, flags
));
12310 else if(!strucmp(field
, "fcc")){
12314 if(Tcl_ListObjGetElements(interp
, objField
[1], &nFcc
, &objFcc
) == TCL_OK
12316 && Tcl_GetIntFromObj(interp
, objFcc
[0], &md
.fcc_colid
) == TCL_OK
12317 && (value
= Tcl_GetStringFromObj(objFcc
[1], NULL
))){
12319 fs_give((void **) &md
.fcc
);
12321 md
.fcc
= cpystr(value
);
12324 strcpy(err
= wtmp_20k_buf
, "Unrecognized Fcc specification");
12325 return(peMsgCollected(interp
, &md
, err
, flags
));
12328 else if(!strucmp(field
, "postoption")){
12333 if(Tcl_ListObjGetElements(interp
, objField
[1], &nPO
, &objPO
) == TCL_OK
12335 && (value
= Tcl_GetStringFromObj(objPO
[0], NULL
))){
12336 if(!strucmp(value
,"fcc-without-attachments")){
12337 if(Tcl_GetIntFromObj(interp
, objPO
[1], &ival
) == TCL_OK
){
12338 md
.postop_fcc_no_attach
= (ival
!= 0);
12341 sprintf(err
= wtmp_20k_buf
, "Malformed Post Option: fcc-without-attachments");
12342 return(peMsgCollected(interp
, &md
, err
, flags
));
12345 else if(!strucmp(value
, "charset")){
12346 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12349 for(p
= value
; ; p
++){ /* sanity check */
12351 md
.charset
= cpystr(value
);
12355 if(isspace((unsigned char ) *p
)
12356 || !isprint((unsigned char) *p
))
12359 if(p
- value
> 255)
12364 err
= "Post option read failure";
12365 return(peMsgCollected(interp
, &md
, err
, flags
));
12368 else if(!strucmp(value
, "flowed")){
12369 if(F_OFF(F_QUELL_FLOWED_TEXT
,wps_global
)){
12370 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12371 if(!strucmp(value
, "yes"))
12375 err
= "Post option read failure";
12376 return(peMsgCollected(interp
, &md
, err
, flags
));
12380 else if(!strucmp(value
, "subtype")){
12381 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12382 if(!strucmp(value
, "html"))
12386 err
= "Post option read failure";
12387 return(peMsgCollected(interp
, &md
, err
, flags
));
12390 else if(!strucmp(value
, "priority")){
12391 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12392 char *priority
= NULL
;
12394 if(!strucmp(value
, "highest"))
12395 priority
= "Highest";
12396 else if(!strucmp(value
, "high"))
12398 else if(!strucmp(value
, "normal"))
12399 priority
= "Normal";
12400 else if(!strucmp(value
, "low"))
12402 else if(!strucmp(value
, "lowest"))
12403 priority
= "Lowest";
12406 if((pf
= set_priority_header(md
.metaenv
, priority
)) != NULL
)
12407 pf
->text
= &pf
->textbuf
;
12411 err
= "Post option read failure";
12412 return(peMsgCollected(interp
, &md
, err
, flags
));
12416 sprintf(err
= wtmp_20k_buf
, "Unknown Post Option: %s", value
);
12417 return(peMsgCollected(interp
, &md
, err
, flags
));
12421 sprintf(err
= wtmp_20k_buf
, "Malformed Post Option");
12422 return(peMsgCollected(interp
, &md
, err
, flags
));
12427 sprintf(err
= wtmp_20k_buf
, "Malformed header (%s)", field
);
12428 return(peMsgCollected(interp
, &md
, err
, flags
));
12431 if((value
= Tcl_GetStringFromObj(objField
[1], &vl
)) != NULL
){
12432 ADDRESS
**addrp
= NULL
;
12433 char **valp
= NULL
, *valcpy
;
12435 if(!strucmp(field
, "from")){
12436 addrp
= &md
.outgoing
->from
;
12438 else if(!strucmp(field
, "reply-to")){
12439 addrp
= &md
.outgoing
->reply_to
;
12441 else if(!strucmp(field
, "to")){
12442 addrp
= &md
.outgoing
->to
;
12444 else if(!strucmp(field
, "cc")){
12445 addrp
= &md
.outgoing
->cc
;
12447 else if(!strucmp(field
, "bcc")){
12448 addrp
= &md
.outgoing
->bcc
;
12450 else if(!strucmp(field
, "subject")){
12451 valp
= &md
.outgoing
->subject
;
12453 else if(!strucmp(field
, "in-reply-to")){
12454 valp
= &md
.outgoing
->in_reply_to
;
12456 else if(!strucmp(field
, "newsgroups")){
12457 valp
= &md
.outgoing
->newsgroups
;
12459 else if(!strucmp(field
, "followup-to")){
12460 valp
= &md
.outgoing
->followup_to
;
12462 else if(!strucmp(field
, "references")){
12463 valp
= &md
.outgoing
->references
;
12465 else if(!strucmp(field
, "x-reply-uid")){
12466 for(pf
= md
.metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
12467 if(!strucmp(pf
->name
, "x-reply-uid")){
12468 valp
= pf
->text
= &pf
->textbuf
;
12472 else if(!strucmp(field
, "x-auth-received")){
12473 for(pf
= md
.metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
12474 if(!strucmp(pf
->name
, "x-auth-received")){
12475 valp
= pf
->text
= &pf
->textbuf
;
12480 for(pf
= md
.metaenv
->custom
; pf
&& pf
->name
; pf
= pf
->next
)
12481 if(!strucmp(field
, pf
->name
)){
12482 if(pf
->type
== Address
)
12485 valp
= &pf
->textbuf
;
12486 else if(pf
->textbuf
)
12487 fs_give((void **) &pf
->textbuf
);
12493 dprint((2, "\nPOST: unrecognized field - %s\n", field
));
12498 fs_give((void **) valp
);
12500 sprintf(*valp
= fs_get((vl
+ 1) * sizeof(char)), "%.*s", vl
, value
);
12504 sprintf(valcpy
= fs_get((vl
+ 1) * sizeof(char)), "%.*s", vl
, value
);
12506 for(; *addrp
; addrp
= &(*addrp
)->next
)
12509 rfc822_parse_adrlist(addrp
, valcpy
,
12510 (flags
& PMC_FORCE_QUAL
)
12511 ? fakedomain
: wps_global
->maildomain
);
12512 fs_give((void **) &valcpy
);
12516 err
= "Value read failure";
12517 return(peMsgCollected(interp
, &md
, err
, flags
));
12523 return(peMsgCollected(interp
, &md
, err
, flags
));
12528 * peMsgCollected - Dispatch collected message data and cleanup
12531 peMsgCollected(Tcl_Interp
*interp
, MSG_COL_S
*md
, char *err
, long flags
)
12533 int rv
= TCL_OK
, non_ascii
= FALSE
;
12535 BODY
*body
= NULL
, *tbp
= NULL
;
12536 char errbuf
[WP_MAX_POST_ERROR
+ 1], *charset
;
12541 so_give(&md
->msgtext
);
12545 else if(md
->qualified_addrs
&& check_addresses(md
->metaenv
) == CA_BAD
){
12546 sprintf(err
= wtmp_20k_buf
, "Address must be fully qualified.");
12550 /* sniff body for possible multipart wrapping to protect encoding */
12551 so_seek(md
->msgtext
, 0L, 0);
12553 while(so_readc(&c
, md
->msgtext
))
12554 if(!c
|| c
& 0x80){
12559 if(!md
->outgoing
->from
)
12560 md
->outgoing
->from
= generate_from();
12562 rfc822_date(wtmp_20k_buf
);
12563 md
->outgoing
->date
= (unsigned char *) cpystr(wtmp_20k_buf
);
12564 md
->outgoing
->return_path
= rfc822_cpy_adr(md
->outgoing
->from
);
12565 md
->outgoing
->message_id
= generate_message_id(NULL
);
12567 body
= mail_newbody();
12569 /* wire any attachments to body */
12570 if(md
->attach
|| (non_ascii
&& F_OFF(F_COMPOSE_ALWAYS_DOWNGRADE
, wps_global
))){
12575 /* setup slot for message text */
12576 body
->type
= TYPEMULTIPART
;
12577 body
->nested
.part
= mail_newbody_part();
12578 tbp
= &body
->nested
.part
->body
;
12580 /* link in attachments */
12581 for(lp
= md
->attach
, np
= &body
->nested
.part
->next
; lp
; lp
= lp
->next
, np
= &(*np
)->next
){
12582 if(!(a
= peGetAttachID(lp
->name
))){
12583 err
= "Unknown Attachment ID";
12588 *np
= mail_newbody_part();
12591 (*np
)->body
.id
= generate_message_id(NULL
);
12592 (*np
)->body
.description
= cpystr(a
->l
.f
.description
);
12594 /* set name parameter */
12595 for(pp
= &(*np
)->body
.parameter
; *pp
; )
12596 if(!struncmp((*pp
)->attribute
, "name", 4)
12597 && (!*((*pp
)->attribute
+ 4)
12598 || *((*pp
)->attribute
+ 4) == '*')){
12599 PARAMETER
*free_me
= *pp
;
12601 free_me
->next
= NULL
;
12602 mail_free_body_parameter(&free_me
);
12608 set_parameter(pp
, "name", a
->l
.f
.remote
);
12610 /* Then set the Content-Disposition ala RFC1806 */
12611 if(!(*np
)->body
.disposition
.type
){
12612 (*np
)->body
.disposition
.type
= cpystr("attachment");
12613 for(pp
= &(*np
)->body
.disposition
.parameter
; *pp
; )
12614 if(!struncmp((*pp
)->attribute
, "filename", 4)
12615 && (!*((*pp
)->attribute
+ 4)
12616 || *((*pp
)->attribute
+ 4) == '*')){
12617 PARAMETER
*free_me
= *pp
;
12619 free_me
->next
= NULL
;
12620 mail_free_body_parameter(&free_me
);
12626 set_parameter(pp
, "filename", a
->l
.f
.remote
);
12629 if(((*np
)->body
.contents
.text
.data
= (void *) so_get(FileStar
, a
->l
.f
.local
, READ_ACCESS
)) != NULL
){
12630 (*np
)->body
.type
= mt_translate_type(a
->l
.f
.type
);
12631 (*np
)->body
.subtype
= cpystr(a
->l
.f
.subtype
);
12632 (*np
)->body
.encoding
= ENCBINARY
;
12633 (*np
)->body
.size
.bytes
= name_file_size(a
->l
.f
.local
);
12635 if((*np
)->body
.type
== TYPEOTHER
12636 && !set_mime_type_by_extension(&(*np
)->body
, a
->l
.f
.local
))
12637 set_mime_type_by_grope(&(*np
)->body
);
12639 so_release((STORE_S
*)(*np
)->body
.contents
.text
.data
);
12643 err
= "Can't open uploaded attachment";
12649 BODY
*newbody
= copy_body(NULL
, a
->l
.b
.body
);
12650 (*np
)->body
= *newbody
;
12651 fs_give((void **) &newbody
);
12652 peBodyMoveContents(a
->l
.b
.body
, &(*np
)->body
);
12655 err
= "BOTCH: Unknown attachment type";
12664 /* assign MIME parameters to text body part */
12665 tbp
->type
= TYPETEXT
;
12666 if(md
->html
) tbp
->subtype
= cpystr("HTML");
12668 tbp
->contents
.text
.data
= (void *) md
->msgtext
;
12669 tbp
->encoding
= ENCOTHER
;
12671 /* set any text flowed param */
12673 peMsgSetParm(&tbp
->parameter
, "format", "flowed");
12676 CONTEXT_S
*fcc_cntxt
= wps_global
->context_list
;
12678 while(md
->fcc_colid
--)
12679 if(fcc_cntxt
->next
)
12680 fcc_cntxt
= fcc_cntxt
->next
;
12682 if(md
->postop_fcc_no_attach
>= 0){
12683 int oldval
= F_ON(F_NO_FCC_ATTACH
, wps_global
);
12684 F_SET(F_NO_FCC_ATTACH
, wps_global
, md
->postop_fcc_no_attach
);
12685 md
->postop_fcc_no_attach
= oldval
;
12688 pine_encode_body(body
);
12690 rv
= (*md
->postfunc
)(md
->metaenv
, body
, md
->fcc
, &fcc_cntxt
, errbuf
);
12692 if(md
->postop_fcc_no_attach
>= 0){
12693 F_SET(F_NO_FCC_ATTACH
, wps_global
, md
->postop_fcc_no_attach
);
12697 if((flags
& PMC_PRSRV_ATT
) == 0)
12698 peFreeAttach(&peCompAttach
);
12701 /* maintain pointers to attachments */
12702 (void) peMsgAttachCollector(NULL
, body
);
12707 pine_free_body(&body
);
12711 fs_give((void **) &md
->charset
);
12713 free_strlist(&md
->attach
);
12715 pine_free_env(&md
->metaenv
);
12718 free_customs(md
->custom
);
12720 mail_free_envelope(&md
->outgoing
);
12723 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
12730 peMsgSetParm(PARAMETER
**pp
, char *pa
, char *pv
)
12732 for(; *pp
; pp
= &(*pp
)->next
)
12733 if(!strucmp(pa
, (*pp
)->attribute
)){
12735 fs_give((void **) &(*pp
)->value
);
12741 *pp
= mail_newbody_parameter();
12742 (*pp
)->attribute
= cpystr(pa
);
12745 (*pp
)->value
= cpystr(pv
);
12750 peMsgAttachCollector(Tcl_Interp
*interp
, BODY
*b
)
12752 char *id
, *name
= NULL
;
12754 Tcl_Obj
*aListObj
= NULL
, *aObj
= NULL
;
12756 peFreeAttach(&peCompAttach
);
12759 aListObj
= Tcl_NewListObj(0, NULL
);
12761 if(b
->type
== TYPEMULTIPART
){
12763 * Walk first level, clipping branches and adding them
12764 * to the attachment list...
12766 for(part
= b
->nested
.part
->next
; part
; part
= part
->next
) {
12767 id
= peBodyAttachID(&part
->body
);
12768 aObj
= Tcl_NewListObj(0, NULL
);
12771 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj(id
, -1));
12774 if((name
= get_filename_parameter(NULL
, 0, &part
->body
, NULL
)) != NULL
){
12775 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj(name
, -1));
12776 fs_give((void **) &name
);
12779 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj("Unknown", -1));
12782 Tcl_ListObjAppendElement(interp
, aObj
,
12783 Tcl_NewLongObj((part
->body
.encoding
== ENCBASE64
)
12784 ? ((part
->body
.size
.bytes
* 3)/4)
12785 : part
->body
.size
.bytes
));
12788 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s",
12789 body_type_names(part
->body
.type
),
12790 part
->body
.subtype
? part
->body
.subtype
: rfc822_default_subtype (part
->body
.type
));
12791 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj(wtmp_20k_buf
, -1));
12792 Tcl_ListObjAppendElement(interp
, aListObj
, aObj
);
12802 peFccAppend(Tcl_Interp
*interp
, Tcl_Obj
*obj
, char *fcc
, int colid
)
12804 Tcl_Obj
*objfcc
= NULL
;
12807 colid
= (wps_global
->context_list
&& (wps_global
->context_list
->use
& CNTXT_INCMNG
)) ? 1 : 0;
12809 return((objfcc
= Tcl_NewListObj(0, NULL
))
12810 && Tcl_ListObjAppendElement(interp
, objfcc
, Tcl_NewStringObj("fcc", -1)) == TCL_OK
12811 && peAppListF(interp
, objfcc
, "%i%s", colid
, fcc
) == TCL_OK
12812 && Tcl_ListObjAppendElement(interp
, obj
, objfcc
) == TCL_OK
);
12816 /* * * * * * * * * * * * * Start of Address Management Routines * * * * * * * * * * * */
12820 * PEAddressCmd - export various bits of address book/directory access
12823 PEAddressCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
12827 dprint((2, "PEAddressCmd"));
12830 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
12833 else if(!wps_global
){
12834 Tcl_SetResult(interp
, "PEAddress: no open folder", TCL_STATIC
);
12837 else if((op
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
12839 if(!strcmp(op
, "safecheck")){
12840 if(peInitAddrbooks(interp
, 1) != TCL_OK
)
12844 else if(!strcmp(op
, "books")){
12848 * return the list of configured address books
12851 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
12854 for(i
= 0; i
< as
.n_addrbk
; i
++){
12857 objmv
[0] = Tcl_NewIntObj(i
);
12858 if(as
.adrbks
[i
].abnick
){
12859 objmv
[1] = Tcl_NewStringObj(as
.adrbks
[i
].abnick
, -1);
12864 snprintf(buf
, sizeof(buf
), "Address book number %d", i
+ 1);
12865 objmv
[1] = Tcl_NewStringObj(buf
, -1);
12868 objmv
[2] = Tcl_NewStringObj(as
.adrbks
[i
].filename
? as
.adrbks
[i
].filename
: "", -1);
12870 objmv
[3] = Tcl_NewIntObj(as
.adrbks
[i
].access
== ReadWrite
);
12872 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
12873 Tcl_NewListObj(4, objmv
));
12879 else if(objc
== 3){
12880 if(!strcmp(op
, "parselist")){
12882 ADDRESS
*addrlist
= NULL
, *atmp
, *anextp
;
12883 static char *fakedomain
= "@";
12885 if((addrstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
)
12886 addrstr
= cpystr(addrstr
); /* can't munge tcl copy */
12888 wps_global
->c_client_error
[0] = '\0';
12889 rfc822_parse_adrlist(&addrlist
, addrstr
,
12890 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, wps_global
))
12891 ? fakedomain
: wps_global
->maildomain
);
12893 fs_give((void **) &addrstr
);
12894 if(wps_global
->c_client_error
[0]){
12895 Tcl_SetResult(interp
, wps_global
->c_client_error
, TCL_STATIC
);
12899 for(atmp
= addrlist
; atmp
; ){
12902 anextp
= atmp
->next
;
12904 wtmp_20k_buf
[0] = '\0';
12905 rbuf
.f
= dummy_soutr
;
12907 rbuf
.beg
= wtmp_20k_buf
;
12908 rbuf
.cur
= wtmp_20k_buf
;
12909 rbuf
.end
= wtmp_20k_buf
+SIZEOF_20KBUF
-1;
12910 rfc822_output_address_list(&rbuf
, atmp
, 0L, NULL
);
12912 Tcl_ListObjAppendElement(interp
,
12913 Tcl_GetObjResult(interp
),
12914 Tcl_NewStringObj(wtmp_20k_buf
, -1));
12918 mail_free_address(&addrlist
);
12921 else if(!strcmp(op
, "xlookup")){
12923 ADDRESS
*addrlist
= NULL
, *atmp
, *anextp
;
12924 static char *fakedomain
= "@";
12926 if((addrstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
)
12927 addrstr
= cpystr(addrstr
); /* can't munge tcl copy */
12929 wps_global
->c_client_error
[0] = '\0';
12930 rfc822_parse_adrlist(&addrlist
, addrstr
,
12931 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, wps_global
))
12932 ? fakedomain
: wps_global
->maildomain
);
12934 fs_give((void **) &addrstr
);
12935 if(wps_global
->c_client_error
[0]){
12936 Tcl_SetResult(interp
, wps_global
->c_client_error
, TCL_STATIC
);
12940 for(atmp
= addrlist
; atmp
; ){
12941 anextp
= atmp
->next
;
12943 wtmp_20k_buf
[0] = '\0';
12945 if(atmp
->host
[0] == '@'){
12946 /* leading ampersand means "missing-hostname" */
12951 rbuf
.f
= dummy_soutr
;
12953 rbuf
.beg
= wtmp_20k_buf
;
12954 rbuf
.cur
= wtmp_20k_buf
;
12955 rbuf
.end
= wtmp_20k_buf
+SIZEOF_20KBUF
-1;
12956 rfc822_output_address_list(&rbuf
, atmp
, 0L, NULL
);
12958 Tcl_ListObjAppendElement(interp
,
12959 Tcl_GetObjResult(interp
),
12960 Tcl_NewStringObj(wtmp_20k_buf
, -1));
12962 } /* else group syntax, move on */
12967 mail_free_address(&addrlist
);
12970 else if(!strcmp(op
, "format")){
12974 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
12980 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
)
12981 for(i
= 0; i
< as
.n_addrbk
; i
++)
12983 addrbook_new_disp_form(&as
.adrbks
[booknum
], wps_global
->VAR_ABOOK_FORMATS
, booknum
, NULL
);
12985 for(i
= 0; i
< NFIELDS
&& as
.adrbks
[booknum
].disp_form
[i
].type
!= Notused
; i
++){
12986 switch(as
.adrbks
[booknum
].disp_form
[i
].type
){
13010 objmv
[0] = Tcl_NewStringObj(s
, -1);
13011 objmv
[1] = Tcl_NewIntObj((100 * as
.adrbks
[booknum
].disp_form
[i
].width
) / wps_global
->ttyo
->screen_cols
);
13012 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13013 Tcl_NewListObj(2, objmv
));
13021 snprintf(buf
, sizeof(buf
), "PEAddress list: unknown address book number \"%d\"", booknum
);
13022 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13025 else if(!strcmp(op
, "list")){
13026 int i
, j
, k
, n
, booknum
;
13029 Tcl_Obj
*objev
[NFIELDS
+ 1], *objhv
[2];
13031 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13037 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
)
13038 for(i
= 0; i
< as
.n_addrbk
; i
++)
13040 addrbook_new_disp_form(&as
.adrbks
[booknum
], wps_global
->VAR_ABOOK_FORMATS
, booknum
, NULL
);
13043 (ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, i
));
13046 /* first member is type: Single, List or Lookup */
13054 default : /* not set!?! */
13061 objhv
[0] = Tcl_NewStringObj(ae
->nickname
, -1);
13062 objhv
[1] = Tcl_NewStringObj(s
, -1);
13063 objev
[n
= 0] = Tcl_NewListObj(2, objhv
);
13066 * set fields based on VAR_ABOOK_FORMATS
13069 for(j
= 0; j
< NFIELDS
&& as
.adrbks
[booknum
].disp_form
[j
].type
!= Notused
; j
++){
13070 switch(as
.adrbks
[booknum
].disp_form
[j
].type
){
13072 objev
[++n
] = Tcl_NewStringObj(ae
->nickname
, -1);
13075 objev
[++n
] = Tcl_NewStringObj(ae
->fullname
, -1);
13078 if(ae
->tag
== Single
){
13079 objev
[++n
] = Tcl_NewStringObj(ae
->addr
.addr
, -1);
13084 for(k
= 0; ae
->addr
.list
[k
]; k
++)
13087 objav
= (Tcl_Obj
**) fs_get(k
* sizeof(Tcl_Obj
*));
13088 for(k
= 0; ae
->addr
.list
[k
]; k
++)
13089 objav
[k
] = Tcl_NewStringObj(ae
->addr
.list
[k
], -1);
13091 objev
[++n
] = Tcl_NewListObj(k
, objav
);
13092 fs_give((void **) &objav
);
13096 objev
[++n
] = Tcl_NewStringObj(ae
->fcc
? ae
->fcc
: "", -1);
13099 objev
[++n
] = Tcl_NewStringObj(ae
->extra
? ae
->extra
: "", -1);
13107 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13108 Tcl_NewListObj(n
+ 1, objev
));
13114 snprintf(buf
, sizeof(buf
), "PEAddress list: unknown address book number \"%d\"", booknum
);
13115 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13119 else if(objc
== 4){
13120 if(!strcmp(op
, "verify")){
13122 * The object here is to check the following list of field values
13123 * to see that they are valid address list, expanding if necessary.
13124 * The first argument is the list of field values, with "to" being
13125 * first. The second arg is the current fcc value.
13127 * The return value is of the following form:
13129 * { {{errstr {{oldstr newstr {ldap-opts ...}} ...}} ...} newfcc}
13132 char *addrstr
, *newaddr
= NULL
, *error
= NULL
,
13133 *tstr1
, *tstr2
, *fcc
, *newfcc
= NULL
;
13135 int rv
, badadrs
, i
, numlistvals
,
13136 numldapqueries
= 0;
13137 Tcl_Obj
*resObj
= NULL
, *secObj
, *strObj
, *adrObj
, *res2Obj
;
13141 wpldap_global
->query_no
++;
13142 if(wpldap_global
->ldap_search_list
){
13143 wpldap_global
->ldap_search_list
=
13144 free_wpldapres(wpldap_global
->ldap_search_list
);
13147 tsl
= &(wpldap_global
->ldap_search_list
);
13148 #endif /* ENABLE_LDAP */
13150 if(Tcl_ListObjGetElements(interp
, objv
[2], &numlistvals
,
13151 &objVal
) == TCL_OK
){
13152 if((fcc
= Tcl_GetStringFromObj(objv
[3], NULL
)) == NULL
)
13154 res2Obj
= Tcl_NewListObj(0, NULL
);
13155 for(i
= 0; i
< numlistvals
; i
++){
13158 if((addrstr
= Tcl_GetStringFromObj(objVal
[i
], NULL
)) == NULL
)
13161 addrstr
= cpystr(addrstr
); /* can't munge tcl copy */
13163 toaddr
.arg
.str
= cpystr(addrstr
);
13164 l
= strlen(addrstr
);
13166 resObj
= Tcl_NewListObj(0, NULL
);
13167 secObj
= Tcl_NewListObj(0, NULL
);
13168 for(tstr1
= addrstr
; tstr1
; tstr1
= tstr2
){
13169 tstr2
= strqchr(tstr1
, ',', 0, -1);
13173 strncpy(toaddr
.arg
.str
, tstr1
, l
);
13174 toaddr
.arg
.str
[l
] = '\0';
13176 removing_leading_and_trailing_white_space(toaddr
.arg
.str
);
13177 if(*toaddr
.arg
.str
){
13178 if(i
== 0 && tstr1
== addrstr
)
13179 newfcc
= cpystr(fcc
);
13181 rv
= our_build_address(toaddr
, &newaddr
, &error
, &newfcc
, NULL
);
13184 strObj
= Tcl_NewListObj(0, NULL
);
13185 Tcl_ListObjAppendElement(interp
, strObj
,
13186 Tcl_NewStringObj(toaddr
.arg
.str
, -1));
13187 Tcl_ListObjAppendElement(interp
, strObj
,
13188 Tcl_NewStringObj(newaddr
,-1));
13189 /* append whether or not ldap stuff
13192 adrObj
= Tcl_NewListObj(0,NULL
);
13195 LDAP_CHOOSE_S
*tres
;
13196 LDAP_SERV_RES_S
*trl
;
13201 tres
= (LDAP_CHOOSE_S
*)fs_get(sizeof(LDAP_CHOOSE_S
));
13202 for(trl
= (*tsl
)->reslist
; trl
;
13204 for(e
= ldap_first_entry(trl
->ld
,
13207 e
= ldap_next_entry(trl
->ld
, e
)){
13208 tres
->ld
= trl
->ld
;
13209 tres
->selected_entry
= e
;
13210 tres
->info_used
= trl
->info_used
;
13211 tres
->serv
= trl
->serv
;
13212 if((newadr
= address_from_ldap(tres
)) != NULL
){
13213 if(newadr
->mailbox
&& newadr
->host
){
13217 len
= est_size(newadr
);
13218 ret_to
= (char *)fs_get(len
* sizeof(char));
13220 rbuf
.f
= dummy_soutr
;
13224 rbuf
.end
= ret_to
+len
-1;
13225 rfc822_output_address_list(&rbuf
, newadr
, 0L, NULL
);
13227 Tcl_ListObjAppendElement(interp
,
13228 adrObj
, Tcl_NewStringObj(ret_to
, -1));
13229 fs_give((void **)&ret_to
);
13231 mail_free_address(&newadr
);
13235 fs_give((void **)&tres
);
13237 tsl
= &((*tsl
)->next
);
13239 #endif /* ENABLE_LDAP */
13240 Tcl_ListObjAppendElement(interp
, strObj
, adrObj
);
13241 Tcl_ListObjAppendElement(interp
, secObj
, strObj
);
13253 resObj
= Tcl_NewListObj(0, NULL
);
13254 Tcl_ListObjAppendElement(interp
, resObj
,
13255 Tcl_NewStringObj(badadrs
13256 ? (error
? error
: "Unknown")
13258 Tcl_ListObjAppendElement(interp
, resObj
, secObj
);
13259 Tcl_ListObjAppendElement(interp
, res2Obj
, resObj
);
13260 fs_give((void **) &addrstr
);
13261 fs_give((void **) &toaddr
.arg
.str
);
13263 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), res2Obj
);
13264 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13265 Tcl_NewStringObj(newfcc
? newfcc
13266 : (fcc
? fcc
: ""), -1));
13267 if(newfcc
) fs_give((void **)&newfcc
);
13272 else if(!strcmp(op
, "expand")){
13274 char *addrstr
, *newaddr
= NULL
, *error
= NULL
, *fcc
, *newfcc
= NULL
;
13278 * Return value will be of the form:
13280 * ldap-query-number,
13284 * ldap-query-number will be nonzero if
13285 * there is something interesting to display as a result
13286 * of an ldap query.
13290 * Given what looks like an rfc822 address line, parse the
13291 * contents and expand any tokens that look like they ought
13295 if((addrstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
13297 toaddr
.arg
.str
= cpystr(addrstr
); /* can't munge tcl copy */
13298 fcc
= Tcl_GetStringFromObj(objv
[3], NULL
);
13300 wpldap_global
->query_no
++;
13301 if(wpldap_global
->ldap_search_list
){
13302 wpldap_global
->ldap_search_list
=
13303 free_wpldapres(wpldap_global
->ldap_search_list
);
13305 #endif /* ENABLE_LDAP */
13306 newfcc
= cpystr(fcc
);
13307 rv
= our_build_address(toaddr
, &newaddr
, &error
, &newfcc
, NULL
);
13308 fs_give((void **) &toaddr
.arg
.str
);
13312 * c-client quotes results with spaces in them, so we'll go
13313 * through and unquote them.
13315 if(wpldap_global
->ldap_search_list
){
13317 char *tstr1
, *tstr2
;
13318 char *qstr1
, *newnewaddr
;
13321 for(tres
= wpldap_global
->ldap_search_list
;
13322 tres
; tres
= tres
->next
){
13323 if(strqchr(tres
->str
, ' ', 0, -1)){
13324 qstr1len
= strlen(tres
->str
) + 3;
13325 qstr1
= (char *)fs_get(qstr1len
*sizeof(char));
13326 snprintf(qstr1
, qstr1len
, "\"%.*s\"", qstr1len
, tres
->str
);
13327 for(tstr1
= newaddr
; tstr1
; tstr1
= tstr2
){
13328 tstr2
= strqchr(tstr1
, ',', 0, -1);
13329 if(strncmp(qstr1
, tstr1
, tstr2
? tstr2
- tstr1
13330 : strlen(tstr1
)) == 0){
13332 l
= strlen(newaddr
) + strlen(tres
->str
) + 2
13333 + (tstr2
? strlen(tstr2
) : 0);
13334 newnewaddr
= (char *) fs_get(l
* sizeof(char));
13335 snprintf(newnewaddr
, l
, "%.*s%s%s", (int) (tstr1
- newaddr
),
13336 newaddr
, tres
->str
, tstr2
? tstr2
: "");
13337 fs_give((void **)&newaddr
);
13338 newaddr
= newnewaddr
;
13343 if(tstr2
&& *tstr2
== ' ')
13347 fs_give((void **) &qstr1
);
13351 #endif /* ENABLE_LDAP */
13352 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13353 Tcl_NewStringObj(newaddr
, -1)) != TCL_OK
)
13356 if(wpldap_global
->ldap_search_list
){
13357 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13358 Tcl_NewIntObj(wpldap_global
->query_no
)) != TCL_OK
)
13362 #endif /* ENABLE_LDAP */
13363 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13364 Tcl_NewIntObj(0)) != TCL_OK
)
13366 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13367 Tcl_NewStringObj(newfcc
? newfcc
13368 : (fcc
? fcc
: ""), -1)) != TCL_OK
)
13370 if(newfcc
) fs_give((void **)&newfcc
);
13375 Tcl_SetResult(interp
, error
? error
: "Indeterminate error", TCL_VOLATILE
);
13376 if(newfcc
) fs_give((void **)&newfcc
);
13381 else if(!strcmp(op
, "complete")){
13383 * CMD: complete uid
13385 * Look for possible completions for
13386 * given query_string.
13388 * ARGS: <query_string> <uid>
13390 * Returns: candidate list: {nickname {personal mailbox}}
13392 char *query
, *errstr
;
13394 COMPLETE_S
*completions
, *cp
;
13396 if(peInitAddrbooks(interp
, 0) == TCL_OK
){
13397 if((query
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
13398 if(Tcl_GetLongFromObj(interp
, objv
[3], &uid
) == TCL_OK
){
13400 completions
= adrbk_list_of_completions(query
,
13401 wps_global
->mail_stream
,
13404 ((strlen(query
) >= 5) ? ALC_INCLUDE_LDAP
: 0) |
13405 #endif /* ENABLE_LDAP */
13409 for(cp
= completions
; cp
; cp
= cp
->next
)
13410 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s %s %s",
13411 cp
->nickname
? cp
->nickname
: "",
13412 cp
->full_address
? cp
->full_address
: "",
13413 cp
->fcc
? cp
->fcc
: "");
13415 free_complete_s(&completions
);
13418 Tcl_SetResult(interp
, "", TCL_STATIC
);
13423 errstr
= "PEAddress: Cannot read UID";
13426 errstr
= "PEAddress: Cannot get completion query";
13429 errstr
= "PEAddress: Address Book initialization failed";
13431 Tcl_SetResult(interp
, errstr
, TCL_STATIC
);
13435 else if(objc
== 5){
13436 if(!strcmp(op
, "entry")){
13437 int booknum
, i
, aindex
;
13438 char *nick
, *astr
= NULL
, *errstr
= NULL
, *fccstr
= NULL
, buf
[128];
13442 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13446 * Given an address book handle and nickname, return address
13448 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
)
13449 for(i
= 0; i
< as
.n_addrbk
; i
++)
13451 if((nick
= Tcl_GetStringFromObj(objv
[3], NULL
)) == NULL
){
13452 Tcl_SetResult(interp
, "PEAddress list: Can't get nickname", TCL_STATIC
);
13455 if(Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
13456 || (*nick
== '\0' && aindex
< 0)){
13457 Tcl_SetResult(interp
, "PEAddress list: Can't get aindex", TCL_STATIC
);
13461 ? (ae
= adrbk_lookup_by_nick(as
.adrbks
[booknum
].address_book
, nick
, NULL
))
13462 : (ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, aindex
))){
13464 bldto
.arg
.abe
= ae
;
13466 (void) our_build_address(bldto
, &astr
, &errstr
, &fccstr
, NULL
);
13470 fs_give((void **) &astr
);
13472 Tcl_SetResult(interp
, errstr
, TCL_VOLATILE
);
13480 l
= (4*strlen(astr
) + 1) * sizeof(char);
13481 p
= (char *) fs_get(l
);
13482 if(rfc1522_decode_to_utf8((unsigned char *) p
, l
, astr
) == (unsigned char *) p
){
13483 fs_give((void **) &astr
);
13487 fs_give((void **)&p
);
13492 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13493 Tcl_NewStringObj(astr
, -1));
13494 fs_give((void **) &astr
);
13497 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13498 Tcl_NewStringObj(*fccstr
? fccstr
: "\"\"", -1));
13499 fs_give((void **) &fccstr
);
13502 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13503 Tcl_NewStringObj("", -1));
13506 Tcl_SetResult(interp
, "", TCL_STATIC
);
13511 snprintf(buf
, sizeof(buf
), "PEAddress list: unknown address book ID %d", booknum
);
13512 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13515 else if(!strcmp(op
, "fullentry")){
13516 int booknum
, j
, aindex
;
13521 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13525 * Given an address book handle and nickname, return
13526 * nickname, fullname, address(es), fcc, and comments
13528 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
){
13529 if(booknum
>= 0 && booknum
< as
.n_addrbk
){
13530 if((nick
= Tcl_GetStringFromObj(objv
[3], NULL
)) == NULL
)
13532 if(Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
13533 || (*nick
== '\0' && aindex
< 0))
13536 ? (ae
= adrbk_lookup_by_nick(as
.adrbks
[booknum
].address_book
, nick
, NULL
))
13537 : (ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, aindex
))){
13538 Tcl_ListObjAppendElement(interp
,
13539 Tcl_GetObjResult(interp
),
13540 Tcl_NewStringObj(ae
->nickname
? ae
->nickname
: "", -1));
13541 Tcl_ListObjAppendElement(interp
,
13542 Tcl_GetObjResult(interp
),
13543 Tcl_NewStringObj(ae
->fullname
? ae
->fullname
: "", -1));
13544 resObj
= Tcl_NewListObj(0,NULL
);
13545 if(ae
->tag
== Single
)
13546 Tcl_ListObjAppendElement(interp
,
13548 Tcl_NewStringObj(ae
->addr
.addr
? ae
->addr
.addr
: "", -1));
13550 for(j
= 0; ae
->addr
.list
[j
]; j
++)
13551 Tcl_ListObjAppendElement(interp
, resObj
,
13552 Tcl_NewStringObj(ae
->addr
.list
[j
] ? ae
->addr
.list
[j
] : "", -1));
13554 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), resObj
);
13555 Tcl_ListObjAppendElement(interp
,
13556 Tcl_GetObjResult(interp
),
13557 Tcl_NewStringObj(ae
->fcc
? ae
->fcc
: "", -1));
13558 Tcl_ListObjAppendElement(interp
,
13559 Tcl_GetObjResult(interp
),
13560 Tcl_NewStringObj(ae
->extra
? ae
->extra
: "", -1));
13567 else if(!strcmp(op
, "delete")){
13568 char *nick
, buf
[256];
13569 int booknum
, aindex
;
13570 adrbk_cntr_t old_entry
;
13572 if(peInitAddrbooks(interp
, 0) != TCL_OK
){
13573 snprintf(buf
, sizeof(buf
), "PEAddress delete: couldn't init addressbooks");
13574 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13577 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
){
13578 nick
= Tcl_GetStringFromObj(objv
[3], NULL
);
13579 removing_leading_and_trailing_white_space(nick
);
13583 if(booknum
>= 0 && booknum
< as
.n_addrbk
) {
13584 if(as
.adrbks
[booknum
].access
!= ReadWrite
) return TCL_ERROR
;
13585 ab
= as
.adrbks
[booknum
].address_book
;
13588 snprintf(buf
, sizeof(buf
), "PEAddress delete: Book number out of range");
13589 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13592 if((Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
)
13593 || (*nick
== '\0' && aindex
< 0))
13595 adrbk_check_validity(ab
, 1L);
13596 if(ab
->flags
& FILE_OUTOFDATE
||
13597 (ab
->rd
&& ab
->rd
->flags
& REM_OUTOFDATE
)){
13598 Tcl_SetResult(interp
,
13599 "Address book out of sync. Cannot update at this moment",
13604 snprintf(buf
, sizeof(buf
), "PEAddress delete: No nickname");
13605 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13609 ? (!adrbk_lookup_by_nick(ab
, nick
, &old_entry
))
13610 : ((old_entry
= (adrbk_cntr_t
)aindex
) == -1)){
13611 snprintf(buf
, sizeof(buf
), "PEAddress delete: Nickname \"%.128s\" not found", nick
);
13612 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13615 if(adrbk_delete(ab
, old_entry
, 0, 0, 1, 1)){
13616 snprintf(buf
, sizeof(buf
), "PEAddress delete: Couldn't delete addressbook entry");
13617 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13623 else if((objc
== 10 || objc
== 11) && !strcmp(op
, "edit")){
13624 if(!strcmp(op
, "edit")){
13625 int booknum
, adri
, add
, rv
, aindex
;
13626 char *nick
, *fn
, *fcc
, *comment
, *addrfield
,
13627 buf
[256], **addrs
, *orignick
= NULL
;
13628 AdrBk_Entry
*ae
= NULL
;
13630 adrbk_cntr_t old_entry
= NO_NEXT
, new_entry
;
13632 ADDRESS
*adr
= NULL
;
13635 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13637 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
){
13638 if(as
.adrbks
[booknum
].access
!= ReadWrite
) return TCL_ERROR
;
13639 nick
= Tcl_GetStringFromObj(objv
[3], NULL
);
13640 removing_leading_and_trailing_white_space(nick
);
13641 if(Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
){
13642 Tcl_SetResult(interp
, "No Address Handle", TCL_VOLATILE
);
13645 fn
= Tcl_GetStringFromObj(objv
[5], NULL
);
13646 removing_leading_and_trailing_white_space(fn
);
13647 if(!*fn
) fn
= NULL
;
13648 addrfield
= Tcl_GetStringFromObj(objv
[6], NULL
);
13649 removing_leading_and_trailing_white_space(addrfield
);
13650 if(!*addrfield
) addrfield
= NULL
;
13652 if(Tcl_ListObjGetElements(interp, objv[7], &numlistvals, &objVal) != TCL_OK)
13655 fcc
= Tcl_GetStringFromObj(objv
[7], NULL
);
13656 removing_leading_and_trailing_white_space(fcc
);
13657 if(!*fcc
) fcc
= NULL
;
13658 comment
= Tcl_GetStringFromObj(objv
[8], NULL
);
13659 removing_leading_and_trailing_white_space(comment
);
13660 if(!*comment
) comment
= NULL
;
13661 if(Tcl_GetIntFromObj(interp
, objv
[9], &add
) != TCL_OK
)
13665 * if objc == 11 then that means that they changed the
13666 * value of nick to something else, and this one is the
13669 orignick
= Tcl_GetStringFromObj(objv
[10], NULL
);
13670 removing_leading_and_trailing_white_space(orignick
);
13672 if((addrs
= parse_addrlist(addrfield
)) != NULL
){
13673 int tbuflen
= strlen(addrfield
);
13675 if(!(tbuf
= (char *) fs_get(sizeof(char) * (tbuflen
+128)))){
13676 Tcl_SetResult(interp
, "malloc error", TCL_VOLATILE
);
13677 fs_give((void **) &addrs
);
13680 for(adri
= 0; addrs
[adri
]; adri
++){
13681 if(*(addrs
[adri
])){
13682 wps_global
->c_client_error
[0] = '\0';
13683 strncpy(tbuf
, addrs
[adri
], tbuflen
+128);
13684 tbuf
[tbuflen
+128-1] = '\0';
13685 rfc822_parse_adrlist(&adr
, tbuf
, "@");
13686 if(adr
) mail_free_address(&adr
);
13688 if(wps_global
->c_client_error
[0]){
13689 snprintf(buf
, sizeof(buf
),"Problem with address %.10s%s: %s",
13690 addrs
[adri
], strlen(addrs
[adri
]) > 10 ?
13691 "..." : "", wps_global
->c_client_error
);
13692 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13694 fs_give((void **) &tbuf
);
13695 fs_give((void **) &addrs
);
13700 if(tbuf
) fs_give((void **)&tbuf
);
13704 /* addrs[adri] = NULL; */
13706 if(adri
> 1) tag
= List
;
13709 if(booknum
>= 0 && booknum
< as
.n_addrbk
) {
13710 ab
= as
.adrbks
[booknum
].address_book
;
13714 fs_give((void **) &addrs
);
13717 adrbk_check_validity(ab
, 1L);
13718 if(ab
->flags
& FILE_OUTOFDATE
||
13719 (ab
->rd
&& ab
->rd
->flags
& REM_OUTOFDATE
)){
13720 Tcl_SetResult(interp
,
13721 "Address book out of sync. Cannot update at this moment",
13726 ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, aindex
);
13728 old_entry
= (adrbk_cntr_t
) aindex
;
13731 Tcl_SetResult(interp
, "No Address Handle!", TCL_VOLATILE
);
13735 else if(nick
&& *nick
&& adrbk_lookup_by_nick(ab
, nick
, NULL
)){
13736 snprintf(buf
, sizeof(buf
), "Entry with nickname %.128s already exists.",
13738 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13740 fs_give((void **) &addrs
);
13744 ((tag
== List
&& ae
->tag
== Single
) ||
13745 (tag
== Single
&& ae
->tag
== List
))){
13746 if(adrbk_delete(ab
, old_entry
, 0,0,1,0)){
13747 snprintf(buf
, sizeof(buf
), "Problem updating from %s to %s.",
13748 ae
->tag
== Single
? "Single" : "List",
13749 tag
== List
? "List" : "Single");
13750 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13752 fs_give((void **) &addrs
);
13755 old_entry
= NO_NEXT
;
13757 if((rv
= adrbk_add(ab
, old_entry
,
13760 tag
== List
? (char *)addrs
:
13761 (addrs
&& *addrs
) ? *addrs
: "",
13763 comment
? comment
: "",
13764 tag
, &new_entry
, NULL
, 0, 1,
13765 tag
== List
? 0 : 1)) != 0){
13766 snprintf(buf
, sizeof(buf
), "Couldn't add entry! rv=%d.", rv
);
13767 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13769 fs_give((void **) &addrs
);
13773 adrbk_listdel_all(ab
, new_entry
);
13774 adrbk_nlistadd(ab
, new_entry
, NULL
, NULL
, addrs
, 0, 1, 1);
13778 snprintf(buf
, sizeof(buf
), "Unknown address book ID %d", booknum
);
13779 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13785 Tcl_SetResult(interp
, "PEAddress: unrecognized command", TCL_STATIC
);
13791 peInitAddrbooks(Tcl_Interp
*interp
, int safe
)
13793 if(wps_global
->remote_abook_validity
> 0)
13794 (void)adrbk_check_and_fix_all(safe
, 0, 0);
13796 if(!init_addrbooks(NoDisplay
, 1, 1, 0)){
13797 Tcl_SetResult(interp
, "No Address Book Configured", TCL_STATIC
);
13807 peRuleStatVal(char *str
, int *n
)
13812 if(!strcmp(str
, "either"))
13813 *n
= PAT_STAT_EITHER
;
13814 else if(!strcmp(str
, "yes"))
13816 else if(!strcmp(str
, "no"))
13825 #define RS_RULE_EDIT 0x0001
13826 #define RS_RULE_ADD 0x0002
13827 #define RS_RULE_DELETE 0x0004
13828 #define RS_RULE_SHUFFUP 0x0008
13829 #define RS_RULE_SHUFFDOWN 0x0010
13830 #define RS_RULE_GETPAT 0x0100
13831 #define RS_RULE_FINDPAT 0x0200
13834 peRuleSet(Tcl_Interp
*interp
, Tcl_Obj
**objv
)
13836 char *rule
, *patvar
, *patval
, *actvar
, *actval
, *tstr
, *ruleaction
;
13837 int rno
, nPat
, nPatEmnt
, nAct
, nActEmnt
, i
, rv
= 0;
13838 Tcl_Obj
**objPat
, **objPatEmnt
, **objAct
, **objActEmnt
;
13839 long rflags
= PAT_USE_CHANGED
, aflags
= 0;
13841 PAT_S
*pat
, *new_pat
;
13843 if(!(rule
= Tcl_GetStringFromObj(objv
[0], NULL
)))
13846 if(!(ruleaction
= Tcl_GetStringFromObj(objv
[1], NULL
)))
13849 if(Tcl_GetIntFromObj(interp
, objv
[2], &rno
) == TCL_ERROR
)
13852 if(!(strcmp(rule
, "filter")))
13853 rflags
|= ROLE_DO_FILTER
;
13854 else if(!(strcmp(rule
, "score")))
13855 rflags
|= ROLE_DO_SCORES
;
13856 else if(!(strcmp(rule
, "indexcolor")))
13857 rflags
|= ROLE_DO_INCOLS
;
13861 if(!(strcmp(ruleaction
, "edit"))){
13862 aflags
|= RS_RULE_EDIT
;
13863 aflags
|= RS_RULE_GETPAT
;
13864 aflags
|= RS_RULE_FINDPAT
;
13866 else if(!(strcmp(ruleaction
, "add"))){
13867 aflags
|= RS_RULE_ADD
;
13868 aflags
|= RS_RULE_GETPAT
;
13870 else if(!(strcmp(ruleaction
, "delete"))){
13871 aflags
|= RS_RULE_DELETE
;
13872 aflags
|= RS_RULE_FINDPAT
;
13874 else if(!(strcmp(ruleaction
, "shuffup"))){
13875 aflags
|= RS_RULE_SHUFFUP
;
13876 aflags
|= RS_RULE_FINDPAT
;
13878 else if(!(strcmp(ruleaction
, "shuffdown"))){
13879 aflags
|= RS_RULE_SHUFFDOWN
;
13880 aflags
|= RS_RULE_FINDPAT
;
13882 else return(TCL_ERROR
);
13884 if(aflags
& RS_RULE_FINDPAT
){
13885 if(any_patterns(rflags
, &pstate
)){
13886 for(pat
= first_pattern(&pstate
), i
= 0;
13888 pat
= next_pattern(&pstate
), i
++);
13889 if(i
!= rno
) return(TCL_ERROR
);
13892 if(aflags
& RS_RULE_GETPAT
){
13895 Tcl_ListObjGetElements(interp
, objv
[3], &nPat
, &objPat
);
13896 Tcl_ListObjGetElements(interp
, objv
[4], &nAct
, &objAct
);
13898 new_pat
= (PAT_S
*)fs_get(sizeof(PAT_S
));
13899 memset(new_pat
, 0, sizeof(PAT_S
));
13900 new_pat
->patgrp
= (PATGRP_S
*)fs_get(sizeof(PATGRP_S
));
13901 memset(new_pat
->patgrp
, 0, sizeof(PATGRP_S
));
13902 new_pat
->action
= (ACTION_S
*)fs_get(sizeof(ACTION_S
));
13903 memset(new_pat
->action
, 0, sizeof(ACTION_S
));
13905 /* Set up the pattern group */
13906 for(i
= 0; i
< nPat
; i
++){
13907 Tcl_ListObjGetElements(interp
, objPat
[i
], &nPatEmnt
, &objPatEmnt
);
13908 if(nPatEmnt
!= 2) return(TCL_ERROR
);
13909 patvar
= Tcl_GetStringFromObj(objPatEmnt
[0], NULL
);
13910 patval
= Tcl_GetStringFromObj(objPatEmnt
[1], NULL
);
13911 if(!patvar
|| !patval
) return(TCL_ERROR
);
13915 tstr
= cpystr(patval
);
13916 removing_leading_and_trailing_white_space(tstr
);
13918 fs_give((void **) &tstr
);
13921 if(!(strcmp(patvar
, "nickname"))){
13922 new_pat
->patgrp
->nick
= tstr
;
13925 else if(!(strcmp(patvar
, "comment"))){
13926 new_pat
->patgrp
->comment
= tstr
;
13929 else if(!(strcmp(patvar
, "to"))){
13930 new_pat
->patgrp
->to
= string_to_pattern(tstr
);
13932 else if(!(strcmp(patvar
, "from"))){
13933 new_pat
->patgrp
->from
= string_to_pattern(tstr
);
13935 else if(!(strcmp(patvar
, "sender"))){
13936 new_pat
->patgrp
->sender
= string_to_pattern(tstr
);
13938 else if(!(strcmp(patvar
, "cc"))){
13939 new_pat
->patgrp
->cc
= string_to_pattern(tstr
);
13941 else if(!(strcmp(patvar
, "recip"))){
13942 new_pat
->patgrp
->recip
= string_to_pattern(tstr
);
13944 else if(!(strcmp(patvar
, "partic"))){
13945 new_pat
->patgrp
->partic
= string_to_pattern(tstr
);
13947 else if(!(strcmp(patvar
, "news"))){
13948 new_pat
->patgrp
->news
= string_to_pattern(tstr
);
13950 else if(!(strcmp(patvar
, "subj"))){
13951 new_pat
->patgrp
->subj
= string_to_pattern(tstr
);
13953 else if(!(strcmp(patvar
, "bodytext"))){
13954 new_pat
->patgrp
->bodytext
= string_to_pattern(tstr
);
13956 else if(!(strcmp(patvar
, "alltext"))){
13957 new_pat
->patgrp
->alltext
= string_to_pattern(tstr
);
13959 else if(!(strcmp(patvar
, "keyword"))){
13960 new_pat
->patgrp
->keyword
= string_to_pattern(tstr
);
13962 else if(!(strcmp(patvar
, "charset"))){
13963 new_pat
->patgrp
->charsets
= string_to_pattern(tstr
);
13965 else if(!(strcmp(patvar
, "ftype"))){
13966 if(!tstr
) return(TCL_ERROR
);
13968 if(!(strcmp(tstr
, "any")))
13969 new_pat
->patgrp
->fldr_type
= FLDR_ANY
;
13970 else if(!(strcmp(tstr
, "news")))
13971 new_pat
->patgrp
->fldr_type
= FLDR_NEWS
;
13972 else if(!(strcmp(tstr
, "email")))
13973 new_pat
->patgrp
->fldr_type
= FLDR_EMAIL
;
13974 else if(!(strcmp(tstr
, "specific")))
13975 new_pat
->patgrp
->fldr_type
= FLDR_SPECIFIC
;
13977 free_pat(&new_pat
);
13981 else if(!(strcmp(patvar
, "folder"))){
13982 new_pat
->patgrp
->folder
= string_to_pattern(tstr
);
13984 else if(!(strcmp(patvar
, "stat_new"))){
13985 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_new
)){
13986 free_pat(&new_pat
);
13990 else if(!(strcmp(patvar
, "stat_rec"))){
13991 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_rec
)){
13992 free_pat(&new_pat
);
13996 else if(!(strcmp(patvar
, "stat_del"))){
13997 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_del
)){
13998 free_pat(&new_pat
);
14002 else if(!(strcmp(patvar
, "stat_imp"))){
14003 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_imp
)){
14004 free_pat(&new_pat
);
14008 else if(!(strcmp(patvar
, "stat_ans"))){
14009 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_ans
)){
14010 free_pat(&new_pat
);
14014 else if(!(strcmp(patvar
, "stat_8bitsubj"))){
14015 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_8bitsubj
)){
14016 free_pat(&new_pat
);
14020 else if(!(strcmp(patvar
, "stat_bom"))){
14021 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_bom
)){
14022 free_pat(&new_pat
);
14026 else if(!(strcmp(patvar
, "stat_boy"))){
14027 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_boy
)){
14028 free_pat(&new_pat
);
14032 else if(!(strcmp(patvar
, "age"))){
14033 new_pat
->patgrp
->age
= parse_intvl(tstr
);
14035 else if(!(strcmp(patvar
, "size"))){
14036 new_pat
->patgrp
->size
= parse_intvl(tstr
);
14038 else if(!(strcmp(patvar
, "score"))){
14039 new_pat
->patgrp
->score
= parse_intvl(tstr
);
14041 else if(!(strcmp(patvar
, "addrbook"))){
14043 if(!strcmp(tstr
, "either"))
14044 new_pat
->patgrp
->inabook
= IAB_EITHER
;
14045 else if(!strcmp(tstr
, "yes"))
14046 new_pat
->patgrp
->inabook
= IAB_YES
;
14047 else if(!strcmp(tstr
, "no"))
14048 new_pat
->patgrp
->inabook
= IAB_NO
;
14049 else if(!strcmp(tstr
, "yesspecific"))
14050 new_pat
->patgrp
->inabook
= IAB_SPEC_YES
;
14051 else if(!strcmp(tstr
, "nospecific"))
14052 new_pat
->patgrp
->inabook
= IAB_SPEC_NO
;
14060 free_pat(&new_pat
);
14062 else if(!(strcmp(patvar
, "specificabook"))){
14063 new_pat
->patgrp
->abooks
= string_to_pattern(tstr
);
14065 else if(!(strcmp(patvar
, "headers"))){
14067 int nHdrList
, nHdrPair
, n
;
14068 Tcl_Obj
**objHdrList
, **objHdrPair
;
14070 Tcl_ListObjGetElements(interp
, objPatEmnt
[1], &nHdrList
, &objHdrList
);
14072 for(ahp
= &new_pat
->patgrp
->arbhdr
; *ahp
; ahp
= &(*ahp
)->next
)
14075 for (n
= 0; n
< nHdrList
; n
++){
14079 Tcl_ListObjGetElements(interp
, objHdrList
[n
], &nHdrPair
, &objHdrPair
);
14083 hdrfld
= Tcl_GetStringFromObj(objHdrPair
[0], NULL
);
14084 hdrval
= Tcl_GetStringFromObj(objHdrPair
[1], NULL
);
14087 *ahp
= (ARBHDR_S
*) fs_get(sizeof(ARBHDR_S
));
14088 memset(*ahp
, 0, sizeof(ARBHDR_S
));
14090 (*ahp
)->field
= cpystr(hdrfld
);
14092 (*ahp
)->p
= string_to_pattern(hdrval
);
14095 (*ahp
)->isemptyval
= 1;
14097 ahp
= &(*ahp
)->next
;
14102 free_pat(&new_pat
);
14107 fs_give((void **) &tstr
);
14113 if((new_pat
->patgrp
->inabook
& (IAB_SPEC_YES
| IAB_SPEC_NO
)) == 0
14114 && new_pat
->patgrp
->abooks
)
14115 free_pattern(&new_pat
->patgrp
->abooks
);
14117 if(new_pat
->patgrp
->fldr_type
!= FLDR_SPECIFIC
&& new_pat
->patgrp
->folder
)
14118 free_pattern(&new_pat
->patgrp
->folder
);
14120 /* set up the action */
14121 if(!(strcmp(rule
, "filter")))
14122 new_pat
->action
->is_a_filter
= 1;
14123 else if(!(strcmp(rule
, "role")))
14124 new_pat
->action
->is_a_role
= 1;
14125 else if(!(strcmp(rule
, "score")))
14126 new_pat
->action
->is_a_score
= 1;
14127 else if(!(strcmp(rule
, "indexcolor")))
14128 new_pat
->action
->is_a_incol
= 1;
14130 free_pat(&new_pat
);
14134 for(i
= 0; i
< nAct
; i
++){
14135 Tcl_ListObjGetElements(interp
, objAct
[i
], &nActEmnt
, &objActEmnt
);
14137 free_pat(&new_pat
);
14141 actvar
= Tcl_GetStringFromObj(objActEmnt
[0], NULL
);
14142 actval
= Tcl_GetStringFromObj(objActEmnt
[1], NULL
);
14143 if(!actvar
|| !actval
){
14144 free_pat(&new_pat
);
14148 if(new_pat
->action
->is_a_filter
&& !(strcmp(actvar
, "action"))){
14149 if(!strcmp(actval
, "delete"))
14150 new_pat
->action
->kill
= 1;
14151 else if(!strcmp(actval
, "move"))
14152 new_pat
->action
->kill
= 0;
14154 free_pat(&new_pat
);
14158 else if(new_pat
->action
->is_a_filter
&& !(strcmp(actvar
, "folder"))){
14159 tstr
= cpystr(actval
);
14160 removing_leading_and_trailing_white_space(tstr
);
14161 if(!(*tstr
)) fs_give((void **)&tstr
);
14162 new_pat
->action
->folder
= string_to_pattern(tstr
);
14163 if(tstr
) fs_give((void **)&tstr
);
14165 else if(new_pat
->action
->is_a_filter
&& !(strcmp(actvar
, "moind"))){
14166 if(!strcmp(actval
, "1"))
14167 new_pat
->action
->move_only_if_not_deleted
= 1;
14168 else if(!strcmp(actval
, "0"))
14169 new_pat
->action
->move_only_if_not_deleted
= 0;
14171 free_pat(&new_pat
);
14175 else if(new_pat
->action
->is_a_incol
&& !(strcmp(actvar
, "fg"))){
14176 char asciicolor
[256];
14178 if(ascii_colorstr(asciicolor
, actval
) == 0) {
14179 if(!new_pat
->action
->incol
){
14180 new_pat
->action
->incol
= new_color_pair(asciicolor
,NULL
);
14183 snprintf(new_pat
->action
->incol
->fg
,
14184 sizeof(new_pat
->action
->incol
->fg
), "%s", asciicolor
);
14187 else if(new_pat
->action
->is_a_incol
&& !(strcmp(actvar
, "bg"))){
14188 char asciicolor
[256];
14190 if(ascii_colorstr(asciicolor
, actval
) == 0) {
14191 if(!new_pat
->action
->incol
){
14192 new_pat
->action
->incol
= new_color_pair(NULL
, asciicolor
);
14195 snprintf(new_pat
->action
->incol
->bg
,
14196 sizeof(new_pat
->action
->incol
->bg
), "%s", asciicolor
);
14199 else if(new_pat
->action
->is_a_score
&& !(strcmp(actvar
, "scoreval"))){
14200 long scoreval
= (long) atoi(actval
);
14202 if(scoreval
>= SCORE_MIN
&& scoreval
<= SCORE_MAX
)
14203 new_pat
->action
->scoreval
= scoreval
;
14205 else if(new_pat
->action
->is_a_score
&& !(strcmp(actvar
, "scorehdr"))){
14206 HEADER_TOK_S
*hdrtok
;
14208 if((hdrtok
= stringform_to_hdrtok(actval
)) != NULL
)
14209 new_pat
->action
->scorevalhdrtok
= hdrtok
;
14212 free_pat(&new_pat
);
14217 if(new_pat
->action
->is_a_filter
&& new_pat
->action
->kill
&& new_pat
->action
->folder
)
14218 fs_give((void **)&new_pat
->action
->folder
);
14219 else if(new_pat
->action
->is_a_filter
&& new_pat
->action
->kill
== 0 && new_pat
->action
->folder
== 0){
14220 free_pat(&new_pat
);
14221 Tcl_SetResult(interp
, "No folder set for Move", TCL_VOLATILE
);
14226 if(aflags
& RS_RULE_EDIT
)
14227 rv
= edit_pattern(new_pat
, rno
, rflags
);
14228 else if(aflags
& RS_RULE_ADD
)
14229 rv
= add_pattern(new_pat
, rflags
);
14230 else if(aflags
& RS_RULE_DELETE
)
14231 rv
= delete_pattern(rno
, rflags
);
14232 else if(aflags
& RS_RULE_SHUFFUP
)
14233 rv
= shuffle_pattern(rno
, 1, rflags
);
14234 else if(aflags
& RS_RULE_SHUFFDOWN
)
14235 rv
= shuffle_pattern(rno
, -1, rflags
);
14239 return(rv
? TCL_ERROR
: TCL_OK
);
14245 peAEToAddress(AdrBk_Entry
*ae
)
14247 char *list
, *l1
, *l2
;
14250 ADDRESS
*addr
= NULL
;
14252 if(ae
->tag
== List
){
14254 for(l2
= ae
->addr
.list
; *l2
; l2
++)
14255 length
+= (strlen(*l2
) + 1);
14257 list
= (char *) fs_get(length
+ 1);
14260 for(l2
= ae
->addr
.list
; *l2
; l2
++){
14261 if(l1
!= list
&& l1
-list
< length
+1)
14264 strncpy(l1
, *l2
, length
+1-(l1
-list
));
14268 list
[length
] = '\0';
14271 bldto
.arg
.str
= list
;
14272 adr2
= expand_address(bldto
, userdomain
, localdomain
,
14273 loop_detected
, fcc
, did_set
,
14274 lcc
, error
, 1, simple_verify
,
14277 fs_give((void **) &list
);
14279 else if(ae
->tag
== Single
){
14280 if(strucmp(ae
->addr
.addr
, a
->mailbox
)){
14282 bldto
.arg
.str
= ae
->addr
.addr
;
14283 adr2
= expand_address(bldto
, userdomain
,
14284 localdomain
, loop_detected
,
14286 error
, 1, simple_verify
,
14291 * A loop within plain single entry is ignored.
14292 * Set up so later code thinks we expanded.
14294 adr2
= mail_newaddr();
14295 adr2
->mailbox
= cpystr(ae
->addr
.addr
);
14296 adr2
->host
= cpystr(userdomain
);
14297 adr2
->adl
= cpystr(a
->adl
);
14302 * Personal names: If the expanded address has a personal
14303 * name and the address book entry is a list with a fullname,
14304 * tack the full name from the address book on in front.
14305 * This mainly occurs with a distribution list where the
14306 * list has a full name, and the first person in the list also
14309 * This algorithm doesn't work very well if lists are
14310 * included within lists, but it's not clear what would
14313 if(ae
->fullname
&& ae
->fullname
[0]){
14314 if(adr2
->personal
&& adr2
->personal
[0]){
14315 if(ae
->tag
== List
){
14316 /* combine list name and existing name */
14319 if(!simple_verify
){
14321 l
= strlen(adr2
->personal
) + strlen(ae
->fullname
) + 4;
14322 name
= (char *)fs_get((l
+1) * sizeof(char));
14323 snprintf(name
, l
+1, "%s -- %s", ae
->fullname
,
14325 fs_give((void **)&adr2
->personal
);
14326 adr2
->personal
= name
;
14330 /* replace with nickname fullname */
14331 fs_give((void **)&adr2
->personal
);
14332 adr2
->personal
= adrbk_formatname(ae
->fullname
,
14337 if(abe
-p
>tag
!= List
|| !simple_verify
){
14339 fs_give((void **)&adr2
->personal
);
14341 adr2
->personal
= adrbk_formatname(abe
->fullname
,
14353 peAEFcc(AdrBk_Entry
*ae
)
14357 if(ae
->fcc
&& ae
->fcc
[0]){
14359 if(!strcmp(ae
->fcc
, "\"\""))
14362 fcc
= cpystr(ae
->fcc
);
14365 else if(ae
->nickname
&& ae
->nickname
[0] &&
14366 (wps_global
->fcc_rule
== FCC_RULE_NICK
||
14367 wps_global
->fcc_rule
== FCC_RULE_NICK_RECIP
)){
14369 * else if fcc-rule=fcc-by-nickname, use that
14372 fcc
= cpystr(ae
->nickname
);
14383 extern PINEFIELD
*parse_custom_hdrs(char **, CustomType
);
14385 return(parse_custom_hdrs(wps_global
->VAR_CUSTOM_HDRS
, UseAsDef
));
14391 * PEClistCmd - Collection list editing tools
14394 PEClistCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
14396 char *err
= "Unknown PEClist request";
14398 dprint((2, "PEClistCmd"));
14401 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
14404 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
14407 if(objc
== 3){ /* delete */
14408 if(!strcmp(s1
, "delete")){
14409 int cl
, i
, n
, deln
;
14411 CONTEXT_S
*del_ctxt
, *tmp_ctxt
, *new_ctxt
;
14413 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14414 Tcl_SetResult(interp
,
14415 "cledit malformed: first arg must be int",
14419 for(i
= 0, del_ctxt
= wps_global
->context_list
;
14420 del_ctxt
&& i
< cl
; i
++, del_ctxt
= del_ctxt
->next
);
14421 if(!del_ctxt
) return(TCL_ERROR
);
14422 for(n
= 0; del_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14424 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14426 deln
= del_ctxt
->var
.i
;
14427 for(i
= 0; del_ctxt
->var
.v
->current_val
.l
[i
]; i
++){
14429 newl
[i
] = cpystr(del_ctxt
->var
.v
->current_val
.l
[i
]);
14431 newl
[i
-1] = cpystr(del_ctxt
->var
.v
->current_val
.l
[i
]);
14433 n
= set_variable_list(del_ctxt
->var
.v
- wps_global
->vars
,
14434 *newl
? newl
: NULL
, TRUE
, Main
);
14435 free_list_array(&newl
);
14436 set_current_val(del_ctxt
->var
.v
, TRUE
, FALSE
);
14438 Tcl_SetResult(interp
,
14439 "Error saving changes",
14443 for(tmp_ctxt
= del_ctxt
->next
; tmp_ctxt
&& tmp_ctxt
->var
.v
==
14444 del_ctxt
->var
.v
; tmp_ctxt
= tmp_ctxt
->next
)
14446 if((tmp_ctxt
= del_ctxt
->next
) != NULL
)
14447 tmp_ctxt
->prev
= del_ctxt
->prev
;
14448 if((tmp_ctxt
= del_ctxt
->prev
) != NULL
)
14449 tmp_ctxt
->next
= del_ctxt
->next
;
14450 if(!del_ctxt
->prev
&& !del_ctxt
->next
){
14451 new_ctxt
= new_context(del_ctxt
->var
.v
->current_val
.l
[0], NULL
);
14452 wps_global
->context_list
= new_ctxt
;
14453 if(!new_ctxt
->var
.v
)
14454 new_ctxt
->var
= del_ctxt
->var
;
14456 else if(wps_global
->context_list
== del_ctxt
){
14457 wps_global
->context_list
= del_ctxt
->next
;
14458 if(!wps_global
->context_list
)
14459 return TCL_ERROR
; /* this shouldn't happen */
14461 if(wps_global
->context_last
== del_ctxt
)
14462 wps_global
->context_last
= NULL
;
14463 if(wps_global
->context_current
== del_ctxt
){
14464 strncpy(wps_global
->cur_folder
,
14465 wps_global
->mail_stream
->mailbox
,
14466 sizeof(wps_global
->cur_folder
));
14467 wps_global
->cur_folder
[sizeof(wps_global
->cur_folder
)-1] = '\0';
14468 wps_global
->context_current
= wps_global
->context_list
;
14470 del_ctxt
->prev
= NULL
;
14471 del_ctxt
->next
= NULL
;
14472 free_context(&del_ctxt
);
14473 init_inbox_mapping(wps_global
->VAR_INBOX_PATH
,
14474 wps_global
->context_list
);
14477 else if(!strcmp(s1
, "shuffdown")){
14479 CONTEXT_S
*sh_ctxt
, *nsh_ctxt
, *tctxt
;
14480 char **newl
, *tmpch
;
14482 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14483 Tcl_SetResult(interp
,
14484 "cledit malformed: first arg must be int",
14488 for(sh_ctxt
= wps_global
->context_list
, i
= 0;
14489 sh_ctxt
&& i
< cl
; i
++, sh_ctxt
= sh_ctxt
->next
);
14490 if(!sh_ctxt
|| !sh_ctxt
->next
){
14491 Tcl_SetResult(interp
,
14492 "invalid context list number",
14496 if(sh_ctxt
->var
.v
== sh_ctxt
->next
->var
.v
){
14497 shn
= sh_ctxt
->var
.i
;
14498 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14499 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14501 for(i
= 0; sh_ctxt
->var
.v
->current_val
.l
[i
]; i
++){
14503 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
+1]);
14504 else if(i
== shn
+ 1)
14505 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14507 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14509 n
= set_variable_list(sh_ctxt
->var
.v
- wps_global
->vars
,
14511 free_list_array(&newl
);
14512 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14514 Tcl_SetResult(interp
,
14515 "Error saving changes",
14519 nsh_ctxt
= sh_ctxt
->next
;
14524 nsh_ctxt
= sh_ctxt
->next
;
14525 shn
= sh_ctxt
->var
.i
;
14526 tmpch
= cpystr(sh_ctxt
->var
.v
->current_val
.l
[shn
]);
14527 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14529 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14531 for(i
= 0; sh_ctxt
->var
.v
->current_val
.l
[i
+1]; i
++)
14532 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14533 n
= set_variable_list(sh_ctxt
->var
.v
- wps_global
->vars
,
14534 newl
, FALSE
, Main
);
14535 free_list_array(&newl
);
14536 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14537 for(n
= 0; nsh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14539 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14541 newl
[0] = cpystr(nsh_ctxt
->var
.v
->current_val
.l
[0]);
14543 for(i
= 2; nsh_ctxt
->var
.v
->current_val
.l
[i
-1]; i
++)
14544 newl
[i
] = cpystr(nsh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14545 n
= set_variable_list(nsh_ctxt
->var
.v
- wps_global
->vars
,
14547 free_list_array(&newl
);
14548 set_current_val(nsh_ctxt
->var
.v
, TRUE
, FALSE
);
14549 sh_ctxt
->var
.v
= nsh_ctxt
->var
.v
;
14550 sh_ctxt
->var
.i
= 1;
14551 /* this for loop assumes that there are only two variable lists,
14552 * folder-collections and news-collections, a little more will
14553 * have to be done if we want to accommodate for the INHERIT
14554 * option introduced in 4.30.
14556 for(tctxt
= nsh_ctxt
->next
; tctxt
; tctxt
= tctxt
->next
)
14559 if(sh_ctxt
->prev
) sh_ctxt
->prev
->next
= nsh_ctxt
;
14560 nsh_ctxt
->prev
= sh_ctxt
->prev
;
14561 sh_ctxt
->next
= nsh_ctxt
->next
;
14562 nsh_ctxt
->next
= sh_ctxt
;
14563 sh_ctxt
->prev
= nsh_ctxt
;
14564 if(sh_ctxt
->next
) sh_ctxt
->next
->prev
= sh_ctxt
;
14565 if(wps_global
->context_list
== sh_ctxt
)
14566 wps_global
->context_list
= nsh_ctxt
;
14567 init_inbox_mapping(wps_global
->VAR_INBOX_PATH
,
14568 wps_global
->context_list
);
14571 else if(!strcmp(s1
, "shuffup")){
14573 CONTEXT_S
*sh_ctxt
, *psh_ctxt
, *tctxt
;
14574 char **newl
, *tmpch
;
14576 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14577 Tcl_SetResult(interp
,
14578 "cledit malformed: first arg must be int",
14582 for(sh_ctxt
= wps_global
->context_list
, i
= 0;
14583 sh_ctxt
&& i
< cl
; i
++, sh_ctxt
= sh_ctxt
->next
);
14584 if(!sh_ctxt
|| !sh_ctxt
->prev
){
14585 Tcl_SetResult(interp
,
14586 "invalid context list number",
14590 if(sh_ctxt
->var
.v
== sh_ctxt
->prev
->var
.v
){
14591 shn
= sh_ctxt
->var
.i
;
14592 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14593 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14595 for(i
= 0; sh_ctxt
->var
.v
->current_val
.l
[i
]; i
++){
14597 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14598 else if(i
== shn
- 1)
14599 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
+1]);
14601 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14603 i
= set_variable_list(sh_ctxt
->var
.v
- wps_global
->vars
,
14605 free_list_array(&newl
);
14606 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14608 Tcl_SetResult(interp
,
14609 "Error saving changes",
14613 psh_ctxt
= sh_ctxt
->prev
;
14618 psh_ctxt
= sh_ctxt
->prev
;
14619 shn
= sh_ctxt
->var
.i
;
14620 tmpch
= cpystr(sh_ctxt
->var
.v
->current_val
.l
[shn
]);
14621 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14623 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14625 for(i
= 1; sh_ctxt
->var
.v
->current_val
.l
[i
]; i
++)
14626 newl
[i
-1] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14627 i
= set_variable_list(sh_ctxt
->var
.v
- wps_global
->vars
,
14628 newl
, FALSE
, Main
);
14629 free_list_array(&newl
);
14631 Tcl_SetResult(interp
,
14632 "Error saving changes",
14636 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14637 for(n
= 0; psh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14639 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14641 for(i
= 0; psh_ctxt
->var
.v
->current_val
.l
[i
+1]; i
++)
14642 newl
[i
] = cpystr(psh_ctxt
->var
.v
->current_val
.l
[i
]);
14644 newl
[i
] = cpystr(psh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14645 i
= set_variable_list(psh_ctxt
->var
.v
- wps_global
->vars
,
14647 free_list_array(&newl
);
14649 Tcl_SetResult(interp
,
14650 "Error saving changes",
14654 set_current_val(psh_ctxt
->var
.v
, TRUE
, FALSE
);
14655 for(tctxt
= sh_ctxt
->next
; tctxt
; tctxt
= tctxt
->next
)
14657 sh_ctxt
->var
.v
= psh_ctxt
->var
.v
;
14658 sh_ctxt
->var
.i
= n
- 2;
14659 /* There MUST be at least 2 collections in the list */
14662 if(sh_ctxt
->next
) sh_ctxt
->next
->prev
= psh_ctxt
;
14663 psh_ctxt
->next
= sh_ctxt
->next
;
14664 sh_ctxt
->prev
= psh_ctxt
->prev
;
14665 psh_ctxt
->prev
= sh_ctxt
;
14666 sh_ctxt
->next
= psh_ctxt
;
14667 if(sh_ctxt
->prev
) sh_ctxt
->prev
->next
= sh_ctxt
;
14668 if(wps_global
->context_list
== psh_ctxt
)
14669 wps_global
->context_list
= sh_ctxt
;
14670 init_inbox_mapping(wps_global
->VAR_INBOX_PATH
,
14671 wps_global
->context_list
);
14675 else if(objc
== 7){
14676 if(!strcmp(s1
, "edit") || !strcmp(s1
, "add")){
14677 int cl
, quotes_needed
= 0, i
, add
= 0, n
= 0;
14678 char *nick
, *server
, *path
, *view
,
14679 context_buf
[MAILTMPLEN
*4], **newl
;
14680 CONTEXT_S
*new_ctxt
, *tmp_ctxt
;
14682 if(!strcmp(s1
, "add")) add
= 1;
14684 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14685 Tcl_SetResult(interp
,
14686 "cledit malformed: first arg must be int",
14690 if(!(nick
= Tcl_GetStringFromObj(objv
[3], NULL
))){
14691 Tcl_SetResult(interp
,
14696 if(!(server
= Tcl_GetStringFromObj(objv
[4], NULL
))){
14697 Tcl_SetResult(interp
,
14702 if(!(path
= Tcl_GetStringFromObj(objv
[5], NULL
))){
14703 Tcl_SetResult(interp
,
14708 if(!(view
= Tcl_GetStringFromObj(objv
[6], NULL
))){
14709 Tcl_SetResult(interp
,
14714 removing_leading_and_trailing_white_space(nick
);
14715 removing_leading_and_trailing_white_space(server
);
14716 removing_leading_and_trailing_white_space(path
);
14717 removing_leading_and_trailing_white_space(view
);
14718 if(strchr(nick
, ' '))
14720 if(strlen(nick
)+strlen(server
)+strlen(path
)+strlen(view
) >
14721 MAILTMPLEN
* 4 - 20) { /* for good measure */
14722 Tcl_SetResult(interp
,
14728 if(3 + strlen(nick
) + strlen(server
) + strlen(path
) +
14729 strlen(view
) > MAILTMPLEN
+ 4){
14730 Tcl_SetResult(interp
,
14731 "collection fields too long",
14735 snprintf(context_buf
, sizeof(context_buf
), "%s%s%s%s%s%s[%s]", quotes_needed
?
14736 "\"" : "", nick
, quotes_needed
? "\"" : "",
14737 strlen(nick
) ? " " : "",
14738 server
, path
, view
);
14739 new_ctxt
= new_context(context_buf
, NULL
);
14741 for(tmp_ctxt
= wps_global
->context_list
, i
= 0;
14742 tmp_ctxt
&& i
< cl
; i
++, tmp_ctxt
= tmp_ctxt
->next
);
14744 Tcl_SetResult(interp
,
14745 "invalid context list number",
14749 new_ctxt
->next
= tmp_ctxt
->next
;
14750 new_ctxt
->prev
= tmp_ctxt
->prev
;
14751 if(tmp_ctxt
->prev
&& tmp_ctxt
->prev
->next
== tmp_ctxt
)
14752 tmp_ctxt
->prev
->next
= new_ctxt
;
14753 if(tmp_ctxt
->next
&& tmp_ctxt
->next
->prev
== tmp_ctxt
)
14754 tmp_ctxt
->next
->prev
= new_ctxt
;
14755 if(wps_global
->context_list
== tmp_ctxt
)
14756 wps_global
->context_list
= new_ctxt
;
14757 if(wps_global
->context_current
== tmp_ctxt
){
14758 strncpy(wps_global
->cur_folder
,
14759 wps_global
->mail_stream
->mailbox
,
14760 sizeof(wps_global
->cur_folder
));
14761 wps_global
->cur_folder
[sizeof(wps_global
->cur_folder
)-1] = '\0';
14762 wps_global
->context_current
= new_ctxt
;
14764 if(wps_global
->context_last
== tmp_ctxt
)
14765 wps_global
->context_last
= new_ctxt
;
14766 new_ctxt
->var
= tmp_ctxt
->var
;
14767 tmp_ctxt
->next
= tmp_ctxt
->prev
= NULL
;
14768 free_context(&tmp_ctxt
);
14771 for(tmp_ctxt
= wps_global
->context_list
;
14772 tmp_ctxt
->next
; tmp_ctxt
= tmp_ctxt
->next
);
14773 new_ctxt
->prev
= tmp_ctxt
;
14774 tmp_ctxt
->next
= new_ctxt
;
14775 new_ctxt
->var
.v
= tmp_ctxt
->var
.v
;
14776 new_ctxt
->var
.i
= tmp_ctxt
->var
.i
+ 1;
14778 if(!new_ctxt
->var
.v
){
14779 Tcl_SetResult(interp
,
14784 for(n
= 0; new_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14786 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14788 for(n
= 0; new_ctxt
->var
.v
->current_val
.l
[n
]; n
++)
14789 newl
[n
] = (n
== new_ctxt
->var
.i
)
14790 ? cpystr(context_buf
)
14791 : cpystr(new_ctxt
->var
.v
->current_val
.l
[n
]);
14792 if(add
) newl
[n
++] = cpystr(context_buf
);
14793 n
= set_variable_list(new_ctxt
->var
.v
- wps_global
->vars
,
14795 free_list_array(&newl
);
14796 set_current_val(new_ctxt
->var
.v
, TRUE
, FALSE
);
14797 init_inbox_mapping(wps_global
->VAR_INBOX_PATH
,
14798 wps_global
->context_list
);
14800 Tcl_SetResult(interp
,
14801 "Error saving changes",
14811 Tcl_SetResult(interp
, err
, TCL_STATIC
);
14817 * peTakeaddr - Take Address
14820 peTakeaddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
14822 TA_S
*talist
= NULL
, *current
, *head
;
14823 Tcl_Obj
*itemObj
, *secObj
= NULL
, *resObj
= NULL
;
14826 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
));
14828 if(set_up_takeaddr('a', wps_global
, sp_msgmap(wps_global
->mail_stream
),
14829 &talist
, &anum
, TA_NOPROMPT
, NULL
) < 0
14830 || (talist
== NULL
)){
14831 Tcl_SetResult(interp
,
14832 "Take address failed to set up",
14837 for(head
= talist
; head
->prev
; head
= head
->prev
);
14839 * Return value will be of the form:
14841 * { "line to print",
14842 * {"personal", "mailbox", "host"} # addr
14843 * {"nick", "fullname", "fcc", "comment"} # suggested
14848 * The two list items will be empty if that line is
14849 * just informational.
14851 itemObj
= Tcl_NewListObj(0, NULL
);
14852 for(current
= head
; current
; current
= current
->next
){
14853 if(current
->skip_it
&& !current
->print
) continue;
14854 secObj
= Tcl_NewListObj(0, NULL
);
14855 if(Tcl_ListObjAppendElement(interp
, secObj
,
14856 Tcl_NewStringObj(current
->strvalue
,-1)) != TCL_OK
)
14858 resObj
= Tcl_NewListObj(0, NULL
);
14859 /* append the address information */
14860 if(current
->addr
&& !current
->print
){
14861 if(Tcl_ListObjAppendElement(interp
, resObj
,
14862 Tcl_NewStringObj(current
->addr
->personal
14863 ? current
->addr
->personal
14864 : "", -1)) != TCL_OK
)
14866 if(Tcl_ListObjAppendElement(interp
, resObj
,
14867 Tcl_NewStringObj(current
->addr
->mailbox
14868 ? current
->addr
->mailbox
14869 : "", -1)) != TCL_OK
)
14871 if(Tcl_ListObjAppendElement(interp
, resObj
,
14872 Tcl_NewStringObj(current
->addr
->host
14873 ? current
->addr
->host
14874 : "", -1)) != TCL_OK
)
14877 if(Tcl_ListObjAppendElement(interp
, secObj
,
14880 resObj
= Tcl_NewListObj(0, NULL
);
14881 /* append the suggested possible entries */
14883 && (current
->nickname
|| current
->fullname
14884 || current
->fcc
|| current
->comment
)){
14885 if(Tcl_ListObjAppendElement(interp
, resObj
,
14886 Tcl_NewStringObj(current
->nickname
14887 ? current
->nickname
14888 : "", -1)) != TCL_OK
)
14890 if(Tcl_ListObjAppendElement(interp
, resObj
,
14891 Tcl_NewStringObj(current
->fullname
14892 ? current
->fullname
14893 : "", -1)) != TCL_OK
)
14895 if(Tcl_ListObjAppendElement(interp
, resObj
,
14896 Tcl_NewStringObj(current
->fcc
14898 : "", -1)) != TCL_OK
)
14900 if(Tcl_ListObjAppendElement(interp
, resObj
,
14901 Tcl_NewStringObj(current
->comment
14903 : "", -1)) != TCL_OK
)
14906 if(Tcl_ListObjAppendElement(interp
, secObj
, resObj
) != TCL_OK
)
14908 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
14913 free_talines(&talist
);
14919 * peTakeFrom - Take only From Address
14922 peTakeFrom(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
14931 * Return value will be of the form:
14933 * { "line to print",
14934 * {"personal", "mailbox", "host"} # addr
14935 * {"nick", "fullname", "fcc", "comment"} # suggested
14940 * The two list items will be empty if that line is
14941 * just informational.
14945 if((env
= pine_mail_fetchstructure(wps_global
->mail_stream
,
14946 rawno
= peSequenceNumber(uid
),
14948 /* append the address information */
14949 for(ap
= env
->from
; ap
; ap
= ap
->next
){
14950 objItem
= Tcl_NewListObj(0, NULL
);
14951 /* append EMPTY "line to print" */
14952 if(Tcl_ListObjAppendElement(interp
, objItem
, Tcl_NewStringObj("",-1)) != TCL_OK
)
14955 /* append address info */
14956 peAppListF(interp
, objItem
, "%s%s%s",
14957 ap
->personal
? (char *) rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
, SIZEOF_20KBUF
, ap
->personal
) : "",
14958 ap
->mailbox
? ap
->mailbox
: "",
14959 ap
->host
? ap
->host
: "");
14961 /* append suggested info */
14962 peAddSuggestedContactInfo(interp
, objItem
, ap
);
14964 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objItem
) != TCL_OK
)
14971 err
= wps_global
->last_error
;
14974 err
= "Invalid UID";
14981 peAddSuggestedContactInfo(Tcl_Interp
*interp
, Tcl_Obj
*lobjp
, ADDRESS
*addr
)
14983 char *nick
= NULL
, *full
= NULL
, *fcc
= NULL
, *comment
= NULL
;
14985 get_contactinfo_from_addr(addr
, &nick
, &full
, &fcc
, &comment
);
14987 peAppListF(interp
, lobjp
, "%s%s%s%s",
14991 comment
? comment
: "");
14994 fs_give((void **) &nick
);
14997 fs_give((void **) &full
);
15000 fs_give((void **) &fcc
);
15003 fs_give((void **) &comment
);
15009 /* * * * * * * * * Status message ring management * * * * * * * * * * * * */
15012 sml_newmsg(int priority
, char *text
)
15014 static long id
= 1;
15017 smp
= (STATMSG_S
*) fs_get(sizeof(STATMSG_S
));
15018 memset(smp
, 0, sizeof(STATMSG_S
));
15020 smp
->posted
= time(0);
15021 smp
->type
= priority
;
15022 smp
->text
= cpystr(text
);
15028 sml_addmsg(int priority
, char *text
)
15030 STATMSG_S
*smp
= sml_newmsg(priority
, text
);
15033 smp
->next
= peStatList
;
15046 char **retstrs
= NULL
, **tmpstrs
;
15048 for(n
= 0, smp
= peStatList
; smp
&& !smp
->seen
; n
++, smp
= smp
->next
)
15051 if(n
== 0) return NULL
;
15052 retstrs
= (char **)fs_get((n
+1)*sizeof(char *));
15053 for(tmpstrs
= retstrs
, smp
= peStatList
; smp
&& !smp
->seen
; smp
= smp
->next
){
15054 *tmpstrs
= smp
->text
;
15066 return(peStatList
? peStatList
->text
: "");
15074 for(smp
= peStatList
; smp
; smp
= smp
->next
)
15080 /* * * * * * * * * LDAP Support Routines * * * * * * * * * * * */
15084 * PELdapCmd - LDAP TCL interface
15087 PELdapCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
15089 #ifndef ENABLE_LDAP
15090 char *err
= "Call to PELdap when LDAP not enabled";
15092 char *err
= "Unknown PELdap request";
15095 dprint((2, "PELdapCmd"));
15098 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15099 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15102 s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
15106 if(!strcmp(s1
, "directories")){
15112 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15113 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15116 if(wps_global
->VAR_LDAP_SERVERS
){
15117 for(i
= 0; wps_global
->VAR_LDAP_SERVERS
[i
] &&
15118 wps_global
->VAR_LDAP_SERVERS
[i
][0]; i
++){
15119 info
= break_up_ldap_server(wps_global
->VAR_LDAP_SERVERS
[i
]);
15120 secObj
= Tcl_NewListObj(0, NULL
);
15121 if(Tcl_ListObjAppendElement(interp
, secObj
,
15122 Tcl_NewStringObj(info
->nick
? info
->nick
15123 : "", -1)) != TCL_OK
)
15125 if(Tcl_ListObjAppendElement(interp
, secObj
,
15126 Tcl_NewStringObj(info
->serv
? info
->serv
15127 : "", -1)) != TCL_OK
)
15131 free_ldap_server_info(&info
);
15132 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15138 Tcl_SetResult(interp
, "", TCL_STATIC
);
15142 else if(!strcmp(s1
, "query")){
15144 char *srchstr
, *filtstr
;
15145 LDAP_CHOOSE_S
*winning_e
= NULL
;
15146 LDAP_SERV_RES_S
*results
= NULL
;
15148 CUSTOM_FILT_S
*filter
= NULL
;
15151 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15152 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15155 if(Tcl_GetIntFromObj(interp
, objv
[2], &dir
) == TCL_ERROR
){
15156 Tcl_SetResult(interp
,
15157 "PELdap results malformed: first arg must be int",
15161 wpldap_global
->query_no
++;
15162 if(wpldap_global
->ldap_search_list
){
15163 wpldap_global
->ldap_search_list
=
15164 free_wpldapres(wpldap_global
->ldap_search_list
);
15166 srchstr
= Tcl_GetStringFromObj(objv
[3], NULL
);
15167 filtstr
= Tcl_GetStringFromObj(objv
[4], NULL
);
15168 if(!srchstr
) return(TCL_ERROR
);
15169 if(!filtstr
) return(TCL_ERROR
);
15171 filter
= (CUSTOM_FILT_S
*)fs_get(sizeof(CUSTOM_FILT_S
));
15172 filter
->filt
= cpystr(filtstr
);
15173 filter
->combine
= 0;
15175 memset(&wp_err
, 0, sizeof(wp_err
));
15176 ldap_lookup_all(srchstr
, dir
, 0, AlwaysDisplay
, filter
, &winning_e
,
15177 &wp_err
, &results
);
15179 fs_give((void **)&filter
->filt
);
15180 fs_give((void **)&filter
);
15182 Tcl_SetResult(interp
, int2string(wpldap_global
->ldap_search_list
15183 ? wpldap_global
->query_no
: 0),
15188 * First argument has always got to be the query number for now.
15189 * Might need to rething that when setting up queries.
15192 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15193 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15196 if(Tcl_GetIntFromObj(interp
, objv
[2], &qn
) == TCL_ERROR
){
15197 Tcl_SetResult(interp
,
15198 "PELdap results malformed: first arg must be int",
15202 if(qn
!= wpldap_global
->query_no
){
15203 Tcl_SetResult(interp
,
15204 "Query is no longer valid", TCL_VOLATILE
);
15208 if(!strcmp(s1
, "results")){
15209 return(peLdapQueryResults(interp
));
15212 else if(objc
== 4){
15213 if(!strcmp(s1
, "ldapext")){
15215 * Returns a list of the form:
15216 * {"dn" {{attrib {val, ...} {opt, ...}}, ...}}
15218 char *whichrec
= Tcl_GetStringFromObj(objv
[3], NULL
);
15219 char *tmpstr
, *tmp
, *tmp2
, *a
;
15220 struct berval
**vals
;
15221 WPLDAPRES_S
*curres
;
15222 LDAP_CHOOSE_S
*winning_e
= NULL
;
15223 LDAP_SERV_RES_S
*trl
;
15224 Tcl_Obj
*secObj
= NULL
, *resObj
= NULL
, *itemObj
;
15227 int i
, j
, whichi
, whichj
;
15229 if(whichrec
== NULL
){
15230 Tcl_SetResult(interp
, "Ldap ldapext error 1", TCL_VOLATILE
);
15233 tmpstr
= cpystr(whichrec
);
15235 for(tmp2
= tmp
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15237 Tcl_SetResult(interp
, "Ldap ldapext error 2", TCL_VOLATILE
);
15241 whichi
= atoi(tmp
);
15244 for(tmp
= tmp2
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15246 Tcl_SetResult(interp
, "Ldap ldapext error 3", TCL_VOLATILE
);
15249 whichj
= atoi(tmp
);
15250 fs_give((void **)&tmpstr
);
15251 for(curres
= wpldap_global
->ldap_search_list
, i
= 0;
15252 i
< whichi
&& curres
; i
++, curres
= curres
->next
);
15254 Tcl_SetResult(interp
, "Ldap ldapext error 4", TCL_VOLATILE
);
15257 for(trl
= curres
->reslist
, j
= 0; trl
; trl
= trl
->next
){
15258 for(e
= ldap_first_entry(trl
->ld
, trl
->res
);
15259 e
!= NULL
&& j
< whichj
;
15260 e
= ldap_next_entry(trl
->ld
, e
), j
++);
15261 if(e
!= NULL
&& j
== whichj
)
15264 if(e
== NULL
|| trl
== NULL
){
15265 Tcl_SetResult(interp
, "Ldap ldapext error 5", TCL_VOLATILE
);
15268 winning_e
= (LDAP_CHOOSE_S
*)fs_get(sizeof(LDAP_CHOOSE_S
));
15269 winning_e
->ld
= trl
->ld
;
15270 winning_e
->selected_entry
= e
;
15271 winning_e
->info_used
= trl
->info_used
;
15272 winning_e
->serv
= trl
->serv
;
15273 a
= ldap_get_dn(winning_e
->ld
, winning_e
->selected_entry
);
15274 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15275 Tcl_NewStringObj(a
? a
: "", -1)) != TCL_OK
)
15278 our_ldap_dn_memfree(a
);
15280 itemObj
= Tcl_NewListObj(0, NULL
);
15281 for(a
= ldap_first_attribute(winning_e
->ld
, winning_e
->selected_entry
, &ber
);
15283 a
= ldap_next_attribute(winning_e
->ld
, winning_e
->selected_entry
, ber
)){
15285 secObj
= Tcl_NewListObj(0, NULL
);
15286 if(Tcl_ListObjAppendElement(interp
, secObj
,
15287 Tcl_NewStringObj(ldap_translate(a
,
15288 winning_e
->info_used
), -1)) != TCL_OK
)
15290 resObj
= Tcl_NewListObj(0, NULL
);
15291 vals
= ldap_get_values_len(winning_e
->ld
, winning_e
->selected_entry
, a
);
15293 for(i
= 0; vals
[i
]; i
++){
15294 if(Tcl_ListObjAppendElement(interp
, resObj
,
15295 Tcl_NewStringObj(vals
[i
]->bv_val
, -1)) != TCL_OK
)
15298 ldap_value_free_len(vals
);
15299 if(Tcl_ListObjAppendElement(interp
, secObj
, resObj
) != TCL_OK
)
15301 resObj
= Tcl_NewListObj(0, NULL
);
15303 if(!strucmp(a
, "objectclass")){
15304 if(Tcl_ListObjAppendElement(interp
, resObj
,
15305 Tcl_NewStringObj("objectclass", -1)) != TCL_OK
)
15308 for(tmp
= strchr(a
, ';'); tmp
!= NULL
; tmp
= tmp2
){
15311 tmp2
= strchr(++tmp
, ';');
15314 retval
= Tcl_ListObjAppendElement(interp
, resObj
,
15315 Tcl_NewStringObj(tmp
, -1));
15318 if(retval
!= TCL_OK
)
15321 if(Tcl_ListObjAppendElement(interp
, secObj
, resObj
) != TCL_OK
)
15323 if(Tcl_ListObjAppendElement(interp
, itemObj
, secObj
) != TCL_OK
)
15326 our_ldap_memfree(a
);
15329 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15330 itemObj
) != TCL_OK
)
15333 fs_give((void **)&winning_e
);
15337 else if(objc
== 6){
15338 if(!strcmp(s1
, "setaddrs")){
15339 char *listset
= Tcl_GetStringFromObj(objv
[3], NULL
);
15340 char *addrstr
= Tcl_GetStringFromObj(objv
[4], NULL
);
15341 char *tmp
, *tmp2
, *tmplistset
, was_char
, *ret_to
,
15343 int **lset
, noreplace
= 0;
15344 ADDRESS
*adr
= NULL
, *curadr
, *prevadr
, *newadr
,
15345 *curnewadr
, *newadrs
;
15346 int curi
, i
, j
, numsrchs
, numset
, setit
;
15347 LDAP_CHOOSE_S
*tres
;
15348 LDAP_SERV_RES_S
*trl
;
15349 WPLDAPRES_S
*curres
;
15354 if(Tcl_GetIntFromObj(interp
, objv
[5], &noreplace
) == TCL_ERROR
){
15355 Tcl_SetResult(interp
,
15356 "PELdap results malformed: first arg must be int",
15360 if(listset
== NULL
|| addrstr
== NULL
) return TCL_ERROR
;
15361 tmpaddrstr
= cpystr(addrstr
);
15364 mail_parameters(NIL
, SET_PARSEPHRASE
, (void *)massage_phrase_addr
);
15365 rfc822_parse_adrlist(&adr
, tmpaddrstr
, "@");
15366 mail_parameters(NIL
, SET_PARSEPHRASE
, NULL
);
15369 tmplistset
= cpystr(listset
);
15370 for(curres
= wpldap_global
->ldap_search_list
, numsrchs
= 0;
15371 curres
; curres
= curres
->next
, numsrchs
++);
15372 lset
= (int **)fs_get((numsrchs
+1)*sizeof(int *));
15373 for(i
= 0; i
< numsrchs
; i
++){
15374 for(tmp
= tmplistset
, numset
= 0; *tmp
;){
15375 for(tmp2
= tmp
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15377 Tcl_SetResult(interp
, "Ldap error 1", TCL_VOLATILE
);
15380 if(atoi(tmp
) == i
) numset
++;
15382 for(tmp
= tmp2
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15383 if(*tmp2
!= ',' && *tmp2
!= '\0'){
15384 Tcl_SetResult(interp
, "Ldap error 2", TCL_VOLATILE
);
15390 lset
[i
] = (int *)fs_get((numset
+1)*sizeof(int));
15391 for(tmp
= tmplistset
, j
= 0; *tmp
&& j
< numset
;){
15393 for(tmp2
= tmp
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15395 Tcl_SetResult(interp
, "Ldap error 3", TCL_VOLATILE
);
15399 if(atoi(tmp
) == i
) setit
++;
15402 for(tmp
= tmp2
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15403 if(*tmp2
!= ',' && *tmp2
!= '\0'){
15404 Tcl_SetResult(interp
, "Ldap error 4", TCL_VOLATILE
);
15410 lset
[i
][j
++] = atoi(tmp
);
15419 for(i
= 0, curres
= wpldap_global
->ldap_search_list
;
15420 i
< numsrchs
&& curres
; i
++, curres
= curres
->next
){
15422 for(curadr
= adr
; curadr
; curadr
= curadr
->next
){
15423 if(strcmp(curadr
->mailbox
, curres
->str
) == 0
15424 && curadr
->host
&& *curadr
->host
== '@')
15428 if(!curadr
&& !noreplace
){
15429 Tcl_SetResult(interp
, "Ldap error 5", TCL_VOLATILE
);
15432 newadrs
= newadr
= curnewadr
= NULL
;
15433 for(trl
= curres
->reslist
, j
= 0, curi
= 0; trl
; trl
= trl
->next
){
15434 for(e
= ldap_first_entry(trl
->ld
, trl
->res
);
15435 e
!= NULL
&& lset
[i
][curi
] != -1;
15436 e
= ldap_next_entry(trl
->ld
, e
), j
++){
15437 if(j
== lset
[i
][curi
]){
15438 tres
= (LDAP_CHOOSE_S
*)fs_get(sizeof(LDAP_CHOOSE_S
));
15439 tres
->ld
= trl
->ld
;
15440 tres
->selected_entry
= e
;
15441 tres
->info_used
= trl
->info_used
;
15442 tres
->serv
= trl
->serv
;
15443 newadr
= address_from_ldap(tres
);
15444 fs_give((void **)&tres
);
15446 if(newadrs
== NULL
){
15447 newadrs
= curnewadr
= newadr
;
15450 curnewadr
->next
= newadr
;
15451 curnewadr
= newadr
;
15457 if(newadrs
== NULL
|| curnewadr
== NULL
){
15458 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "No Result Selected for \"%s\"", curadr
->mailbox
? curadr
->mailbox
: "noname");
15459 q_status_message(SM_ORDER
, 0, 3, wtmp_20k_buf
);
15460 newadr
= copyaddr(curadr
);
15461 if(newadrs
== NULL
){
15462 newadrs
= curnewadr
= newadr
;
15465 curnewadr
->next
= newadr
;
15466 curnewadr
= newadr
;
15469 curnewadr
->next
= curadr
? curadr
->next
: NULL
;
15470 if(curadr
) curadr
->next
= NULL
;
15474 prevadr
->next
= newadrs
;
15476 mail_free_address(&curadr
);
15480 len
= est_size(adr
);
15481 ret_to
= (char *)fs_get(len
* sizeof(char));
15483 strip_personal_quotes(adr
);
15484 rbuf
.f
= dummy_soutr
;
15488 rbuf
.end
= ret_to
+len
-1;
15489 rfc822_output_address_list(&rbuf
, adr
, 0L, NULL
);
15491 Tcl_SetResult(interp
, ret_to
, TCL_VOLATILE
);
15492 fs_give((void **)&ret_to
);
15493 fs_give((void **)&tmpaddrstr
);
15494 fs_give((void **)&tmplistset
);
15495 for(i
= 0; lset
[i
]; i
++)
15496 fs_give((void **)&lset
[i
]);
15497 fs_give((void **)&lset
);
15499 mail_free_address(&adr
);
15505 #endif /* ENABLE_LDAP */
15506 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15513 peLdapQueryResults(Tcl_Interp
*interp
)
15516 Tcl_Obj
*secObj
= NULL
, *resObj
= NULL
, *itemObj
;
15518 LDAP_SERV_RES_S
*trl
;
15519 /* returned list will be of the form:
15523 * {name, {title, ...}, {unit, ...},
15524 * {org, ...}, {email, ...}},
15531 for(tsl
= wpldap_global
->ldap_search_list
;
15532 tsl
; tsl
= tsl
->next
){
15533 secObj
= Tcl_NewListObj(0, NULL
);
15534 if(Tcl_ListObjAppendElement(interp
, secObj
,
15535 Tcl_NewStringObj(tsl
->str
? tsl
->str
15536 : "", -1)) != TCL_OK
)
15538 resObj
= Tcl_NewListObj(0, NULL
);
15539 for(trl
= tsl
->reslist
; trl
; trl
= trl
->next
){
15540 for(e
= ldap_first_entry(trl
->ld
, trl
->res
);
15542 e
= ldap_next_entry(trl
->ld
, e
)){
15544 struct berval
**cn
, **org
, **unit
, **title
, **mail
, **sn
;
15547 cn
= org
= title
= unit
= mail
= sn
= NULL
;
15549 itemObj
= Tcl_NewListObj(0, NULL
);
15550 peLdapEntryParse(trl
, e
, &cn
, &org
, &unit
, &title
,
15553 if(Tcl_ListObjAppendElement(interp
, itemObj
,
15554 Tcl_NewStringObj(cn
[0]->bv_val
, -1)) != TCL_OK
)
15556 ldap_value_free_len(cn
);
15559 if(Tcl_ListObjAppendElement(interp
, itemObj
,
15560 Tcl_NewStringObj(sn
[0]->bv_val
, -1)) != TCL_OK
)
15562 ldap_value_free_len(sn
);
15565 dn
= ldap_get_dn(trl
->ld
, e
);
15568 our_ldap_dn_memfree(dn
);
15572 if(Tcl_ListObjAppendElement(interp
, itemObj
,
15573 Tcl_NewStringObj(dn
? dn
: "", -1)) != TCL_OK
)
15577 our_ldap_dn_memfree(dn
);
15579 if(peLdapStrlist(interp
, itemObj
, title
) == TCL_ERROR
)
15581 if(peLdapStrlist(interp
, itemObj
, unit
) == TCL_ERROR
)
15583 if(peLdapStrlist(interp
, itemObj
, org
) == TCL_ERROR
)
15585 if(peLdapStrlist(interp
, itemObj
, mail
) == TCL_ERROR
)
15587 if(Tcl_ListObjAppendElement(interp
, resObj
, itemObj
) != TCL_OK
)
15590 ldap_value_free_len(title
);
15592 ldap_value_free_len(unit
);
15594 ldap_value_free_len(org
);
15596 ldap_value_free_len(mail
);
15599 if(Tcl_ListObjAppendElement(interp
, secObj
, resObj
) != TCL_OK
)
15601 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15609 peLdapStrlist(Tcl_Interp
*interp
, Tcl_Obj
*itemObj
, struct berval
**strl
)
15614 strlObj
= Tcl_NewListObj(0, NULL
);
15616 for(i
= 0; ALPINE_LDAP_usable(strl
, i
); i
++){
15617 if(Tcl_ListObjAppendElement(interp
, strlObj
,
15618 Tcl_NewStringObj(strl
[i
]->bv_val
, -1)) != TCL_OK
)
15622 if(Tcl_ListObjAppendElement(interp
, itemObj
, strlObj
) != TCL_OK
)
15629 init_ldap_pname(struct pine
*ps
)
15631 if(!wps_global
->VAR_PERSONAL_NAME
15632 || wps_global
->VAR_PERSONAL_NAME
[0] == '\0'){
15634 struct variable
*vtmp
;
15636 if(ps
->maildomain
&& *ps
->maildomain
15637 && ps
->VAR_USER_ID
&& *ps
->VAR_USER_ID
){
15638 pname
= peLdapPname(ps
->VAR_USER_ID
, ps
->maildomain
);
15640 vtmp
= &ps
->vars
[V_PERSONAL_NAME
];
15641 if((vtmp
->fixed_val
.p
&& vtmp
->fixed_val
.p
[0] == '\0')
15642 || (vtmp
->is_fixed
&& !vtmp
->fixed_val
.p
)){
15643 if(vtmp
->fixed_val
.p
)
15644 fs_give((void **)&vtmp
->fixed_val
.p
);
15645 vtmp
->fixed_val
.p
= cpystr(pname
);
15648 if(vtmp
->global_val
.p
)
15649 fs_give((void **)&vtmp
->global_val
.p
);
15650 vtmp
->global_val
.p
= cpystr(pname
);
15652 fs_give((void **)&pname
);
15653 set_current_val(vtmp
, FALSE
, FALSE
);
15659 #endif /* ENABLE_LDAP */
15662 * Note: this is taken straight out of pico/composer.c
15664 * strqchr - returns pointer to first non-quote-enclosed occurance of ch in
15665 * the given string. otherwise NULL.
15667 * ch -- the character we're looking for
15668 * q -- q tells us if we start out inside quotes on entry and is set
15669 * correctly on exit.
15670 * m -- max characters we'll check for ch (set to -1 for no check)
15673 strqchr(char *s
, int ch
, int *q
, int m
)
15675 int quoted
= (q
) ? *q
: 0;
15677 for(; s
&& *s
&& m
!= 0; s
++, m
--){
15684 if(!quoted
&& *s
== ch
)
15693 wp_prune_folders(CONTEXT_S
*ctxt
,
15700 Tcl_Interp
*interp
)
15702 Tcl_Obj
*resObj
= NULL
, *secObj
= NULL
;
15703 char path2
[MAXPATH
+1], tmp
[21];
15704 int exists
, month_to_use
;
15705 struct sm_folder
*mail_list
, *sm
;
15707 mail_list
= get_mail_list(ctxt
, fcc
);
15709 for(sm
= mail_list
; sm
!= NULL
&& sm
->name
!= NULL
; sm
++)
15710 if(sm
->month_num
== cur_month
- 1)
15711 break; /* matched a month */
15713 month_to_use
= (sm
== NULL
|| sm
->name
== NULL
) ? cur_month
- 1 : 0;
15715 if(!(month_to_use
== 0 || pr
== PRUNE_NO_AND_ASK
|| pr
== PRUNE_NO_AND_NO
)){
15716 strncpy(path2
, fcc
, sizeof(path2
)-1);
15717 path2
[sizeof(path2
)-1] = '\0';
15718 strncpy(tmp
, month_abbrev((month_to_use
% 12)+1), sizeof(tmp
)-1);
15719 tmp
[sizeof(tmp
)-1] = '\0';
15720 lcase((unsigned char *) tmp
);
15721 snprintf(path2
+ strlen(path2
), sizeof(path2
)-strlen(path2
), "-%.20s-%d", tmp
, month_to_use
/12);
15723 if((exists
= folder_exists(ctxt
, fcc
)) == FEX_ERROR
){
15727 else if(exists
& FEX_ISFILE
){
15728 if(pr
== PRUNE_YES_AND_ASK
|| (pr
== PRUNE_YES_AND_NO
&& !moved_fldrs
)){
15729 prune_move_folder(fcc
, path2
, ctxt
);
15731 resObj
= Tcl_NewListObj(0, NULL
);
15732 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewStringObj(type
, -1));
15733 secObj
= Tcl_NewListObj(0, NULL
);
15734 Tcl_ListObjAppendElement(interp
, secObj
, Tcl_NewStringObj(fcc
, -1));
15735 Tcl_ListObjAppendElement(interp
, secObj
, Tcl_NewStringObj(path2
, -1));
15736 Tcl_ListObjAppendElement(interp
, resObj
, secObj
);
15740 if(pr
== PRUNE_ASK_AND_ASK
|| pr
== PRUNE_YES_AND_ASK
15741 || pr
== PRUNE_NO_AND_ASK
){
15743 if(!resObj
&& sm
&& sm
->name
&& sm
->name
[0] != '\0'){
15744 resObj
= Tcl_NewListObj(0, NULL
);
15745 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewStringObj(type
, -1));
15746 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewListObj(0, NULL
));
15749 secObj
= Tcl_NewListObj(0, NULL
);
15750 for(sm
= mail_list
; sm
!= NULL
&& sm
->name
!= NULL
; sm
++){
15751 if(sm
->name
[0] == '\0') /* can't happen */
15753 Tcl_ListObjAppendElement(interp
, secObj
, Tcl_NewStringObj(sm
->name
, -1));
15756 Tcl_ListObjAppendElement(interp
, resObj
, secObj
);
15758 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewListObj(0, NULL
));
15760 free_folder_list(ctxt
);
15762 if((sm
= mail_list
) != NULL
){
15764 fs_give((void **)&(sm
->name
));
15768 fs_give((void **)&mail_list
);
15776 hex_colorstr(char *hexcolor
, char *str
)
15778 char *tstr
, *p
, *p2
, tbuf
[256];
15781 strcpy(hexcolor
, "000000");
15782 tstr
= color_to_asciirgb(str
);
15784 p2
= strindex(p
, ',');
15785 if(p2
== NULL
) return 0;
15786 strncpy(tbuf
, p
, min(50, p2
-p
));
15788 sprintf(hexcolor
, "%2.2x", i
);
15790 p2
= strindex(p
, ',');
15791 if(p2
== NULL
) return 0;
15792 strncpy(tbuf
, p
, min(50, p2
-p
));
15794 sprintf(hexcolor
+2, "%2.2x", i
);
15796 strncpy(tbuf
, p
, 50);
15798 sprintf(hexcolor
+4, "%2.2x", i
);
15806 if(ch
>= '0' && ch
<= '9')
15808 else if (ch
>= 'A' && ch
<= 'F')
15809 return (10 + (ch
- 'A'));
15810 else if (ch
>= 'a' && ch
<= 'f')
15811 return (10 + (ch
- 'a'));
15816 ascii_colorstr(char *acolor
, char *hexcolor
)
15820 if(strlen(hexcolor
) > 6) return 1;
15822 if((hv
= hexval(hexcolor
[0])) == -1) return 1;
15824 if((hv
= hexval(hexcolor
[1])) == -1) return 1;
15826 sprintf(acolor
, "%3.3d,", i
);
15828 if((hv
= hexval(hexcolor
[2])) == -1) return 1;
15830 if((hv
= hexval(hexcolor
[3])) == -1) return 1;
15832 sprintf(acolor
+4, "%3.3d,", i
);
15834 if((hv
= hexval(hexcolor
[4])) == -1) return 1;
15836 if((hv
= hexval(hexcolor
[5])) == -1) return 1;
15838 sprintf(acolor
+8, "%3.3d", i
);
15845 peRandomString(char *b
, int l
, int f
)
15847 static char *kb
= "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
15854 for(j
= 0; j
< ((sizeof(long) * 8) / 5); j
++){
15861 case PRS_LOWER_CASE
:
15862 *s
++ = (char) tolower((unsigned char) kb
[(n
& 0x1F)]);
15865 case PRS_MIXED_CASE
:
15867 *s
++ = (char) tolower((unsigned char) kb
[(n
& 0x1F)]);
15872 *s
++ = kb
[(n
& 0x1F)];
15883 peAppendMsg(MAILSTREAM
*stream
, void *data
, char **flags
, char **date
, STRING
**message
)
15885 char *t
,*t1
,tmp
[MAILTMPLEN
];
15888 APPEND_PKG
*ap
= (APPEND_PKG
*) data
;
15889 *flags
= *date
= NIL
; /* assume no flags or date */
15890 if (ap
->flags
) fs_give ((void **) &ap
->flags
);
15891 if (ap
->date
) fs_give ((void **) &ap
->date
);
15892 mail_gc (ap
->stream
,GC_TEXTS
);
15893 if (++ap
->msgno
<= ap
->msgmax
) {
15894 /* initialize flag string */
15895 memset (t
= tmp
,0,MAILTMPLEN
);
15896 /* output system flags */
15897 if ((elt
= mail_elt (ap
->stream
,ap
->msgno
))->seen
) {strncat (t
," \\Seen", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15898 if (elt
->deleted
) {strncat (t
," \\Deleted", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15899 if (elt
->flagged
) {strncat (t
," \\Flagged", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15900 if (elt
->answered
) {strncat (t
," \\Answered", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15901 if (elt
->draft
) {strncat (t
," \\Draft", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15902 if ((u
= elt
->user_flags
) != 0L) do /* any user flags? */
15903 if ((MAILTMPLEN
- ((t
+= strlen (t
)) - tmp
)) > (long)
15905 (t1
= ap
->stream
->user_flags
[find_rightmost_bit (&u
)]))) {
15906 if(t
-tmp
< sizeof(tmp
))
15907 *t
++ = ' '; /* space delimiter */
15908 strncpy (t
,t1
,sizeof(tmp
)-(t
-tmp
)); /* copy the user flag */
15910 while (u
); /* until no more user flags */
15911 tmp
[sizeof(tmp
)-1] = '\0';
15912 *flags
= ap
->flags
= cpystr (tmp
+ 1);
15913 *date
= ap
->date
= cpystr (mail_date (tmp
,elt
));
15914 *message
= ap
->message
; /* message stringstruct */
15915 INIT (ap
->message
,mstring
,(void *) ap
,elt
->rfc822_size
);
15917 else *message
= NIL
; /* all done */
15922 /* Initialize file string structure for file stringstruct
15923 * Accepts: string structure
15924 * pointer to message data structure
15929 ms_init(STRING
*s
, void *data
, unsigned long size
)
15931 APPEND_PKG
*md
= (APPEND_PKG
*) data
;
15932 s
->data
= data
; /* note stream/msgno and header length */
15933 mail_fetchheader_full (md
->stream
,md
->msgno
,NIL
,&s
->data1
,FT_PREFETCHTEXT
);
15934 mail_fetchtext_full (md
->stream
,md
->msgno
,&s
->size
,NIL
);
15935 s
->size
+= s
->data1
; /* header + body size */
15940 /* Get next character from file stringstruct
15941 * Accepts: string structure
15942 * Returns: character, string structure chunk refreshed
15947 char c
= *s
->curpos
++; /* get next byte */
15948 SETPOS (s
,GETPOS (s
)); /* move to next chunk */
15949 return c
; /* return the byte */
15953 /* Set string pointer position for file stringstruct
15954 * Accepts: string structure
15958 ms_setpos(STRING
*s
, unsigned long i
)
15960 APPEND_PKG
*md
= (APPEND_PKG
*) s
->data
;
15961 if (i
< s
->data1
) { /* want header? */
15962 s
->chunk
= mail_fetchheader (md
->stream
,md
->msgno
);
15963 s
->chunksize
= s
->data1
; /* header length */
15964 s
->offset
= 0; /* offset is start of message */
15966 else if (i
< s
->size
) { /* want body */
15967 s
->chunk
= mail_fetchtext (md
->stream
,md
->msgno
);
15968 s
->chunksize
= s
->size
- s
->data1
;
15969 s
->offset
= s
->data1
; /* offset is end of header */
15971 else { /* off end of message */
15972 s
->chunk
= NIL
; /* make sure that we crack on this then */
15973 s
->chunksize
= 1; /* make sure SNX cracks the right way... */
15976 /* initial position and size */
15977 s
->curpos
= s
->chunk
+ (i
-= s
->offset
);
15978 s
->cursize
= s
->chunksize
- i
;
15983 remote_pinerc_failure(void)
15985 snprintf(wps_global
->last_error
, sizeof(wps_global
->last_error
), "%s",
15986 wps_global
->c_client_error
[0]
15987 ? wps_global
->c_client_error
15988 : _("Unable to read remote configuration"));
15994 peWebAlpinePrefix(void)
16000 void peNewMailAnnounce(MAILSTREAM
*stream
, long n
, long t_nm_count
){
16001 char subject
[MAILTMPLEN
+1], subjtext
[MAILTMPLEN
+1], from
[MAILTMPLEN
+1],
16002 *folder
= NULL
, intro
[MAILTMPLEN
+1];
16004 ENVELOPE
*e
= NULL
;
16007 if(n
&& (resObj
= Tcl_NewListObj(0, NULL
)) != NULL
){
16009 Tcl_ListObjAppendElement(peED
.interp
, resObj
, Tcl_NewLongObj(number
= sp_mail_since_cmd(stream
)));
16010 Tcl_ListObjAppendElement(peED
.interp
, resObj
, Tcl_NewLongObj(mail_uid(stream
, n
)));
16013 e
= pine_mail_fetchstructure(stream
, n
, NULL
);
16015 if(sp_flagged(stream
, SP_INBOX
))
16018 folder
= STREAMNAME(stream
);
16019 if(folder
[0] == '?' && folder
[1] == '\0')
16024 format_new_mail_msg(folder
, number
, e
, intro
, from
, subject
, subjtext
, sizeof(intro
));
16026 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
,
16027 "%s%s%s%.80s%.80s", intro
,
16028 from
? ((number
> 1L) ? " Most recent f" : " F") : "",
16029 from
? "rom " : "",
16033 Tcl_ListObjAppendElement(peED
.interp
, resObj
, Tcl_NewStringObj(wtmp_20k_buf
,-1));
16035 Tcl_ListObjAppendElement(peED
.interp
, Tcl_GetObjResult(peED
.interp
), resObj
);
16040 /* * * * * * * * * RSS 2.0 Support Routines * * * * * * * * * * * */
16043 * PERssCmd - RSS TCL interface
16046 PERssCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
16050 dprint((2, "PERssCmd"));
16053 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
16056 s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
16059 if(!strcmp(s1
, "news")){
16060 return(peRssReturnFeed(interp
, "news", wps_global
->VAR_RSS_NEWS
));
16062 else if(!strcmp(s1
, "weather")){
16063 return(peRssReturnFeed(interp
, "weather", wps_global
->VAR_RSS_WEATHER
));
16067 Tcl_SetResult(interp
, "Unknown PERss command", TCL_STATIC
);
16072 * peRssReturnFeed - fetch feed contents and package Tcl response
16075 peRssReturnFeed(Tcl_Interp
*interp
, char *type
, char *link
)
16078 char *errstr
= "UNKNOWN";
16081 wps_global
->c_client_error
[0] = '\0';
16083 if((feed
= peRssFeed(interp
, type
, link
)) != NULL
)
16084 return(peRssPackageFeed(interp
, feed
));
16086 if(wps_global
->mm_log_error
)
16087 errstr
= wps_global
->c_client_error
;
16090 errstr
= "missing setting";
16092 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s feed fail: %s", type
, errstr
);
16093 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
16098 * peRssPackageFeed - build a list of feed item elements
16100 * LIST ORDER: {title} {link} {description} {image}
16103 peRssPackageFeed(Tcl_Interp
*interp
, RSS_FEED_S
*feed
)
16107 for(item
= feed
->items
; item
; item
= item
->next
)
16108 if(peAppListF(interp
, Tcl_GetObjResult(interp
), "%s %s %s %s",
16109 (item
->title
&& *item
->title
)? item
->title
: "Feed Provided No Title",
16110 item
->link
? item
->link
: "",
16111 item
->description
? item
->description
: "",
16112 feed
->image
? feed
->image
: "") != TCL_OK
)
16120 * peRssFeed - return cached feed struct or fetch a new one
16123 peRssFeed(Tcl_Interp
*interp
, char *type
, char *link
)
16125 int i
, cache_l
, cp_ref
;
16126 time_t now
= time(0);
16127 RSS_FEED_S
*feed
= NULL
;
16128 RSS_CACHE_S
*cache
, *cp
;
16129 static RSS_CACHE_S news_cache
[RSS_NEWS_CACHE_SIZE
], weather_cache
[RSS_WEATHER_CACHE_SIZE
];
16131 if(!strucmp(type
,"news")){
16132 cache
= &news_cache
[0];
16133 cache_l
= RSS_NEWS_CACHE_SIZE
;
16136 cache
= &weather_cache
[0];
16137 cache_l
= RSS_WEATHER_CACHE_SIZE
;
16140 /* search/purge cache */
16141 for(i
= 0; i
< cache_l
; i
++)
16143 if(now
> cache
[i
].stale
){
16144 peRssClearCacheEntry(&cache
[i
]);
16146 else if(!strcmp(link
, cache
[i
].link
)){
16147 cache
[i
].referenced
++;
16148 return(cache
[i
].feed
); /* HIT! */
16152 if((feed
= peRssFetch(interp
, link
)) != NULL
){
16153 /* find cache slot, and insert feed into cache */
16154 for(i
= 0, cp_ref
= 0; i
< cache_l
; i
++)
16155 if(!cache
[i
].feed
){
16159 else if(cache
[i
].referenced
>= cp_ref
)
16163 cp
= &cache
[0]; /* failsafe */
16165 peRssClearCacheEntry(cp
); /* make sure */
16167 cp
->link
= cpystr(link
);
16169 cp
->referenced
= 0;
16170 cp
->stale
= now
+ (((feed
->ttl
> 0) ? feed
->ttl
: 60) * 60);
16177 * peRssFetch - follow the provided link an return the resulting struct
16180 peRssFetch(Tcl_Interp
*interp
, char *link
)
16182 char *scheme
= NULL
, *loc
= NULL
, *path
= NULL
, *parms
= NULL
, *query
= NULL
, *frag
= NULL
;
16183 char *buffer
= NULL
, *bp
, *p
, *q
;
16185 unsigned long port
= 0L, buffer_len
= 0L;
16186 time_t theirdate
= 0;
16187 STORE_S
*feed_so
= NULL
;
16188 TCPSTREAM
*tcp_stream
;
16192 rfc1808_tokens(link
, &scheme
, &loc
, &path
, &parms
, &query
, &frag
);
16193 if(scheme
&& loc
&& path
){
16194 if((p
= strchr(loc
,':')) != NULL
){
16196 while(*p
&& isdigit((unsigned char) *p
))
16197 port
= ((port
* 10) + (*p
++ - '0'));
16200 Tcl_SetResult(interp
, "Bad RSS port number", TCL_STATIC
);
16201 peRssComponentFree(&scheme
,&loc
,&path
,&parms
,&query
,&frag
);
16206 if(scheme
&& !strucmp(scheme
, "feed")){
16207 fs_give((void **) &scheme
);
16208 scheme
= cpystr("http");
16211 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long) 5);
16212 tcp_stream
= tcp_open (loc
, scheme
, port
| NET_NOOPENTIMEOUT
);
16213 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long) 30);
16215 if(tcp_stream
!= NULL
){
16218 snprintf(wtmp_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",
16219 path
, parms
? ":" : "", parms
? parms
: "",
16220 query
? "?" : "", query
? query
: "", loc
,
16221 ALPINE_VERSION
, SYSTYPE
, get_alpine_revision_string(rev
, sizeof(rev
)));
16223 mail_parameters(NULL
, SET_WRITETIMEOUT
, (void *)(long) 5);
16224 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long) 5);
16226 if(tcp_sout(tcp_stream
, wtmp_20k_buf
, strlen(wtmp_20k_buf
))){
16227 int ok
= 0, chunked
= FALSE
;
16229 while((p
= tcp_getline(tcp_stream
)) != NULL
){
16232 if(strucmp(p
,"HTTP/1.1 200 OK")){
16233 fs_give((void **) &p
);
16237 else if(*p
== '\0'){ /* first blank line, start of body */
16238 if(buffer
|| feed_so
){
16239 fs_give((void **) &p
);
16244 buffer
= fs_get(buffer_len
+ 16);
16245 if(!tcp_getbuffer(tcp_stream
, buffer_len
, buffer
))
16246 fs_give((void **) &buffer
);
16248 fs_give((void **) &p
);
16251 else if((feed_so
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
16252 fs_give((void **) &p
);
16256 else if(feed_so
){ /* collect body */
16258 int chunk_len
= 0, gotbuf
;
16260 /* first line is chunk size in hex */
16261 for(q
= p
; *q
&& isxdigit((unsigned char) *q
); q
++)
16262 chunk_len
= (chunk_len
* 16) + XDIGIT2C(*q
);
16264 if(chunk_len
> 0){ /* collect chunk */
16265 char *tbuf
= fs_get(chunk_len
+ 16);
16266 gotbuf
= tcp_getbuffer(tcp_stream
, chunk_len
, tbuf
);
16268 so_nputs(feed_so
, tbuf
, chunk_len
);
16270 fs_give((void **) &tbuf
);
16273 fs_give((void **) &p
);
16278 /* collect trailing CRLF */
16279 gotbuf
= ((q
= tcp_getline(tcp_stream
)) != NULL
&& *q
== '\0');
16281 fs_give((void **) &q
);
16283 if(chunk_len
== 0 || !gotbuf
){
16284 fs_give((void **) &p
);
16289 so_puts(feed_so
, p
);
16291 else{ /* in header, grok fields */
16292 if((q
= strchr(p
,':')) != NULL
){
16296 while(isspace((unsigned char ) *q
))
16299 /* content-length */
16300 if(l
== 4 && !strucmp(p
, "date")){
16301 theirdate
= date_to_local_time_t(q
);
16303 else if(l
== 7 && !strucmp(p
, "expires")){
16304 time_t expires
= date_to_local_time_t(q
) - ((theirdate
> 0) ? theirdate
: time(0));
16306 if(expires
> 0 && expires
< (8 * 60 * 60))
16309 else if(l
== 12 && !strucmp(p
, "content-type")
16310 && struncmp(q
,"text/xml", 8)
16311 && struncmp(q
,"application/xhtml+xml", 21)
16312 && struncmp(q
,"application/rss+xml", 19)
16313 && struncmp(q
,"application/xml", 15)){
16314 fs_give((void **) &p
);
16317 else if(l
== 13 && !strucmp(p
, "cache-control")){
16318 if(!struncmp(q
,"max-age=",8)){
16321 for(q
+= 8; *q
&& isdigit((unsigned char) *q
); q
++)
16322 secs
= ((secs
* 10) + (*q
- '0'));
16328 else if(l
== 14 && !strucmp(p
,"content-length")){
16329 while(*q
&& isdigit((unsigned char) *q
))
16330 buffer_len
= ((buffer_len
* 10) + (*q
++ - '0'));
16333 fs_give((void **) &p
);
16337 else if(l
== 17 && !strucmp(p
, "transfer-encoding")){
16338 if(!struncmp(q
,"chunked", 7)){
16341 else{ /* unknown encoding */
16342 fs_give((void **) &p
);
16349 fs_give((void **) &p
);
16353 Tcl_SetResult(interp
, "RSS send failure", TCL_STATIC
);
16354 peRssComponentFree(&scheme
,&loc
,&path
,&parms
,&query
,&frag
);
16357 tcp_close(tcp_stream
);
16358 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long) 60);
16359 mail_parameters(NULL
, SET_WRITETIMEOUT
, (void *)(long) 60);
16360 peRssComponentFree(&scheme
,&loc
,&path
,&parms
,&query
,&frag
);
16363 buffer
= (char *) so_text(feed_so
);
16364 buffer_len
= (int) so_tell(feed_so
);
16367 if(buffer
&& buffer_len
){
16373 /* grok response */
16374 bucket
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
16375 gf_set_readc(&gc
, buffer
, buffer_len
, CharStar
, 0);
16376 gf_set_so_writec(&pc
, bucket
);
16378 gf_link_filter(gf_html2plain
, gf_html2plain_rss_opt(&feed
,0));
16379 if((err
= gf_pipe(gc
, pc
)) != NULL
){
16380 gf_html2plain_rss_free(&feed
);
16381 Tcl_SetResult(interp
, "RSS connection failure", TCL_STATIC
);
16389 fs_give((void **) &buffer
);
16394 Tcl_SetResult(interp
, "RSS response error", TCL_STATIC
);
16397 Tcl_SetResult(interp
, "RSS connection failure", TCL_STATIC
);
16400 Tcl_SetResult(interp
, "RSS feed missing scheme", TCL_STATIC
);
16403 Tcl_SetResult(interp
, "No RSS Feed Defined", TCL_STATIC
);
16410 peRssComponentFree(char **scheme
,char **loc
,char **path
,char **parms
,char **query
,char **frag
)
16412 if(scheme
) fs_give((void **) scheme
);
16413 if(loc
) fs_give((void **) loc
);
16414 if(path
) fs_give((void **) path
);
16415 if(parms
) fs_give((void **) parms
);
16416 if(query
) fs_give((void **) query
);
16417 if(frag
) fs_give((void **) frag
);
16421 peRssClearCacheEntry(RSS_CACHE_S
*entry
)
16425 fs_give((void **) &entry
->link
);
16427 gf_html2plain_rss_free(&entry
->feed
);
16428 memset(entry
, 0, sizeof(RSS_CACHE_S
));