1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: alpined.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $";
5 /* ========================================================================
6 * Copyright 2006-2008 University of Washington
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * ========================================================================
17 /* ========================================================================
18 Implement alpine TCL interfaces. Execute TCL interfaces
19 via interpreter reading commands and writing results over
21 ======================================================================== */
27 #include "../../../c-client/c-client.h"
28 #include "../../../c-client/imap4r1.h"
30 #include "../../../pith/osdep/color.h" /* color support library */
31 #include "../../../pith/osdep/canaccess.h"
32 #include "../../../pith/osdep/temp_nam.h"
33 #include "../../../pith/osdep/collate.h"
34 #include "../../../pith/osdep/filesize.h"
35 #include "../../../pith/osdep/writ_dir.h"
36 #include "../../../pith/osdep/err_desc.h"
38 #include "../../../pith/stream.h"
39 #include "../../../pith/context.h"
40 #include "../../../pith/state.h"
41 #include "../../../pith/msgno.h"
42 #include "../../../pith/debug.h"
43 #include "../../../pith/init.h"
44 #include "../../../pith/conf.h"
45 #include "../../../pith/conftype.h"
46 #include "../../../pith/detoken.h"
47 #include "../../../pith/flag.h"
48 #include "../../../pith/help.h"
49 #include "../../../pith/remote.h"
50 #include "../../../pith/status.h"
51 #include "../../../pith/mailcmd.h"
52 #include "../../../pith/savetype.h"
53 #include "../../../pith/save.h"
54 #include "../../../pith/reply.h"
55 #include "../../../pith/sort.h"
56 #include "../../../pith/ldap.h"
57 #include "../../../pith/addrbook.h"
58 #include "../../../pith/ablookup.h"
59 #include "../../../pith/takeaddr.h"
60 #include "../../../pith/bldaddr.h"
61 #include "../../../pith/copyaddr.h"
62 #include "../../../pith/thread.h"
63 #include "../../../pith/folder.h"
64 #include "../../../pith/mailview.h"
65 #include "../../../pith/indxtype.h"
66 #include "../../../pith/icache.h"
67 #include "../../../pith/mailindx.h"
68 #include "../../../pith/mailpart.h"
69 #include "../../../pith/mimedesc.h"
70 #include "../../../pith/detach.h"
71 #include "../../../pith/newmail.h"
72 #include "../../../pith/charset.h"
73 #include "../../../pith/util.h"
74 #include "../../../pith/rfc2231.h"
75 #include "../../../pith/string.h"
76 #include "../../../pith/send.h"
77 #include "../../../pith/options.h"
78 #include "../../../pith/list.h"
79 #include "../../../pith/mimetype.h"
80 #include "../../../pith/mailcap.h"
81 #include "../../../pith/sequence.h"
82 #include "../../../pith/smime.h"
83 #include "../../../pith/url.h"
84 #include "../../../pith/charconv/utf8.h"
97 * Fake screen dimension for word wrap and such
99 #define FAKE_SCREEN_WIDTH 80
100 #define FAKE_SCREEN_LENGTH 24
103 * Arbitrary minimum display width (in characters)
105 #define MIN_SCREEN_COLS 20
109 * Maximum number of lines allowed in signatures
111 #define SIG_MAX_LINES 24
112 #define SIG_MAX_COLS 1024
116 * Number of seconds we'll wait before we assume the client has wondered
117 * on to more interesting content
119 #define PE_INPUT_TIMEOUT 1800
123 * Posting error length max
125 #define WP_MAX_POST_ERROR 128
129 * AUTH Response Tokens
131 #define AUTH_EMPTY_STRING "NOPASSWD"
132 #define AUTH_FAILURE_STRING "BADPASSWD"
135 * CERT Response Tokens
137 #define CERT_QUERY_STRING "CERTQUERY"
138 #define CERT_FAILURE_STRING "CERTFAIL"
142 * Charset used within alpined and to communicate with alpined
143 * Note: posting-charset still respected
145 #define WP_INTERNAL_CHARSET "UTF-8"
149 * Globals referenced throughout pine...
151 struct pine
*wps_global
; /* THE global variable! */
157 long gPeITop
, gPeICount
;
159 long gPeInputTimeout
= PE_INPUT_TIMEOUT
;
160 long gPEAbandonTimeout
= 0;
164 * Authorization issues
166 int peNoPassword
, peCredentialError
;
167 int peCertFailure
, peCertQuery
;
168 char peCredentialRequestor
[CRED_REQ_SIZE
];
174 CONTEXT_S
*config_context_list
;
176 STRLIST_S
*peCertHosts
;
178 bitmap_t changed_feature_list
;
179 #define F_CH_ON(feature) (bitnset((feature),changed_feature_list))
180 #define F_CH_OFF(feature) (!F_CH_ON(feature))
181 #define F_CH_TURN_ON(feature) (setbitn((feature),changed_feature_list))
182 #define F_CH_TURN_OFF(feature) (clrbitn((feature),changed_feature_list))
183 #define F_CH_SET(feature,value) ((value) ? F_CH_TURN_ON((feature)) \
184 : F_CH_TURN_OFF((feature)))
187 typedef struct _status_msg
{
193 struct _status_msg
*next
;
196 static STATMSG_S
*peStatList
;
198 typedef struct _composer_attachment
{
219 struct _composer_attachment
*next
;
222 static COMPATT_S
*peCompAttach
;
227 typedef struct _msg_data
{
235 int postop_fcc_no_attach
;
238 int (*postfunc
)(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *);
241 unsigned qualified_addrs
:1;
246 * locally global structure to keep track of various bits of state
247 * needed to collect filtered output
249 static struct _embedded_data
{
270 typedef struct _rss_cache_s
{
277 #define RSS_NEWS_CACHE_SIZE 1
278 #define RSS_WEATHER_CACHE_SIZE 1
282 WPLDAP_S
*wpldap_global
;
286 * random string generator flags
288 #define PRS_NONE 0x0000
289 #define PRS_LOWER_CASE 0x0001
290 #define PRS_UPPER_CASE 0x0002
291 #define PRS_MIXED_CASE 0x0004
294 * peSaveWork flag definitions
296 #define PSW_NONE 0x00
297 #define PSW_COPY 0x01
298 #define PSW_MOVE 0x02
301 * Message Collector flags
303 #define PMC_NONE 0x00
304 #define PMC_FORCE_QUAL 0x01
305 #define PMC_PRSRV_ATT 0x02
308 * length of thread info string
310 #define WP_MAX_THRD_S 64
313 * static buf size for putenv() if necessary
315 #define PUTENV_MAX 64
319 /*----------------------------------------------------------------------
320 General use big buffer. It is used in the following places:
321 compose_mail: while parsing header of postponed message
322 append_message2: while writing header into folder
323 q_status_messageX: while doing printf formatting
324 addr_book: Used to return expanded address in. (Can only use here
325 because mm_log doesn't q_status on PARSE errors !)
326 alpine.c: When address specified on command line
327 init.c: When expanding variable values
328 and many many more...
331 char wtmp_20k_buf
[20480];
336 /* Internal prototypes */
337 void peReturn(int, char *, const char *);
338 int peWrite(int, char *);
339 char *peCreateUserContext(Tcl_Interp
*, char *, char *, char *);
340 void peDestroyUserContext(struct pine
**);
341 char *peLoadConfig(struct pine
*);
342 int peCreateStream(Tcl_Interp
*, CONTEXT_S
*, char *, int);
343 void peDestroyStream(struct pine
*);
344 void pePrepareForAuthException(void);
345 char *peAuthException(void);
346 void peInitVars(struct pine
*);
347 int peSelect(Tcl_Interp
*, int, Tcl_Obj
**, int);
348 int peSelectNumber(Tcl_Interp
*, int, Tcl_Obj
**, int);
349 int peSelectDate(Tcl_Interp
*, int, Tcl_Obj
**, int);
350 int peSelectText(Tcl_Interp
*, int, Tcl_Obj
**, int);
351 int peSelectStatus(Tcl_Interp
*, int, Tcl_Obj
**, int);
352 char *peSelValTense(Tcl_Obj
*);
353 char *peSelValYear(Tcl_Obj
*);
354 char *peSelValMonth(Tcl_Obj
*);
355 char *peSelValDay(Tcl_Obj
*);
356 int peSelValCase(Tcl_Obj
*);
357 int peSelValField(Tcl_Obj
*);
358 int peSelValFlag(Tcl_Obj
*);
359 int peSelected(Tcl_Interp
*, int, Tcl_Obj
**, int);
360 int peSelectError(Tcl_Interp
*, char *);
361 int peApply(Tcl_Interp
*, int, Tcl_Obj
**);
362 char *peApplyFlag(MAILSTREAM
*, MSGNO_S
*, char, int, long *);
363 int peApplyError(Tcl_Interp
*, char *);
364 int peIndexFormat(Tcl_Interp
*);
365 int peAppendIndexParts(Tcl_Interp
*, imapuid_t
, Tcl_Obj
*, int *);
366 int peAppendIndexColor(Tcl_Interp
*, imapuid_t
, Tcl_Obj
*, int *);
367 int peMessageStatusBits(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
368 char *peMsgStatBitString(struct pine
*, MAILSTREAM
*, MSGNO_S
*, long, long, long, int *);
369 Tcl_Obj
*peMsgStatNameList(Tcl_Interp
*, struct pine
*, MAILSTREAM
*, MSGNO_S
*, long, long, long, int *);
370 int peNewMailResult(Tcl_Interp
*);
371 int peMessageSize(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
372 int peMessageDate(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
373 int peMessageSubject(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
374 int peMessageFromAddr(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
375 int peMessageToAddr(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
376 int peMessageCcAddr(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
377 int peMessageField(Tcl_Interp
*, imapuid_t
, char *);
378 int peMessageStatus(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
379 int peMessageCharset(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
380 int peMessageBounce(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
381 int peMessageSpamNotice(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
382 char *peSendSpamReport(long, char *, char *, char *);
383 int peMsgnoFromUID(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
384 int peMessageText(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
385 int peMessageHeader(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
386 void peFormatEnvelope(MAILSTREAM
*, long, char *, ENVELOPE
*, gf_io_t
, long, char *, int);
387 void peFormatEnvelopeAddress(MAILSTREAM
*, long, char *, char *, ADDRESS
*, int, char *, gf_io_t
);
388 void peFormatEnvelopeNewsgroups(char *, char *, int, gf_io_t
);
389 void peFormatEnvelopeText(char *, char *);
390 int peMessageAttachments(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
391 int peMessageBody(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
392 int peMessagePartFromCID(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
393 int peLocateBodyByCID(char *, char *, BODY
*);
394 char *peColorStr(char *, char *);
395 int peInterpWritec(int);
396 int peInterpFlush(void);
397 int peNullWritec(int);
398 void peGetMimeTyping(BODY
*, Tcl_Obj
**, Tcl_Obj
**, Tcl_Obj
**, Tcl_Obj
**);
399 int peGetFlag(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
400 int peIsFlagged(MAILSTREAM
*, imapuid_t
, char *);
401 int peSetFlag(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
402 int peMsgSelect(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
403 int peReplyHeaders(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
404 int peAppListF(Tcl_Interp
*, Tcl_Obj
*, char *, ...);
405 void pePatAppendID(Tcl_Interp
*, Tcl_Obj
*, PAT_S
*);
406 void pePatAppendPattern(Tcl_Interp
*, Tcl_Obj
*, PAT_S
*);
407 char *pePatStatStr(int);
408 int peReplyText(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
409 int peSoStrToList(Tcl_Interp
*, Tcl_Obj
*, STORE_S
*);
410 int peForwardHeaders(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
411 int peForwardText(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
412 int peDetach(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
413 int peAttachInfo(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
414 int peSaveDefault(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
415 int peSaveWork(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**, long);
416 int peSave(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
417 int peCopy(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
418 int peMove(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
419 int peGotoDefault(Tcl_Interp
*, imapuid_t
, Tcl_Obj
**);
420 int peTakeaddr(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
421 int peTakeFrom(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
422 int peAddSuggestedContactInfo(Tcl_Interp
*, Tcl_Obj
*, ADDRESS
*);
423 int peReplyQuote(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
424 long peMessageNumber(imapuid_t
);
425 long peSequenceNumber(imapuid_t
);
426 int peMsgCollector(Tcl_Interp
*, int, Tcl_Obj
**,
427 int (*)(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *), long);
428 int peMsgCollected(Tcl_Interp
*, MSG_COL_S
*, char *, long);
429 void peMsgSetParm(PARAMETER
**, char *, char *);
430 Tcl_Obj
*peMsgAttachCollector(Tcl_Interp
*, BODY
*);
431 int peFccAppend(Tcl_Interp
*, Tcl_Obj
*, char *, int);
432 int peDoPost(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *);
433 int peDoPostpone(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *);
434 int peWriteSig (Tcl_Interp
*, char *, Tcl_Obj
**);
435 int peInitAddrbooks(Tcl_Interp
*, int);
436 int peRuleStatVal(char *, int *);
437 int peRuleSet(Tcl_Interp
*, Tcl_Obj
**);
438 int peAppendCurrentSort(Tcl_Interp
*interp
);
439 int peAppendDefaultSort(Tcl_Interp
*interp
);
441 ADDRESS
*peAEToAddress(AdrBk_Entry
*);
442 char *peAEFcc(AdrBk_Entry
*);
444 NAMEVAL_S
*sort_key_rules(int);
445 NAMEVAL_S
*wp_indexheight_rules(int);
446 PINEFIELD
*peCustomHdrs(void);
447 STATMSG_S
*sml_newmsg(int, char *);
448 char *sml_getmsg(void);
449 char **sml_getmsgs(void);
452 int peLdapQueryResults(Tcl_Interp
*);
453 int peLdapStrlist(Tcl_Interp
*, Tcl_Obj
*, struct berval
**);
454 int init_ldap_pname(struct pine
*);
455 #endif /* ENABLE_LDAP */
456 char *strqchr(char *, int, int *, int);
457 Tcl_Obj
*wp_prune_folders(CONTEXT_S
*, char *, int, char *,
458 unsigned, int *, int, Tcl_Interp
*);
459 int hex_colorstr(char *, char *);
461 int ascii_colorstr(char *, char *);
462 COMPATT_S
*peNewAttach(void);
463 void peFreeAttach(COMPATT_S
**);
464 COMPATT_S
*peGetAttachID(char *);
465 char *peFileAttachID(char *, char *, char *, char *, char *, int);
466 char *peBodyAttachID(BODY
*);
467 void peBodyMoveContents(BODY
*, BODY
*);
468 int peClearAttachID(char *);
469 char *peRandomString(char *, int, int);
470 void ms_init(STRING
*, void *, unsigned long);
471 char ms_next(STRING
*);
472 void ms_setpos(STRING
*, unsigned long);
473 long peAppendMsg(MAILSTREAM
*, void *, char **, char **, STRING
**);
474 int remote_pinerc_failure(void);
475 char *peWebAlpinePrefix(void);
476 void peNewMailAnnounce(MAILSTREAM
*, long, long);
477 int peMessageNeedPassphrase(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
478 int peRssReturnFeed(Tcl_Interp
*, char *, char *);
479 int peRssPackageFeed(Tcl_Interp
*, RSS_FEED_S
*);
480 RSS_FEED_S
*peRssFeed(Tcl_Interp
*, char *, char *);
481 RSS_FEED_S
*peRssFetch(Tcl_Interp
*, char *);
482 void peRssComponentFree(char **,char **,char **,char **,char **,char **);
483 void peRssClearCacheEntry(RSS_CACHE_S
*);
486 /* Prototypes for Tcl-exported methods */
487 int PEInit(Tcl_Interp
*interp
, char *);
488 void PEExitCleanup(ClientData
);
489 int PEInfoCmd(ClientData clientData
, Tcl_Interp
*interp
,
490 int objc
, Tcl_Obj
*CONST objv
[]);
491 int PEConfigCmd(ClientData clientData
, Tcl_Interp
*interp
,
492 int objc
, Tcl_Obj
*CONST objv
[]);
493 int PEDebugCmd(ClientData clientData
, Tcl_Interp
*interp
,
494 int objc
, Tcl_Obj
*CONST objv
[]);
495 int PESessionCmd(ClientData clientData
, Tcl_Interp
*interp
,
496 int objc
, Tcl_Obj
*CONST objv
[]);
497 int PEMailboxCmd(ClientData clientData
, Tcl_Interp
*interp
,
498 int objc
, Tcl_Obj
*CONST objv
[]);
499 int PEThreadCmd(ClientData clientData
, Tcl_Interp
*interp
,
500 int objc
, Tcl_Obj
*CONST objv
[]);
501 int PEMessageCmd(ClientData clientData
, Tcl_Interp
*interp
,
502 int objc
, Tcl_Obj
*CONST objv
[]);
503 int PEFolderCmd(ClientData clientData
, Tcl_Interp
*interp
,
504 int objc
, Tcl_Obj
*CONST objv
[]);
505 int PEComposeCmd(ClientData clientData
, Tcl_Interp
*interp
,
506 int objc
, Tcl_Obj
*CONST objv
[]);
507 int PEPostponeCmd(ClientData clientData
, Tcl_Interp
*interp
,
508 int objc
, Tcl_Obj
*CONST objv
[]);
509 int PEAddressCmd(ClientData clientData
, Tcl_Interp
*interp
,
510 int objc
, Tcl_Obj
*CONST objv
[]);
511 int PEClistCmd(ClientData clientData
, Tcl_Interp
*interp
,
512 int objc
, Tcl_Obj
*CONST objv
[]);
513 int PELdapCmd(ClientData clientData
, Tcl_Interp
*interp
,
514 int objc
, Tcl_Obj
*CONST objv
[]);
515 int PERssCmd(ClientData clientData
, Tcl_Interp
*interp
,
516 int objc
, Tcl_Obj
*CONST objv
[]);
519 typedef struct append_pkg
{
520 MAILSTREAM
*stream
; /* source stream */
521 unsigned long msgno
; /* current message number */
522 unsigned long msgmax
; /* maximum message number */
523 char *flags
; /* current flags */
524 char *date
; /* message internal date */
525 STRING
*message
; /* stringstruct of message */
528 STRINGDRIVER mstring
= {
529 ms_init
, /* initialize string structure */
530 ms_next
, /* get next byte in string structure */
531 ms_setpos
/* set position in string structure */
535 /*----------------------------------------------------------------------
536 main routine -- entry point
538 Args: argv, argc -- The command line arguments
541 Setup c-client drivers and dive into TCL interpreter engine
546 main(int argc
, char *argv
[])
548 int ev
= 1, s
, cs
, n
, co
, o
, l
, bl
= 256, argerr
;
549 char *buf
, sname
[256];
550 struct sockaddr_un name
;
553 extern AUTHENTICATOR auth_gss_proxy
;
556 srandom(getpid() + time(0));
558 /*----------------------------------------------------------------------
560 ----------------------------------------------------------------------*/
563 * NO LOCAL DRIVERS ALLOWED
564 * For this to change pintecld *MUST* be running under the user's UID and
565 * and signal.[ch] need to get fixed to handle KOD rather than change
568 mail_link (&imapdriver
); /* link in the imap driver */
569 mail_link (&unixdriver
); /* link in the unix driver */
570 mail_link (&dummydriver
); /* link in the dummy driver */
572 /* link authentication drivers */
574 auth_link (&auth_gss_proxy
); /* pubcoookie proxy authenticator */
576 auth_link (&auth_md5
); /* link in the md5 authenticator */
577 auth_link (&auth_pla
);
578 auth_link (&auth_log
); /* link in the log authenticator */
580 mail_parameters (NIL
,SET_DISABLEPLAINTEXT
,(void *) 2);
583 /* if REMOTE_USER set, use it as username */
584 if(buf
= getenv("REMOTE_USER"))
585 env_init(buf
, "/tmp");
588 if(!mail_parameters(NULL
, DISABLE_DRIVER
, "unix")){
589 fprintf(stderr
, "Can't disable unix driver");
594 * Set network timeouts so we don't hang forever
595 * The open timeout can be pretty short since we're
596 * just opening tcp connection. The read timeout needs
597 * to be longer because the response to some actions can
598 * take awhile. Hopefully this is well within httpd's
599 * cgi timeout threshold.
601 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long) 30);
602 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long) 60);
604 /*----------------------------------------------------------------------
605 Initialize pith library
606 ----------------------------------------------------------------------*/
607 pith_opt_remote_pinerc_failure
= remote_pinerc_failure
;
608 pith_opt_user_agent_prefix
= peWebAlpinePrefix
;
609 pith_opt_newmail_announce
= peNewMailAnnounce
;
611 setup_for_index_index_screen();
614 /*----------------------------------------------------------------------
616 ----------------------------------------------------------------------*/
618 for(argerr
= 0; !argerr
&& ((n
= getopt(argc
,argv
,"d")) != -1); ) {
620 case 'd' : debug
++; break;
621 case '?' : argerr
= 1; break;
625 if(argerr
|| optind
!= argc
){
626 char *p
= strrchr(argv
[0],'/');
627 fprintf(stderr
, "Usage: %s [-d]\n", p
? p
+ 1 : argv
[0]);
631 /*----------------------------------------------------------------------
632 Hop into the Tcl processing loop
633 ----------------------------------------------------------------------*/
635 buf
= (char *) fs_get(bl
* sizeof(char));
637 if(fgets(sname
, 255, stdin
) && *sname
){
638 if(sname
[l
= strlen(sname
) - 1] == '\n')
641 if((s
= socket(AF_UNIX
, SOCK_STREAM
, 0)) != -1){
643 name
.sun_family
= AF_UNIX
;
644 strcpy(name
.sun_path
, peSocketName
= sname
);
647 if(bind(s
, (struct sockaddr
*) &name
, l
) == 0){
648 if(listen(s
, 5) == 0){
650 * after the groundwork's done, go into the background.
651 * the fork saves the caller from invoking us in the background
652 * which introduces a timing race between the first client
653 * request arrival and our being prepared to accept it.
657 case -1 : /* error */
662 close(0); /* disassociate */
668 default : /* parent */
674 dprint((SYSDBG_INFO
, "started"));
676 interp
= Tcl_CreateInterp();
678 PEInit(interp
, sname
);
686 tv
.tv_sec
= (gPEAbandonTimeout
) ? gPEAbandonTimeout
: gPeInputTimeout
;
688 if((n
= select(s
+1, &rfd
, 0, 0, &tv
)) > 0){
691 gPEAbandonTimeout
= 0;
693 if((cs
= accept(s
, (struct sockaddr
*) &name
, &ll
)) == -1){
694 dprint((SYSDBG_ERR
, "accept failure: %s",
695 error_description(errno
)));
699 dprint((5, "accept success: %d", cs
));
702 * tcl commands are prefixed with a number representing
703 * the length of the command string and a newline character.
704 * the characters representing the length and the newline
705 * are not included in the command line length calculation.
708 while((n
= read(cs
, buf
+ o
, bl
- o
- 1)) > 0){
713 for(i
= 0; i
< o
; i
++)
719 fs_resize((void **) &buf
, bl
* sizeof(char));
725 x
= (x
* 10) + (buf
[i
] - '0');
733 dprint((SYSDBG_ERR
, "read EOF"));
736 dprint((SYSDBG_ERR
, "read failure: %s", error_description(errno
)));
741 /* Log every Eval if somebody *really* wants to see it. */
744 int dlim
= (debug
>= 9) ? 256 : 5120 - 32;
746 snprintf(dbuf
, sizeof(dbuf
), "Tcl_Eval(%.*s)", dlim
, &buf
[co
]);
748 /* But DON'T log any clear-text credentials */
752 && !strncmp(dbuf
+ 12, "ession creds ", 13)){
755 for(p
= &dbuf
[25]; *p
; p
++)
762 switch(Tcl_Eval(interp
, &buf
[co
])){
763 case TCL_OK
: peReturn(cs
, "OK", Tcl_GetStringResult(interp
)); break;
764 case TCL_ERROR
: peReturn(cs
, "ERROR", Tcl_GetStringResult(interp
)); break;
765 case TCL_BREAK
: peReturn(cs
, "BREAK", Tcl_GetStringResult(interp
)); break;
766 case TCL_RETURN
: peReturn(cs
, "RETURN", Tcl_GetStringResult(interp
)); break;
767 default : peReturn(cs
, "BOGUS", "eval returned unexpected value"); break;
773 else if(errno
!= EINTR
){
775 dprint((SYSDBG_ALERT
, "select failure: %s", error_description(errno
)));
778 dprint((SYSDBG_INFO
, "timeout after %d seconds", tv
.tv_sec
));
783 /* Tcl_Exit should never return. Getting here is an error. */
784 dprint((SYSDBG_ERR
, "Tcl_Exit failure"));
801 fprintf(stderr
, "Can't read socket name\n");
808 * peReturn - common routine to return TCL result
811 peReturn(int sock
, char *status
, const char *result
)
813 if(peWrite(sock
, status
))
814 if(peWrite(sock
, "\n"))
815 peWrite(sock
, (char *) result
);
819 * peWrite - write all the given string on the given socket
822 peWrite(int sock
, char *s
)
826 for(i
= 0, n
= strlen(s
); n
; n
= n
- i
)
827 if((i
= write(sock
, s
+ i
, n
)) < 0){
828 dprint((SYSDBG_ERR
, "write: %s", error_description(errno
)));
836 * PEInit - Initialize exported TCL functions
839 PEInit(Tcl_Interp
*interp
, char *sname
)
841 dprint((2, "PEInit: %s", sname
));
843 if(Tcl_Init(interp
) == TCL_ERROR
) {
847 Tcl_CreateObjCommand(interp
, "PEInfo", PEInfoCmd
,
848 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
850 Tcl_CreateObjCommand(interp
, "PEConfig", PEConfigCmd
,
851 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
853 Tcl_CreateObjCommand(interp
, "PEDebug", PEDebugCmd
,
854 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
856 Tcl_CreateObjCommand(interp
, "PESession", PESessionCmd
,
857 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
859 Tcl_CreateObjCommand(interp
, "PEFolder", PEFolderCmd
,
860 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
862 Tcl_CreateObjCommand(interp
, "PEMailbox", PEMailboxCmd
,
863 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
865 Tcl_CreateObjCommand(interp
, "PEThread", PEThreadCmd
,
866 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
868 Tcl_CreateObjCommand(interp
, "PEMessage", PEMessageCmd
,
869 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
871 Tcl_CreateObjCommand(interp
, "PECompose", PEComposeCmd
,
872 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
874 Tcl_CreateObjCommand(interp
, "PEPostpone", PEPostponeCmd
,
875 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
877 Tcl_CreateObjCommand(interp
, "PEAddress", PEAddressCmd
,
878 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
880 Tcl_CreateObjCommand(interp
, "PEClist", PEClistCmd
,
881 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
883 Tcl_CreateObjCommand(interp
, "PELdap", PELdapCmd
,
884 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
886 Tcl_CreateObjCommand(interp
, "PERss", PERssCmd
,
887 (ClientData
) NULL
, (Tcl_CmdDeleteProc
*) NULL
);
889 Tcl_CreateExitHandler(PEExitCleanup
, sname
);
892 wpldap_global
= (WPLDAP_S
*)fs_get(sizeof(WPLDAP_S
));
893 wpldap_global
->query_no
= 0;
894 wpldap_global
->ldap_search_list
= NULL
;
895 #endif /* ENABLE_LDAP */
902 PEExitCleanup(ClientData clientData
)
904 dprint((4, "PEExitCleanup"));
907 /* destroy any open stream */
908 peDestroyStream(wps_global
);
910 /* destroy user context */
911 peDestroyUserContext(&wps_global
);
916 if(wpldap_global
->ldap_search_list
)
917 free_wpldapres(wpldap_global
->ldap_search_list
);
918 fs_give((void **)&wpldap_global
);
920 #endif /* ENABLE_LDAP */
922 if((char *) clientData
)
923 unlink((char *) clientData
);
925 peFreeAttach(&peCompAttach
);
927 dprint((SYSDBG_INFO
, "finished"));
932 * PEInfoCmd - export various bits of alpine state
935 PEInfoCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
937 char *err
= "Unknown PEInfo request";
939 dprint((2, "PEInfoCmd"));
942 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
945 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
948 if(!strcmp(s1
, "colorset")){
949 char *varname
, *fghex
, *bghex
;
950 char tvname
[256], asciicolor
[256];
951 struct variable
*vtmp
;
954 SPEC_COLOR_S
*hcolors
, *thc
;
956 if(!(varname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
957 Tcl_SetResult(interp
, "colorset: can't read variable name", TCL_STATIC
);
961 if(!strcmp(varname
, "viewer-hdr-colors")){
962 char *newhdr
= NULL
, *newpat
= NULL
, *utype
;
966 Tcl_SetResult(interp
, "colorset: too few view-hdr args", TCL_STATIC
);
970 hcolors
= spec_colors_from_varlist(wps_global
->VAR_VIEW_HDR_COLORS
, 0);
971 if(!(utype
= Tcl_GetStringFromObj(objv
[3], NULL
))){
972 Tcl_SetResult(interp
, "colorset: can't read operation", TCL_STATIC
);
976 if(!strcmp(utype
, "delete")){
978 Tcl_SetResult(interp
, "colorset: no viewer-hdrs to delete", TCL_STATIC
);
982 if(Tcl_GetIntFromObj(interp
, objv
[4], &hindex
) == TCL_ERROR
){
983 Tcl_SetResult(interp
, "colorset: can't read index", TCL_STATIC
);
989 hcolors
= hcolors
->next
;
991 free_spec_colors(&thc
);
995 for(thc
= hcolors
, i
= 1; thc
&& i
< hindex
; thc
= thc
->next
, i
++)
998 if(thc
&& thc
->next
){
999 SPEC_COLOR_S
*thc2
= thc
->next
;
1001 thc
->next
= thc2
->next
;
1003 free_spec_colors(&thc2
);
1006 Tcl_SetResult(interp
, "colorset: invalid index", TCL_STATIC
);
1011 else if(!strcmp(utype
, "add")){
1013 Tcl_SetResult(interp
, "colorset: wrong number of view-hdr add args", TCL_STATIC
);
1017 if(Tcl_ListObjGetElements(interp
, objv
[4], &cObjc
, &cObj
) != TCL_OK
)
1021 Tcl_SetResult(interp
, "colorset: wrong number of hdrs for view-hdr add", TCL_STATIC
);
1025 newhdr
= Tcl_GetStringFromObj(cObj
[0], NULL
);
1026 newpat
= Tcl_GetStringFromObj(cObj
[1], NULL
);
1027 if(Tcl_ListObjGetElements(interp
, objv
[5], &cObjc
, &cObj
) != TCL_OK
)
1031 Tcl_SetResult(interp
, "colorset: wrong number of colors for view-hdr add", TCL_STATIC
);
1035 fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
);
1036 bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
);
1037 if(newhdr
&& newpat
&& fghex
&& bghex
){
1040 for(hcp
= &hcolors
; *hcp
!= NULL
; hcp
= &(*hcp
)->next
)
1043 *hcp
= (SPEC_COLOR_S
*)fs_get(sizeof(SPEC_COLOR_S
));
1044 (*hcp
)->inherit
= 0;
1045 (*hcp
)->spec
= cpystr(newhdr
);
1046 (*hcp
)->fg
= cpystr((ascii_colorstr(asciicolor
, fghex
) == 0) ? asciicolor
: "black");
1047 (*hcp
)->bg
= cpystr((ascii_colorstr(asciicolor
, bghex
) == 0) ? asciicolor
: "white");
1049 if(newpat
&& *newpat
)
1050 (*hcp
)->val
= string_to_pattern(newpat
);
1054 (*hcp
)->next
= NULL
;
1057 Tcl_SetResult(interp
, "colorset: invalid args for view-hdr add", TCL_STATIC
);
1061 else if(!strcmp(utype
, "update")){
1063 Tcl_SetResult(interp
, "colorset: wrong number of view-hdr update args", TCL_STATIC
);
1067 if(!(Tcl_ListObjGetElements(interp
, objv
[4], &cObjc
, &cObj
) == TCL_OK
1069 && Tcl_GetIntFromObj(interp
, cObj
[0], &hindex
) == TCL_OK
1070 && (newhdr
= Tcl_GetStringFromObj(cObj
[1], NULL
))
1071 && (newpat
= Tcl_GetStringFromObj(cObj
[2], NULL
)))){
1072 Tcl_SetResult(interp
, "colorset: view-hdr update can't read index or header", TCL_STATIC
);
1076 if(!(Tcl_ListObjGetElements(interp
, objv
[5], &cObjc
, &cObj
) == TCL_OK
1078 && (fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
))
1079 && (bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
)))){
1080 Tcl_SetResult(interp
, "colorset: view-hdr update can't read colors", TCL_STATIC
);
1084 for(thc
= hcolors
, i
= 0; thc
&& i
< hindex
; thc
= thc
->next
, i
++)
1088 Tcl_SetResult(interp
, "colorset: view-hdr update invalid index", TCL_STATIC
);
1093 fs_give((void **)&thc
->spec
);
1095 thc
->spec
= cpystr(newhdr
);
1096 if(ascii_colorstr(asciicolor
, fghex
) == 0) {
1098 fs_give((void **)&thc
->fg
);
1100 thc
->fg
= cpystr(asciicolor
);
1103 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid foreground color value %.100s", fghex
);
1104 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1108 if(ascii_colorstr(asciicolor
, bghex
) == 0) {
1110 fs_give((void **)&thc
->bg
);
1112 thc
->bg
= cpystr(asciicolor
);
1115 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
1116 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1121 fs_give((void **)&thc
->val
);
1123 if(newpat
&& *newpat
){
1124 thc
->val
= string_to_pattern(newpat
);
1128 Tcl_SetResult(interp
, "colorset: unknown operation", TCL_STATIC
);
1132 vtmp
= &wps_global
->vars
[V_VIEW_HDR_COLORS
];
1133 for(i
= 0; vtmp
->main_user_val
.l
&& vtmp
->main_user_val
.l
[i
]; i
++)
1134 fs_give((void **)&vtmp
->main_user_val
.l
[i
]);
1136 if(vtmp
->main_user_val
.l
)
1137 fs_give((void **)&vtmp
->main_user_val
.l
);
1139 vtmp
->main_user_val
.l
= varlist_from_spec_colors(hcolors
);
1140 set_current_val(vtmp
, FALSE
, FALSE
);
1141 free_spec_colors(&hcolors
);
1146 Tcl_SetResult(interp
, "colorset: Wrong number of args", TCL_STATIC
);
1150 if(!(Tcl_ListObjGetElements(interp
, objv
[3], &cObjc
, &cObj
) == TCL_OK
1152 && (fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
))
1153 && (bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
)))){
1154 Tcl_SetResult(interp
, "colorset: Problem reading fore/back ground colors", TCL_STATIC
);
1158 snprintf(tvname
, sizeof(tvname
), "%.200s-foreground-color", varname
);
1159 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
1160 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
1164 if(!vtmp
->name
|| vtmp
->is_list
){
1165 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
1166 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1170 if(ascii_colorstr(asciicolor
, fghex
) == 0) {
1171 if(vtmp
->main_user_val
.p
)
1172 fs_give((void **)&vtmp
->main_user_val
.p
);
1174 vtmp
->main_user_val
.p
= cpystr(asciicolor
);
1175 set_current_val(vtmp
, FALSE
, FALSE
);
1176 if(!strucmp(varname
, "normal"))
1177 pico_set_fg_color(asciicolor
);
1180 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid color value %.100s", fghex
);
1181 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1185 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-background-color");
1187 if((vtmp
->name
&& strucmp(vtmp
->name
, tvname
)) || !vtmp
->name
)
1188 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
1189 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
1193 if(!vtmp
->name
|| vtmp
->is_list
){
1194 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
1195 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1199 if(ascii_colorstr(asciicolor
, bghex
) == 0) {
1200 if(vtmp
->main_user_val
.p
)
1201 fs_give((void **)&vtmp
->main_user_val
.p
);
1203 vtmp
->main_user_val
.p
= cpystr(asciicolor
);
1204 set_current_val(vtmp
, FALSE
, FALSE
);
1205 if(!strucmp(varname
, "normal"))
1206 pico_set_bg_color(asciicolor
);
1209 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
1210 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
1214 Tcl_SetResult(interp
, "1", TCL_STATIC
);
1218 else if(!strcmp(s1
, "lappend")){
1223 if((dObj
= Tcl_ObjGetVar2(interp
, objv
[2], NULL
, TCL_LEAVE_ERR_MSG
)) != NULL
){
1224 for(i
= 3; i
< objc
; i
++)
1225 if(Tcl_ListObjAppendElement(interp
, dObj
, objv
[i
]) != TCL_OK
)
1233 err
= "PEInfo lappend: Unknown list name";
1236 err
= "PEInfo lappend: Too few args";
1239 if(!strcmp(s1
, "version")){
1245 * Returns: string representing Pine version
1248 Tcl_SetResult(interp
, ALPINE_VERSION
, TCL_STATIC
);
1251 else if(!strcmp(s1
, "revision")){
1257 * Returns: string representing Pine SVN revision
1261 Tcl_SetResult(interp
, get_alpine_revision_number(buf
, sizeof(buf
)), TCL_VOLATILE
);
1264 else if(!strcmp(s1
, "key")){
1265 static char key
[64];
1268 peRandomString(key
,32,PRS_UPPER_CASE
);
1270 Tcl_SetResult(interp
, key
, TCL_STATIC
);
1273 else if(!strcmp(s1
, "indexheight")){
1274 Tcl_SetResult(interp
, wps_global
->VAR_WP_INDEXHEIGHT
?
1275 wps_global
->VAR_WP_INDEXHEIGHT
: "", TCL_VOLATILE
);
1278 else if(!strcmp(s1
, "indexlines")){
1279 Tcl_SetResult(interp
, wps_global
->VAR_WP_INDEXLINES
?
1280 wps_global
->VAR_WP_INDEXLINES
: "0", TCL_VOLATILE
);
1283 else if(!strcmp(s1
, "aggtabstate")){
1284 Tcl_SetResult(interp
, wps_global
->VAR_WP_AGGSTATE
?
1285 wps_global
->VAR_WP_AGGSTATE
: "0", TCL_VOLATILE
);
1288 else if(!strcmp(s1
, "alpinestate")){
1291 if((wps
= wps_global
->VAR_WP_STATE
) != NULL
){
1292 wps
= p
= q
= cpystr(wps
);
1294 if(*q
== '\\' && *(q
+1) == '$')
1296 while((*p
++ = *q
++) != '\0');
1299 Tcl_SetResult(interp
, wps
? wps
: "", TCL_VOLATILE
);
1302 fs_give((void **) &wps
);
1306 else if(!strcmp(s1
, "foreground")){
1309 if(!((color
= pico_get_last_fg_color())
1310 && (color
= color_to_asciirgb(color
))
1311 && (color
= peColorStr(color
,wtmp_20k_buf
))))
1314 Tcl_SetResult(interp
, color
, TCL_VOLATILE
);
1317 else if(!strcmp(s1
, "background")){
1320 if(!((color
= pico_get_last_bg_color())
1321 && (color
= color_to_asciirgb(color
))
1322 && (color
= peColorStr(color
,wtmp_20k_buf
))))
1325 Tcl_SetResult(interp
, color
, TCL_VOLATILE
);
1328 else if(!strcmp(s1
, "flaglist")){
1334 * BUG: This list should get merged with the static list in "cmd_flag"
1335 * and exported via some function similar to "feature_list()"
1337 static char *flag_list
[] = {
1338 "Important", "New", "Answered", "Deleted", NULL
1344 * Returns: list of FLAGS available for setting
1346 for(i
= 0; (p
= flag_list
[i
]); i
++)
1347 if((itemObj
= Tcl_NewStringObj(p
, -1)) != NULL
){
1348 if(Tcl_ListObjAppendElement(interp
,
1349 Tcl_GetObjResult(interp
),
1356 else if(!strcmp(s1
, "featurelist")){
1358 char *curfeature
, *s
;
1360 Tcl_Obj
*itemObj
, *secObj
= NULL
, *resObj
= NULL
;
1365 * Returns: list of FEATURES available for setting
1367 for(i
= 0, curfeature
= NULL
; (feature
= feature_list(i
)); i
++)
1368 if((s
= feature_list_section(feature
)) != NULL
){
1369 if(!curfeature
|| strucmp(s
, curfeature
)){
1371 Tcl_ListObjAppendElement(interp
,
1374 Tcl_ListObjAppendElement(interp
,
1375 Tcl_GetObjResult(interp
),
1379 secObj
= Tcl_NewListObj(0, NULL
);
1380 resObj
= Tcl_NewListObj(0, NULL
);
1381 if(Tcl_ListObjAppendElement(interp
,
1383 Tcl_NewStringObj(s
,-1)) != TCL_OK
)
1389 if((itemObj
= Tcl_NewStringObj(feature
->name
, -1)) != NULL
){
1390 if(Tcl_ListObjAppendElement(interp
,
1398 Tcl_ListObjAppendElement(interp
, secObj
, resObj
);
1399 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), secObj
);
1404 else if(!strcmp(s1
, "featuresettings")){
1410 * CMD: featuresettings
1412 * Returns: list of FEATURES currently SET
1414 for(i
= 0; (feature
= feature_list(i
)); i
++)
1415 if(feature_list_section(feature
)){
1416 if(F_ON(feature
->id
, wps_global
)){
1417 if((itemObj
= Tcl_NewStringObj(feature
->name
, -1)) != NULL
){
1418 if(Tcl_ListObjAppendElement(interp
,
1419 Tcl_GetObjResult(interp
),
1428 else if(!strcmp(s1
, "signature")){
1431 if((wps_global
->VAR_LITERAL_SIG
1432 || (wps_global
->VAR_SIGNATURE_FILE
1433 && IS_REMOTE(wps_global
->VAR_SIGNATURE_FILE
)))
1434 && (sig
= detoken(NULL
, NULL
, 2, 0, 1, NULL
, NULL
))){
1437 for(p
= sig
; (q
= strindex(p
, '\n')); p
= q
+ 1)
1438 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1439 Tcl_NewStringObj(p
, q
- p
));
1442 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1443 Tcl_NewStringObj(p
, -1));
1445 fs_give((void **) &sig
);
1448 Tcl_SetResult(interp
, "", TCL_STATIC
);
1452 else if(!strcmp(s1
, "rawsig")){
1453 char *err
= NULL
, *sig
= NULL
, *p
, *q
;
1455 if(wps_global
->VAR_LITERAL_SIG
){
1459 if(wps_global
->restricted
){
1460 err
= "Alpine demo can't change config file";
1463 /* BUG: no "exceptions file" support */
1464 if((apval
= APVAL(&wps_global
->vars
[V_LITERAL_SIG
], Main
)) != NULL
){
1465 sig
= (char *) fs_get((strlen(*apval
? *apval
: "") + 1) * sizeof(char));
1467 cstring_to_string(*apval
, sig
);
1470 err
= "Problem accessing configuration";
1473 else if(!IS_REMOTE(wps_global
->VAR_SIGNATURE_FILE
))
1474 snprintf(err
= wtmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote signature file: %s",
1475 wps_global
->VAR_SIGNATURE_FILE
? wps_global
->VAR_SIGNATURE_FILE
: "<null>");
1476 else if(!(sig
= simple_read_remote_file(wps_global
->VAR_SIGNATURE_FILE
, REMOTE_SIG_SUBTYPE
)))
1477 err
= "Can't read remote pinerc";
1480 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
1484 for(p
= sig
; (q
= strindex(p
, '\n')); p
= q
+ 1)
1485 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1486 Tcl_NewStringObj(p
, q
- p
));
1488 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1489 Tcl_NewStringObj(p
, -1));
1490 fs_give((void **) &sig
);
1493 else if(!strcmp(s1
, "statmsg")){
1494 char *s
= sml_getmsg();
1495 /* BUG: can this be removed? */
1497 Tcl_SetResult(interp
, s
? s
: "", TCL_VOLATILE
);
1500 else if(!strcmp(s1
, "statmsgs")){
1501 char **s
= sml_getmsgs();
1502 char **tmps
, *lmsg
= NULL
;
1504 for(tmps
= s
; tmps
&& *tmps
; lmsg
= *tmps
++)
1505 if(!lmsg
|| strcmp(lmsg
, *tmps
))
1506 Tcl_ListObjAppendElement(interp
,
1507 Tcl_GetObjResult(interp
),
1508 Tcl_NewStringObj(*tmps
, -1));
1510 fs_give((void **)&s
);
1513 else if(!strcmp(s1
, "saveconf")){
1514 write_pinerc(wps_global
, Main
, WRP_NOUSER
);
1517 else if(!strucmp(s1
, "sort")){
1518 return(peAppendDefaultSort(interp
));
1520 else if(!strcmp(s1
, "ldapenabled")){
1524 * Returns: 1 if enabled 0 if not
1527 Tcl_SetResult(interp
, "1", TCL_VOLATILE
);
1529 Tcl_SetResult(interp
, "0", TCL_VOLATILE
);
1534 else if(!strcmp(s1
, "prunecheck")){
1539 if(!check_prune_time(&now
, &tm_now
)){
1540 Tcl_SetResult(interp
, "0", TCL_VOLATILE
);
1544 * We're going to reset the last-time-pruned variable
1545 * so that it asks a maximum of 1 time per month.
1546 * PROs: Annoying-factor is at its lowest
1547 * Can go ahead and move folders right away if
1548 * pruning-rule is automatically set to do so
1549 * CONs: Annoying-factor is at its lowest, if it's set
1550 * later then we can ensure that the questions
1551 * actually get answered or it will keep asking
1553 wps_global
->last_expire_year
= tm_now
->tm_year
;
1554 wps_global
->last_expire_month
= tm_now
->tm_mon
;
1555 snprintf(tmp
, sizeof(tmp
), "%d.%d", wps_global
->last_expire_year
,
1556 wps_global
->last_expire_month
+ 1);
1557 set_variable(V_LAST_TIME_PRUNE_QUESTION
, tmp
, 0, 1, Main
);
1559 Tcl_SetResult(interp
, "1", TCL_VOLATILE
);
1563 else if(!strcmp(s1
, "prunetime")){
1566 CONTEXT_S
*prune_cntxt
;
1567 Tcl_Obj
*retObj
= NULL
;
1568 int cur_month
, ok
= 1;
1570 static int moved_fldrs
= 0;
1572 now
= time((time_t *)0);
1573 tm_now
= localtime(&now
);
1574 cur_month
= (1900 + tm_now
->tm_year
) * 12 + tm_now
->tm_mon
;
1576 if(!(prune_cntxt
= default_save_context(wps_global
->context_list
)))
1577 prune_cntxt
= wps_global
->context_list
;
1580 if(wps_global
->VAR_DEFAULT_FCC
&& *wps_global
->VAR_DEFAULT_FCC
1581 && context_isambig(wps_global
->VAR_DEFAULT_FCC
))
1582 if((retObj
= wp_prune_folders(prune_cntxt
,
1583 wps_global
->VAR_DEFAULT_FCC
,
1585 wps_global
->pruning_rule
, &ok
,
1586 moved_fldrs
, interp
)) != NULL
)
1587 Tcl_ListObjAppendElement(interp
,
1588 Tcl_GetObjResult(interp
),
1591 if(ok
&& wps_global
->VAR_READ_MESSAGE_FOLDER
1592 && *wps_global
->VAR_READ_MESSAGE_FOLDER
1593 && context_isambig(wps_global
->VAR_READ_MESSAGE_FOLDER
))
1594 if((retObj
= wp_prune_folders(prune_cntxt
,
1595 wps_global
->VAR_READ_MESSAGE_FOLDER
,
1597 wps_global
->pruning_rule
, &ok
,
1598 moved_fldrs
, interp
)) != NULL
)
1599 Tcl_ListObjAppendElement(interp
,
1600 Tcl_GetObjResult(interp
),
1602 if(ok
&& (p
= wps_global
->VAR_PRUNED_FOLDERS
)){
1603 for(; ok
&& *p
; p
++)
1604 if(**p
&& context_isambig(*p
))
1605 if((retObj
= wp_prune_folders(prune_cntxt
,
1607 wps_global
->pruning_rule
, &ok
,
1608 moved_fldrs
, interp
)) != NULL
)
1609 Tcl_ListObjAppendElement(interp
,
1610 Tcl_GetObjResult(interp
),
1617 else if(!strcmp(s1
, "authrequestor")){
1618 Tcl_SetResult(interp
, peCredentialRequestor
, TCL_STATIC
);
1621 else if(!strcmp(s1
, "noop")){
1622 /* tickle the imap server too */
1623 if(wps_global
->mail_stream
)
1624 pine_mail_ping(wps_global
->mail_stream
);
1626 Tcl_SetResult(interp
, "NOOP", TCL_STATIC
);
1629 else if(!strcmp(s1
, "inputtimeout")){
1630 Tcl_SetResult(interp
, int2string(get_input_timeout()), TCL_VOLATILE
);
1635 if(!strcmp(s1
, "feature")){
1643 * ARGS: featurename -
1645 * Returns: 1 if named feature set, 0 otherwise
1648 if((featurename
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
)
1649 for(i
= 0; (feature
= feature_list(i
)); i
++)
1650 if(!strucmp(featurename
, feature
->name
)){
1651 isset
= F_ON(feature
->id
, wps_global
);
1655 Tcl_SetResult(interp
, int2string(isset
), TCL_VOLATILE
);
1658 else if(!strcmp(s1
, "colorget")){
1660 char tvname
[256], hexcolor
[256];
1661 struct variable
*vtmp
;
1662 if(!(varname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
1665 if(strcmp("viewer-hdr-colors", varname
) == 0){
1666 SPEC_COLOR_S
*hcolors
, *thc
;
1668 char hexcolor
[256], *tstr
= NULL
;
1670 hcolors
= spec_colors_from_varlist(wps_global
->VAR_VIEW_HDR_COLORS
, 0);
1671 for(thc
= hcolors
; thc
; thc
= thc
->next
){
1672 resObj
= Tcl_NewListObj(0,NULL
);
1673 Tcl_ListObjAppendElement(interp
, resObj
,
1674 Tcl_NewStringObj(thc
->spec
, -1));
1675 hex_colorstr(hexcolor
, thc
->fg
);
1676 Tcl_ListObjAppendElement(interp
, resObj
,
1677 Tcl_NewStringObj(hexcolor
, -1));
1678 hex_colorstr(hexcolor
, thc
->bg
);
1679 Tcl_ListObjAppendElement(interp
, resObj
,
1680 Tcl_NewStringObj(hexcolor
, -1));
1681 Tcl_ListObjAppendElement(interp
, resObj
,
1682 Tcl_NewStringObj(thc
->val
1683 ? tstr
= pattern_to_string(thc
->val
)
1685 if(tstr
) fs_give((void **)&tstr
);
1686 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1689 fs_give((void **)&hcolors
);
1693 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-foreground-color");
1694 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
1695 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
1697 if(!vtmp
->name
) return(TCL_ERROR
);
1698 if(vtmp
->is_list
) return(TCL_ERROR
);
1699 if(!vtmp
->current_val
.p
)
1700 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1701 Tcl_NewStringObj("", -1));
1703 hex_colorstr(hexcolor
, vtmp
->current_val
.p
);
1704 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1705 Tcl_NewStringObj(hexcolor
, -1));
1707 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-background-color");
1709 if((vtmp
->name
&& strucmp(vtmp
->name
, tvname
)) || !vtmp
->name
)
1710 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
1711 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
1715 if(!vtmp
->name
) return(TCL_ERROR
);
1716 if(vtmp
->is_list
) return(TCL_ERROR
);
1717 if(!vtmp
->current_val
.p
)
1718 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1719 Tcl_NewStringObj("", -1));
1721 hex_colorstr(hexcolor
, vtmp
->current_val
.p
);
1722 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
1723 Tcl_NewStringObj(hexcolor
, -1));
1728 else if(!strcmp(s1
, "varget")){
1729 struct variable
*vtmp
;
1730 Tcl_Obj
*itemObj
, *resObj
, *secObj
;
1731 char *vallist
, *varname
, tmperrmsg
[256];
1738 * Returns: get the values for the requested variable
1740 * The list returned follows this general form:
1742 * char *; variable name
1743 * char **; list of set values
1744 * char *; display type (listbox, text, textarea, ...)
1745 * char **; list of possible values
1746 * (so far this is only useful for listboxes)
1748 if(!(varname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
1749 Tcl_SetResult(interp
, "Can't Tcl_GetStringFromObj",
1754 for(vtmp
= wps_global
->vars
;
1755 vtmp
->name
&& strucmp(vtmp
->name
, varname
);
1760 snprintf(tmperrmsg
, sizeof(tmperrmsg
), "Can't find variable named %s",
1761 strlen(varname
) < 200 ? varname
: "");
1762 Tcl_SetResult(interp
, tmperrmsg
, TCL_VOLATILE
);
1765 if((itemObj
= Tcl_NewStringObj(vtmp
->name
, -1)) != NULL
){
1766 Tcl_ListObjAppendElement(interp
,
1767 Tcl_GetObjResult(interp
),
1769 resObj
= Tcl_NewListObj(0, NULL
);
1771 for(i
= 0 ; vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]; i
++){
1772 vallist
= vtmp
->current_val
.l
[i
];
1774 itemObj
= Tcl_NewStringObj(vallist
, -1);
1776 itemObj
= Tcl_NewStringObj("", -1);
1777 Tcl_ListObjAppendElement(interp
, resObj
, itemObj
);
1781 itemObj
= Tcl_NewStringObj(vtmp
->current_val
.p
?
1782 vtmp
->current_val
.p
: "", -1);
1783 Tcl_ListObjAppendElement(interp
, resObj
, itemObj
);
1785 Tcl_ListObjAppendElement(interp
,
1786 Tcl_GetObjResult(interp
),
1788 secObj
= Tcl_NewListObj(0, NULL
);
1790 itemObj
= Tcl_NewStringObj("textarea", -1);
1792 NAMEVAL_S
*(*tmpf
)(int);
1793 switch(vtmp
- wps_global
->vars
){
1794 case V_SAVED_MSG_NAME_RULE
:
1795 tmpf
= save_msg_rules
;
1801 tmpf
= sort_key_rules
;
1803 case V_AB_SORT_RULE
:
1804 tmpf
= ab_sort_rules
;
1806 case V_FLD_SORT_RULE
:
1807 tmpf
= fld_sort_rules
;
1809 case V_GOTO_DEFAULT_RULE
:
1812 case V_INCOMING_STARTUP
:
1813 tmpf
= incoming_startup_rules
;
1815 case V_PRUNING_RULE
:
1816 tmpf
= pruning_rules
;
1818 case V_WP_INDEXHEIGHT
:
1819 tmpf
= wp_indexheight_rules
;
1826 for(i
= 0; (tmpnv
= (tmpf
)(i
)); i
++){
1827 itemObj
= Tcl_NewListObj(0, NULL
);
1828 Tcl_ListObjAppendElement(interp
, itemObj
,
1829 Tcl_NewStringObj(tmpnv
->name
, -1));
1830 if(tmpnv
->shortname
)
1831 Tcl_ListObjAppendElement(interp
, itemObj
,
1832 Tcl_NewStringObj(tmpnv
->shortname
, -1));
1833 Tcl_ListObjAppendElement(interp
, secObj
, itemObj
);
1835 itemObj
= Tcl_NewStringObj("listbox", -1);
1838 itemObj
= Tcl_NewStringObj("text", -1);
1840 Tcl_ListObjAppendElement(interp
,
1841 Tcl_GetObjResult(interp
),
1843 Tcl_ListObjAppendElement(interp
,
1844 Tcl_GetObjResult(interp
),
1849 else if(!strcmp(s1
, "rawsig")){
1851 if(wps_global
->VAR_LITERAL_SIG
){
1852 char *cstring_version
, *sig
, *line
;
1856 wtmp_20k_buf
[0] = '\0';
1857 Tcl_ListObjGetElements(interp
, objv
[2], &nSig
, &objSig
);
1858 for(i
= 0; i
< nSig
&& i
< SIG_MAX_LINES
; i
++)
1859 if((line
= Tcl_GetStringFromObj(objSig
[i
], NULL
)) != NULL
)
1860 snprintf(wtmp_20k_buf
+ strlen(wtmp_20k_buf
), SIZEOF_20KBUF
- strlen(wtmp_20k_buf
), "%.*s\n", SIG_MAX_COLS
, line
);
1862 sig
= cpystr(wtmp_20k_buf
);
1864 if((cstring_version
= string_to_cstring(sig
)) != NULL
){
1865 set_variable(V_LITERAL_SIG
, cstring_version
, 0, 0, Main
);
1866 fs_give((void **)&cstring_version
);
1869 fs_give((void **) &sig
);
1873 return(peWriteSig(interp
, wps_global
->VAR_SIGNATURE_FILE
,
1874 &((Tcl_Obj
**)objv
)[2]));
1876 else if(!strcmp(s1
, "statmsg")){
1882 * ARGS: msg - text to set
1884 * Returns: nothing, but with global status message
1885 * buf set to given msg
1888 if((msg
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
)
1893 else if(!strcmp(s1
, "mode")){
1902 * Returns: return value of given binary mode
1905 if((mode
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
1906 if(!strcmp(mode
, "full-header-mode"))
1907 rv
= wps_global
->full_header
;
1910 Tcl_SetResult(interp
, int2string(rv
), TCL_VOLATILE
);
1913 else if(!strcmp(s1
, "indexlines")){
1917 if(Tcl_GetIntFromObj(interp
, objv
[2], &n
) == TCL_OK
){
1918 set_variable(V_WP_INDEXLINES
, p
= int2string(n
), 0, 0, Main
);
1919 Tcl_SetResult(interp
, p
, TCL_VOLATILE
);
1923 else if(!strcmp(s1
, "aggtabstate")){
1927 if(Tcl_GetIntFromObj(interp
, objv
[2], &n
) == TCL_OK
){
1928 set_variable(V_WP_AGGSTATE
, p
= int2string(n
), 0, 0, Main
);
1929 Tcl_SetResult(interp
, p
, TCL_VOLATILE
);
1933 else if(!strcmp(s1
, "alpinestate")){
1934 char *wps
, *p
, *q
, *twps
= NULL
;
1937 if((wps
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
1938 for(p
= wps
; *p
; p
++)
1943 twps
= (char *) fs_get(((p
- wps
) + (dollars
+ 1)) * sizeof(char));
1950 while((*q
++ = *p
++) != '\0');
1953 set_variable(V_WP_STATE
, twps
? twps
: wps
, 0, 1, Main
);
1954 Tcl_SetResult(interp
, wps
, TCL_VOLATILE
);
1956 fs_give((void **) &twps
);
1961 else if(!strcmp(s1
, "set")){
1964 if((rObj
= Tcl_ObjGetVar2(interp
, objv
[2], NULL
, TCL_LEAVE_ERR_MSG
)) != NULL
){
1965 Tcl_SetObjResult(interp
, rObj
);
1971 else if(!strcmp(s1
, "unset")){
1974 return((varname
= Tcl_GetStringFromObj(objv
[2], NULL
)) ? Tcl_UnsetVar2(interp
, varname
, NULL
, TCL_LEAVE_ERR_MSG
) : TCL_ERROR
);
1978 if(!strcmp(s1
, "feature")){
1980 int i
, set
, wasset
= 0;
1986 * ARGS: featurename -
1987 * value - new value to assign flag
1989 * Returns: 1 if named feature set, 0 otherwise
1992 if((featurename
= Tcl_GetStringFromObj(objv
[2], NULL
))
1993 && Tcl_GetIntFromObj(interp
, objv
[3], &set
) != TCL_ERROR
)
1994 for(i
= 0; (feature
= feature_list(i
)); i
++)
1995 if(!strucmp(featurename
, feature
->name
)){
1996 if(set
!= F_ON(feature
->id
, wps_global
)){
1997 toggle_feature(wps_global
,
1998 &wps_global
->vars
[V_FEATURE_LIST
],
1999 feature
, TRUE
, Main
);
2002 wps_global
->prc
->outstanding_pinerc_changes
= 1;
2008 Tcl_SetResult(interp
, int2string(wasset
), TCL_VOLATILE
);
2011 else if(!strucmp(s1
, "help")){
2014 char **help_text
, **ptext
, *helpname
, tmperrmsg
[256],
2017 struct variable
*vtmp
;
2020 if(!(helpname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
2021 Tcl_SetResult(interp
,
2022 "Can't Tcl_GetStringFromObj for helpname",
2026 if(!(function
= Tcl_GetStringFromObj(objv
[3], NULL
))){
2027 Tcl_SetResult(interp
,
2028 "Can't Tcl_GetStringFromObj for function",
2032 if(strucmp(function
, "plain") == 0){
2033 if((text
= help_name2section(helpname
, strlen(helpname
)))
2037 else if(strucmp(function
, "variable") == 0){
2038 for(vtmp
= wps_global
->vars
;
2039 vtmp
->name
&& strucmp(vtmp
->name
, helpname
);
2042 snprintf(tmperrmsg
, sizeof(tmperrmsg
), "Can't find variable named %s",
2043 strlen(helpname
) < 200 ? helpname
: "");
2044 Tcl_SetResult(interp
, tmperrmsg
, TCL_VOLATILE
);
2047 text
= config_help(vtmp
- wps_global
->vars
, 0);
2051 else if(strucmp(function
, "feature") == 0){
2052 for(i
= 0; (ftmp
= feature_list(i
)); i
++){
2053 if(!strucmp(helpname
, ftmp
->name
)){
2058 if(!ftmp
|| text
== NO_HELP
){
2063 snprintf(tmperrmsg
, sizeof(tmperrmsg
), "Invalid function: %s",
2064 strlen(helpname
) < 200 ? function
: "");
2065 Tcl_SetResult(interp
, tmperrmsg
, TCL_VOLATILE
);
2068 /* assumption here is that HelpType is char ** */
2070 for(ptext
= help_text
; *ptext
; ptext
++){
2071 itemObj
= Tcl_NewStringObj(*ptext
, -1);
2072 Tcl_ListObjAppendElement(interp
,
2073 Tcl_GetObjResult(interp
),
2078 else if(!strcmp(s1
, "varset")){
2079 char *varname
, **tmpstrlist
, *line
;
2080 struct variable
*vtmp
;
2082 int i
, numlistvals
= 0, strlistpos
;
2084 if((varname
= Tcl_GetStringFromObj(objv
[2], NULL
))
2085 && (Tcl_ListObjGetElements(interp
, objv
[3], &numlistvals
,
2086 &objVal
) == TCL_OK
)){
2087 for(vtmp
= wps_global
->vars
;
2088 vtmp
->name
&& strucmp(vtmp
->name
, varname
);
2094 /* found the variable */
2096 for(i
= 0; vtmp
->main_user_val
.l
&& vtmp
->main_user_val
.l
[i
]; i
++)
2097 fs_give((void **)&vtmp
->main_user_val
.l
[i
]);
2098 if(vtmp
->main_user_val
.l
)
2099 fs_give((void **)&vtmp
->main_user_val
.l
);
2100 if(numlistvals
> 0){
2101 tmpstrlist
= (char **)fs_get((numlistvals
+ 1) * sizeof(char *));
2102 for(i
= 0, strlistpos
= 0; i
< numlistvals
; i
++){
2103 if((line
= Tcl_GetStringFromObj(objVal
[i
], 0)) != NULL
){
2104 removing_leading_and_trailing_white_space(line
);
2106 tmpstrlist
[strlistpos
++] = cpystr(line
);
2109 tmpstrlist
[strlistpos
] = NULL
;
2110 vtmp
->main_user_val
.l
= (char **)fs_get((strlistpos
+1) *
2112 for(i
= 0; i
<= strlistpos
; i
++)
2113 vtmp
->main_user_val
.l
[i
] = tmpstrlist
[i
];
2114 fs_give((void **)&tmpstrlist
);
2116 set_current_val(vtmp
, FALSE
, FALSE
);
2120 if((line
= Tcl_GetStringFromObj(objVal
[0], NULL
)) != NULL
){
2121 if(strucmp(vtmp
->name
, "reply-indent-string"))
2122 removing_leading_and_trailing_white_space(line
);
2123 if(vtmp
->main_user_val
.p
)
2124 fs_give((void **)&vtmp
->main_user_val
.p
);
2126 vtmp
->main_user_val
.p
= cpystr(line
);
2127 set_current_val(vtmp
, FALSE
, FALSE
);
2135 else if(!strcmp(s1
, "mode")){
2142 * ARGS: <mode> <value>
2144 * Returns: old value of binary mode we were told to set
2147 if((mode
= Tcl_GetStringFromObj(objv
[2], NULL
))
2148 && Tcl_GetIntFromObj(interp
, objv
[3], &value
) != TCL_ERROR
){
2149 if(!strcmp(mode
, "full-header-mode")){
2150 rv
= wps_global
->full_header
;
2151 wps_global
->full_header
= value
;
2155 Tcl_SetResult(interp
, int2string(rv
), TCL_VOLATILE
);
2158 else if(!strcmp(s1
, "set")){
2161 if((rObj
= Tcl_ObjSetVar2(interp
, objv
[2], NULL
, objv
[3], TCL_LEAVE_ERR_MSG
)) != NULL
){
2162 Tcl_SetObjResult(interp
, rObj
);
2170 err
= "PEInfo: Too many arguments";
2174 Tcl_SetResult(interp
, err
, TCL_STATIC
);
2180 * PEConfigCmd - edit various alpine config variables
2182 * The goal here is to remember what's changed, but not write to pinerc
2183 * until the user's actually chosen to save.
2186 PEConfigCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
2188 char *err
= "Unknown PEConfig request";
2191 dprint((2, "PEConfigCmd"));
2194 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
2195 Tcl_SetResult(interp
, err
, TCL_STATIC
);
2198 s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
2201 if(!strcmp(s1
, "colorset")){
2202 char *varname
, *fghex
, *bghex
;
2203 char tvname
[256], asciicolor
[256];
2204 struct variable
*vtmp
;
2207 SPEC_COLOR_S
*hcolors
, *thc
;
2209 if(!(varname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
2210 Tcl_SetResult(interp
, "colorset: can't read variable name", TCL_STATIC
);
2214 if(!strcmp(varname
, "viewer-hdr-colors")){
2215 char *newhdr
= NULL
, *newpat
= NULL
, *utype
;
2219 Tcl_SetResult(interp
, "colorset: too few view-hdr args", TCL_STATIC
);
2223 if(wps_global
->vars
[V_VIEW_HDR_COLORS
].is_changed_val
)
2224 hcolors
= spec_colors_from_varlist(wps_global
->vars
[V_VIEW_HDR_COLORS
].changed_val
.l
, 0);
2226 hcolors
= spec_colors_from_varlist(wps_global
->VAR_VIEW_HDR_COLORS
, 0);
2227 if(!(utype
= Tcl_GetStringFromObj(objv
[3], NULL
))){
2228 Tcl_SetResult(interp
, "colorset: can't read operation", TCL_STATIC
);
2232 if(!strcmp(utype
, "delete")){
2234 Tcl_SetResult(interp
, "colorset: no viewer-hdrs to delete", TCL_STATIC
);
2238 if(Tcl_GetIntFromObj(interp
, objv
[4], &hindex
) == TCL_ERROR
){
2239 Tcl_SetResult(interp
, "colorset: can't read index", TCL_STATIC
);
2245 hcolors
= hcolors
->next
;
2247 free_spec_colors(&thc
);
2251 for(thc
= hcolors
, i
= 1; thc
&& i
< hindex
; thc
= thc
->next
, i
++)
2254 if(thc
&& thc
->next
){
2255 SPEC_COLOR_S
*thc2
= thc
->next
;
2257 thc
->next
= thc2
->next
;
2259 free_spec_colors(&thc2
);
2262 Tcl_SetResult(interp
, "colorset: invalid index", TCL_STATIC
);
2267 else if(!strcmp(utype
, "add")){
2269 Tcl_SetResult(interp
, "colorset: wrong number of view-hdr add args", TCL_STATIC
);
2273 if(Tcl_ListObjGetElements(interp
, objv
[4], &cObjc
, &cObj
) != TCL_OK
)
2277 Tcl_SetResult(interp
, "colorset: wrong number of hdrs for view-hdr add", TCL_STATIC
);
2281 newhdr
= Tcl_GetStringFromObj(cObj
[0], NULL
);
2282 newpat
= Tcl_GetStringFromObj(cObj
[1], NULL
);
2283 if(Tcl_ListObjGetElements(interp
, objv
[5], &cObjc
, &cObj
) != TCL_OK
)
2287 Tcl_SetResult(interp
, "colorset: wrong number of colors for view-hdr add", TCL_STATIC
);
2291 fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
);
2292 bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
);
2293 if(newhdr
&& newpat
&& fghex
&& bghex
){
2296 for(hcp
= &hcolors
; *hcp
!= NULL
; hcp
= &(*hcp
)->next
)
2299 *hcp
= (SPEC_COLOR_S
*)fs_get(sizeof(SPEC_COLOR_S
));
2300 (*hcp
)->inherit
= 0;
2301 (*hcp
)->spec
= cpystr(newhdr
);
2302 (*hcp
)->fg
= cpystr((ascii_colorstr(asciicolor
, fghex
) == 0) ? asciicolor
: "black");
2303 (*hcp
)->bg
= cpystr((ascii_colorstr(asciicolor
, bghex
) == 0) ? asciicolor
: "white");
2305 if(newpat
&& *newpat
)
2306 (*hcp
)->val
= string_to_pattern(newpat
);
2310 (*hcp
)->next
= NULL
;
2313 Tcl_SetResult(interp
, "colorset: invalid args for view-hdr add", TCL_STATIC
);
2317 else if(!strcmp(utype
, "update")){
2319 Tcl_SetResult(interp
, "colorset: wrong number of view-hdr update args", TCL_STATIC
);
2323 if(!(Tcl_ListObjGetElements(interp
, objv
[4], &cObjc
, &cObj
) == TCL_OK
2325 && Tcl_GetIntFromObj(interp
, cObj
[0], &hindex
) == TCL_OK
2326 && (newhdr
= Tcl_GetStringFromObj(cObj
[1], NULL
))
2327 && (newpat
= Tcl_GetStringFromObj(cObj
[2], NULL
)))){
2328 Tcl_SetResult(interp
, "colorset: view-hdr update can't read index or header", TCL_STATIC
);
2332 if(!(Tcl_ListObjGetElements(interp
, objv
[5], &cObjc
, &cObj
) == TCL_OK
2334 && (fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
))
2335 && (bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
)))){
2336 Tcl_SetResult(interp
, "colorset: view-hdr update can't read colors", TCL_STATIC
);
2340 for(thc
= hcolors
, i
= 0; thc
&& i
< hindex
; thc
= thc
->next
, i
++)
2344 Tcl_SetResult(interp
, "colorset: view-hdr update invalid index", TCL_STATIC
);
2349 fs_give((void **)&thc
->spec
);
2351 thc
->spec
= cpystr(newhdr
);
2352 if(ascii_colorstr(asciicolor
, fghex
) == 0) {
2354 fs_give((void **)&thc
->fg
);
2356 thc
->fg
= cpystr(asciicolor
);
2359 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid foreground color value %.100s", fghex
);
2360 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2364 if(ascii_colorstr(asciicolor
, bghex
) == 0) {
2366 fs_give((void **)&thc
->bg
);
2368 thc
->bg
= cpystr(asciicolor
);
2371 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
2372 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2377 fs_give((void **)&thc
->val
);
2379 if(newpat
&& *newpat
){
2380 thc
->val
= string_to_pattern(newpat
);
2384 Tcl_SetResult(interp
, "colorset: unknown operation", TCL_STATIC
);
2388 vtmp
= &wps_global
->vars
[V_VIEW_HDR_COLORS
];
2389 for(i
= 0; vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]; i
++)
2390 fs_give((void **)&vtmp
->changed_val
.l
[i
]);
2392 if(vtmp
->changed_val
.l
)
2393 fs_give((void **)&vtmp
->changed_val
.l
);
2395 vtmp
->changed_val
.l
= varlist_from_spec_colors(hcolors
);
2396 vtmp
->is_changed_val
= 1;
2397 free_spec_colors(&hcolors
);
2402 Tcl_SetResult(interp
, "colorset: Wrong number of args", TCL_STATIC
);
2406 if(!(Tcl_ListObjGetElements(interp
, objv
[3], &cObjc
, &cObj
) == TCL_OK
2408 && (fghex
= Tcl_GetStringFromObj(cObj
[0], NULL
))
2409 && (bghex
= Tcl_GetStringFromObj(cObj
[1], NULL
)))){
2410 Tcl_SetResult(interp
, "colorset: Problem reading fore/back ground colors", TCL_STATIC
);
2414 snprintf(tvname
, sizeof(tvname
), "%.200s-foreground-color", varname
);
2415 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
2416 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
2420 if(!vtmp
->name
|| vtmp
->is_list
){
2421 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
2422 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2426 if(ascii_colorstr(asciicolor
, fghex
) == 0) {
2427 if(vtmp
->changed_val
.p
)
2428 fs_give((void **)&vtmp
->changed_val
.p
);
2430 vtmp
->changed_val
.p
= cpystr(asciicolor
);
2431 vtmp
->is_changed_val
= 1;
2433 /* We need to handle this in the actual config setting
2434 * if(!strucmp(varname, "normal"))
2435 * pico_set_fg_color(asciicolor);
2439 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid color value %.100s", fghex
);
2440 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2444 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-background-color");
2446 if((vtmp
->name
&& strucmp(vtmp
->name
, tvname
)) || !vtmp
->name
)
2447 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
2448 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
2452 if(!vtmp
->name
|| vtmp
->is_list
){
2453 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
2454 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2458 if(ascii_colorstr(asciicolor
, bghex
) == 0) {
2459 if(vtmp
->changed_val
.p
)
2460 fs_give((void **)&vtmp
->changed_val
.p
);
2462 vtmp
->changed_val
.p
= cpystr(asciicolor
);
2463 vtmp
->is_changed_val
= 1;
2464 /* again, we need to handle this when we actually set the variable
2465 * if(!strucmp(varname, "normal"))
2466 * pico_set_bg_color(asciicolor);
2470 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
2471 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
2475 Tcl_SetResult(interp
, "1", TCL_STATIC
);
2479 else if(!strcmp(s1
, "ruleset")){
2480 return(peRuleSet(interp
, &((Tcl_Obj
**)objv
)[2]));
2483 if(!strcmp(s1
, "featuresettings")){
2484 struct variable
*vtmp
;
2488 vtmp
= &wps_global
->vars
[V_FEATURE_LIST
];
2489 for(i
= 0; (feature
= feature_list(i
)); i
++)
2490 if(feature_list_section(feature
)){
2491 if(vtmp
->is_changed_val
? F_CH_ON(feature
->id
)
2492 : F_ON(feature
->id
, wps_global
)){
2493 Tcl_ListObjAppendElement(interp
,
2494 Tcl_GetObjResult(interp
),
2495 Tcl_NewStringObj(feature
->name
, -1));
2500 else if(!strcmp(s1
, "rawsig")){
2501 char *err
= NULL
, *sig
= NULL
, *p
, *q
;
2503 struct variable
*vtmp
;
2505 vtmp
= &wps_global
->vars
[V_LITERAL_SIG
];
2506 if(vtmp
->is_changed_val
? vtmp
->changed_val
.p
2507 : wps_global
->VAR_LITERAL_SIG
){
2511 if(wps_global
->restricted
){
2512 err
= "Alpine demo can't change config file";
2515 /* BUG: no "exceptions file" support */
2516 apval
= (vtmp
->is_changed_val
? &vtmp
->changed_val
.p
2517 : APVAL(&wps_global
->vars
[V_LITERAL_SIG
], Main
));
2519 sig
= (char *) fs_get((strlen(*apval
? *apval
: "") + 1) * sizeof(char));
2521 cstring_to_string(*apval
, sig
);
2524 err
= "Problem accessing configuration";
2527 else if((vtmp
= &wps_global
->vars
[V_SIGNATURE_FILE
])
2528 && !IS_REMOTE(vtmp
->is_changed_val
? vtmp
->changed_val
.p
2529 : wps_global
->VAR_SIGNATURE_FILE
))
2530 snprintf(err
= wtmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote signature file: %s",
2531 vtmp
->is_changed_val
? (vtmp
->changed_val
.p
2532 ? vtmp
->changed_val
.p
: "<null>")
2533 : (wps_global
->VAR_SIGNATURE_FILE
2534 ? wps_global
->VAR_SIGNATURE_FILE
: "<null>"));
2535 else if(!(peTSig
|| (sig
= simple_read_remote_file(vtmp
->is_changed_val
2536 ? vtmp
->changed_val
.p
2537 : wps_global
->VAR_SIGNATURE_FILE
, REMOTE_SIG_SUBTYPE
))))
2538 err
= "Can't read remote pinerc";
2541 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
2546 for(i
= 0; peTSig
[i
]; i
++)
2547 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2548 Tcl_NewStringObj(peTSig
[i
],-1));
2551 for(p
= sig
; (q
= strindex(p
, '\n')); p
= q
+ 1)
2552 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2553 Tcl_NewStringObj(p
, q
- p
));
2555 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2556 Tcl_NewStringObj(p
, -1));
2557 fs_give((void **) &sig
);
2561 else if(!strcmp(s1
, "filters")){
2562 long rflags
= ROLE_DO_FILTER
| PAT_USE_CHANGED
;
2566 close_every_pattern();
2567 if(any_patterns(rflags
, &pstate
)){
2568 for(pat
= first_pattern(&pstate
);
2570 pat
= next_pattern(&pstate
)){
2571 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2572 Tcl_NewStringObj(pat
->patgrp
->nick
, -1));
2577 else if(!strcmp(s1
, "scores")){
2578 long rflags
= ROLE_DO_SCORES
| PAT_USE_CHANGED
;
2582 close_every_pattern();
2583 if(any_patterns(rflags
, &pstate
)){
2584 for(pat
= first_pattern(&pstate
);
2586 pat
= next_pattern(&pstate
)){
2587 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2588 Tcl_NewStringObj(pat
->patgrp
->nick
, -1));
2593 else if(!strcmp(s1
, "indexcolors")){
2594 long rflags
= ROLE_DO_INCOLS
| PAT_USE_CHANGED
;
2598 close_every_pattern();
2599 if(any_patterns(rflags
, &pstate
)){
2600 for(pat
= first_pattern(&pstate
);
2602 pat
= next_pattern(&pstate
)){
2603 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2604 Tcl_NewStringObj(pat
->patgrp
->nick
, -1));
2609 else if(!strcmp(s1
, "collections")){
2610 struct variable
*vtmp
;
2612 CONTEXT_S
*new_ctxt
;
2614 vtmp
= &wps_global
->vars
[V_FOLDER_SPEC
];
2615 for(i
= 0; (vtmp
->is_changed_val
2616 ? vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]
2617 : vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]);
2619 new_ctxt
= new_context(vtmp
->is_changed_val
2620 ? vtmp
->changed_val
.l
[i
]
2621 : vtmp
->current_val
.l
[i
], NULL
);
2622 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s",
2624 ? new_ctxt
->nickname
2629 : "Some Collection")),
2630 new_ctxt
->label
? new_ctxt
->label
: "");
2631 free_context(&new_ctxt
);
2633 vtmp
= &wps_global
->vars
[V_NEWS_SPEC
];
2634 for(i
= 0; (vtmp
->is_changed_val
2635 ? vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]
2636 : vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]);
2638 new_ctxt
= new_context(vtmp
->is_changed_val
2639 ? vtmp
->changed_val
.l
[i
]
2640 : vtmp
->current_val
.l
[i
], NULL
);
2641 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s",
2643 ? new_ctxt
->nickname
2648 : "Some Collection")),
2649 new_ctxt
->label
? new_ctxt
->label
: "");
2650 free_context(&new_ctxt
);
2655 else if(!strcmp(s1
, "newconf")){
2656 struct variable
*vtmp
;
2660 for(vtmp
= wps_global
->vars
; vtmp
->name
; vtmp
++)
2661 vtmp
->is_changed_val
= 0;
2663 for(i
= 0; (feature
= feature_list(i
)); i
++)
2664 F_CH_SET(feature
->id
, F_ON(feature
->id
, wps_global
));
2667 for(i
= 0; peTSig
[i
]; i
++)
2668 fs_give((void **)&peTSig
[i
]);
2669 fs_give((void **)&peTSig
);
2672 close_patterns(ROLE_DO_FILTER
| ROLE_DO_INCOLS
| ROLE_DO_SCORES
| PAT_USE_CHANGED
);
2675 else if(!strcmp(s1
, "saveconf")){
2676 struct variable
*vtmp
;
2677 int i
, did_change
= 0, def_sort_rev
;
2680 if(wps_global
->vars
[V_FEATURE_LIST
].is_changed_val
){
2681 wps_global
->vars
[V_FEATURE_LIST
].is_changed_val
= 0;
2682 for(i
= 0; (feature
= feature_list(i
)); i
++)
2683 if(feature_list_section(feature
)){
2684 if(F_CH_ON(feature
->id
) != F_ON(feature
->id
, wps_global
)){
2686 toggle_feature(wps_global
,
2687 &wps_global
->vars
[V_FEATURE_LIST
],
2688 feature
, TRUE
, Main
);
2693 for(vtmp
= wps_global
->vars
; vtmp
->name
; vtmp
++){
2694 if(vtmp
->is_changed_val
2695 && (vtmp
- wps_global
->vars
!= V_FEATURE_LIST
)){
2697 for(i
= 0; vtmp
->main_user_val
.l
2698 && vtmp
->main_user_val
.l
[i
]; i
++)
2699 fs_give((void **)&vtmp
->main_user_val
.l
[i
]);
2700 if(vtmp
->main_user_val
.l
)
2701 fs_give((void **)&vtmp
->main_user_val
.l
);
2702 vtmp
->main_user_val
.l
= vtmp
->changed_val
.l
;
2703 vtmp
->changed_val
.l
= NULL
;
2706 if(vtmp
->main_user_val
.p
)
2707 fs_give((void **)&vtmp
->main_user_val
.p
);
2708 vtmp
->main_user_val
.p
= vtmp
->changed_val
.p
;
2709 vtmp
->changed_val
.p
= NULL
;
2711 set_current_val(vtmp
, FALSE
, FALSE
);
2712 vtmp
->is_changed_val
= 0;
2714 switch (vtmp
- wps_global
->vars
) {
2716 init_hostname(wps_global
);
2719 free_contexts(&wps_global
->context_list
);
2720 init_folders(wps_global
);
2722 case V_NORM_FORE_COLOR
:
2723 pico_set_fg_color(vtmp
->current_val
.p
);
2725 case V_NORM_BACK_COLOR
:
2726 pico_set_bg_color(vtmp
->current_val
.p
);
2729 case V_GLOB_ADDRBOOK
:
2731 case V_LDAP_SERVERS
:
2733 case V_ABOOK_FORMATS
:
2735 case V_INDEX_FORMAT
:
2736 init_index_format(wps_global
->VAR_INDEX_FORMAT
,
2737 &wps_global
->index_disp_format
);
2738 clear_index_cache(sp_inbox_stream(), 0);
2741 close_patterns(ROLE_DO_FILTER
| PAT_USE_CURRENT
);
2742 role_process_filters();
2745 close_patterns(ROLE_DO_INCOLS
| PAT_USE_CURRENT
);
2746 clear_index_cache(sp_inbox_stream(), 0);
2747 role_process_filters();
2750 close_patterns(ROLE_DO_SCORES
| PAT_USE_CURRENT
);
2751 role_process_filters();
2754 case V_DEFAULT_SAVE_FOLDER
:
2755 init_save_defaults();
2758 decode_sort(wps_global
->VAR_SORT_KEY
, &wps_global
->def_sort
, &def_sort_rev
);
2760 case V_VIEW_HDR_COLORS
:
2761 set_custom_spec_colors(wps_global
);
2763 case V_POST_CHAR_SET
:
2764 update_posting_charset(wps_global
, 1);
2772 peWriteSig(interp
, wps_global
->VAR_SIGNATURE_FILE
, NULL
);
2775 if(write_pinerc(wps_global
, Main
, WRP_NOUSER
) == 0)
2776 q_status_message(SM_ORDER
, 0, 3, "Configuration changes saved!");
2780 else if(!strcmp(s1
, "columns")){
2781 Tcl_SetResult(interp
, int2string(wps_global
->ttyo
->screen_cols
), TCL_VOLATILE
);
2784 else if(!strcmp(s1
, "indextokens")){
2788 for(i
= 0; (tok
= itoken(i
)) != NULL
; i
++)
2789 if(tok
->what_for
& FOR_INDEX
)
2790 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2791 Tcl_NewStringObj(tok
->name
, -1));
2797 if(!strcmp(s1
, "varget")){
2798 char *varname
= Tcl_GetStringFromObj(objv
[2], NULL
);
2799 struct variable
*vtmp
;
2800 Tcl_Obj
*resObj
, *secObj
;
2805 if(varname
== NULL
) return(TCL_ERROR
);
2807 for(vtmp
= wps_global
->vars
;
2808 vtmp
->name
&& strucmp(vtmp
->name
, varname
);
2813 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
2816 resObj
= Tcl_NewListObj(0, NULL
);
2818 if(vtmp
->is_changed_val
){
2819 for(i
= 0; vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]; i
++){
2820 Tcl_ListObjAppendElement(interp
, resObj
,
2821 Tcl_NewStringObj(vtmp
->changed_val
.l
[i
], -1));
2825 for(i
= 0; vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]; i
++){
2826 Tcl_ListObjAppendElement(interp
, resObj
,
2827 Tcl_NewStringObj(vtmp
->current_val
.l
[i
], -1));
2832 if(vtmp
->is_changed_val
){
2833 if(vtmp
->changed_val
.p
)
2834 Tcl_ListObjAppendElement(interp
, resObj
,
2835 Tcl_NewStringObj(vtmp
->changed_val
.p
[0]
2836 ? vtmp
->changed_val
.p
2840 if(vtmp
->current_val
.p
)
2841 Tcl_ListObjAppendElement(interp
, resObj
,
2842 Tcl_NewStringObj(vtmp
->current_val
.p
[0]
2843 ? vtmp
->current_val
.p
2847 Tcl_ListObjAppendElement(interp
,
2848 Tcl_GetObjResult(interp
),
2850 secObj
= Tcl_NewListObj(0, NULL
);
2852 input_type
= cpystr("textarea");
2854 NAMEVAL_S
*(*tmpf
)(int);
2855 switch(vtmp
- wps_global
->vars
){
2856 case V_SAVED_MSG_NAME_RULE
:
2857 tmpf
= save_msg_rules
;
2863 tmpf
= sort_key_rules
;
2865 case V_AB_SORT_RULE
:
2866 tmpf
= ab_sort_rules
;
2868 case V_FLD_SORT_RULE
:
2869 tmpf
= fld_sort_rules
;
2871 case V_GOTO_DEFAULT_RULE
:
2874 case V_INCOMING_STARTUP
:
2875 tmpf
= incoming_startup_rules
;
2877 case V_PRUNING_RULE
:
2878 tmpf
= pruning_rules
;
2880 case V_WP_INDEXHEIGHT
:
2881 tmpf
= wp_indexheight_rules
;
2888 for(i
= 0; (tmpnv
= (tmpf
)(i
)); i
++){
2889 if(tmpnv
->shortname
)
2890 peAppListF(interp
, secObj
, "%s%s", tmpnv
->name
, tmpnv
->shortname
);
2892 Tcl_ListObjAppendElement(interp
, secObj
,
2893 Tcl_NewStringObj(tmpnv
->name
, -1));
2895 input_type
= cpystr("listbox");
2898 input_type
= cpystr("text");
2900 Tcl_ListObjAppendElement(interp
,
2901 Tcl_GetObjResult(interp
),
2902 Tcl_NewStringObj(input_type
, -1));
2903 Tcl_ListObjAppendElement(interp
,
2904 Tcl_GetObjResult(interp
),
2907 is_default
= !vtmp
->is_changed_val
&& !vtmp
->main_user_val
.l
;
2909 is_default
= !vtmp
->is_changed_val
&& !vtmp
->main_user_val
.p
;
2910 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2911 Tcl_NewIntObj(is_default
));
2912 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
2913 Tcl_NewIntObj(vtmp
->is_fixed
));
2916 else if(!strcmp(s1
, "filtextended")){
2918 long rflags
= ROLE_DO_FILTER
| PAT_USE_CHANGED
;
2921 Tcl_Obj
*resObj
= NULL
, *tObj
= NULL
;
2923 if(Tcl_GetIntFromObj(interp
, objv
[2], &fl
) == TCL_ERROR
)
2926 close_every_pattern();
2927 if(any_patterns(rflags
, &pstate
)){
2928 for(pat
= first_pattern(&pstate
), i
= 0;
2930 pat
= next_pattern(&pstate
), i
++);
2935 /* append the pattern ID */
2936 tObj
= Tcl_NewListObj(0, NULL
);
2937 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("id", -1));
2938 pePatAppendID(interp
, tObj
, pat
);
2939 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
2941 /* append the pattern */
2942 tObj
= Tcl_NewListObj(0, NULL
);
2943 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("pattern", -1));
2944 pePatAppendPattern(interp
, tObj
, pat
);
2945 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
2947 /* now append the filter action */
2948 resObj
= Tcl_NewListObj(0, NULL
);
2949 peAppListF(interp
, resObj
, "%s%i", "kill", pat
->action
->folder
? 0 : 1);
2950 peAppListF(interp
, resObj
, "%s%p", "folder", pat
->action
->folder
);
2951 peAppListF(interp
, resObj
, "%s%i", "move_only_if_not_deleted",
2952 pat
->action
->move_only_if_not_deleted
);
2953 tObj
= Tcl_NewListObj(0, NULL
);
2954 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("filtaction", -1));
2955 Tcl_ListObjAppendElement(interp
, tObj
, resObj
);
2956 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
2958 else return(TCL_ERROR
);
2962 else if(!strcmp(s1
, "indexcolorextended")){
2964 long rflags
= ROLE_DO_INCOLS
| PAT_USE_CHANGED
;
2967 Tcl_Obj
*resObj
= NULL
, *tObj
= NULL
;
2969 if(Tcl_GetIntFromObj(interp
, objv
[2], &fl
) == TCL_ERROR
)
2972 close_every_pattern();
2973 if(any_patterns(rflags
, &pstate
)){
2974 for(pat
= first_pattern(&pstate
), i
= 0;
2976 pat
= next_pattern(&pstate
), i
++);
2981 /* append the pattern ID */
2982 tObj
= Tcl_NewListObj(0, NULL
);
2983 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("id", -1));
2984 pePatAppendID(interp
, tObj
, pat
);
2985 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
2987 /* append the pattern */
2988 tObj
= Tcl_NewListObj(0, NULL
);
2989 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("pattern", -1));
2990 pePatAppendPattern(interp
, tObj
, pat
);
2991 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
2993 /* now append the pattern colors */
2994 resObj
= Tcl_NewListObj(0, NULL
);
2995 tObj
= Tcl_NewListObj(0, NULL
);
2996 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("indexcolor", -1));
2997 if(pat
->action
->is_a_incol
){
2999 Tcl_Obj
*colObj
= Tcl_NewListObj(0, NULL
);
3001 if(!(pat
->action
->incol
3002 && pat
->action
->incol
->fg
3003 && pat
->action
->incol
->fg
[0]
3004 && (color
= color_to_asciirgb(pat
->action
->incol
->fg
))
3005 && (color
= peColorStr(color
,wtmp_20k_buf
))))
3008 Tcl_ListObjAppendElement(interp
, colObj
, Tcl_NewStringObj(color
, -1));
3010 if(!(pat
->action
->incol
3011 && pat
->action
->incol
->bg
3012 && pat
->action
->incol
->bg
[0]
3013 && (color
= color_to_asciirgb(pat
->action
->incol
->bg
))
3014 && (color
= peColorStr(color
,wtmp_20k_buf
))))
3017 Tcl_ListObjAppendElement(interp
, colObj
, Tcl_NewStringObj(color
, -1));
3018 Tcl_ListObjAppendElement(interp
, tObj
, colObj
);
3020 Tcl_ListObjAppendElement(interp
, resObj
, tObj
);
3022 tObj
= Tcl_NewListObj(0, NULL
);
3023 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("indexcolors", -1));
3024 Tcl_ListObjAppendElement(interp
, tObj
, resObj
);
3025 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
3027 else return(TCL_ERROR
);
3031 else if(!strcmp(s1
, "scoreextended")){
3033 long rflags
= ROLE_DO_SCORES
| PAT_USE_CHANGED
;
3037 Tcl_Obj
*resObj
= NULL
, *tObj
= NULL
;
3039 if(Tcl_GetIntFromObj(interp
, objv
[2], &fl
) == TCL_ERROR
)
3042 close_every_pattern();
3043 if(any_patterns(rflags
, &pstate
)){
3044 for(pat
= first_pattern(&pstate
), i
= 0;
3046 pat
= next_pattern(&pstate
), i
++);
3051 /* append the pattern ID */
3052 tObj
= Tcl_NewListObj(0, NULL
);
3053 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("id", -1));
3054 pePatAppendID(interp
, tObj
, pat
);
3055 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
3057 /* append the pattern */
3058 tObj
= Tcl_NewListObj(0, NULL
);
3059 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("pattern", -1));
3060 pePatAppendPattern(interp
, tObj
, pat
);
3061 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
3063 /* now append the filter action */
3064 resObj
= Tcl_NewListObj(0, NULL
);
3065 peAppListF(interp
, resObj
, "%s%l", "scoreval", pat
->action
->scoreval
);
3066 if(pat
->action
->scorevalhdrtok
)
3067 hdr
= hdrtok_to_stringform(pat
->action
->scorevalhdrtok
);
3069 peAppListF(interp
, resObj
, "%s%s", "scorehdr", hdr
? hdr
: "");
3072 fs_give((void **) &hdr
);
3074 tObj
= Tcl_NewListObj(0, NULL
);
3075 Tcl_ListObjAppendElement(interp
, tObj
, Tcl_NewStringObj("scores", -1));
3076 Tcl_ListObjAppendElement(interp
, tObj
, resObj
);
3077 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
3079 else return(TCL_ERROR
);
3083 else if(!strcmp(s1
, "clextended")){
3084 int cl
, i
, j
= 0, in_folder_spec
= 0;
3085 struct variable
*vtmp
;
3086 char tpath
[MAILTMPLEN
], *p
;
3089 vtmp
= &wps_global
->vars
[V_FOLDER_SPEC
];
3090 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
)
3092 for(i
= 0; i
< cl
&& (vtmp
->is_changed_val
3093 ? (vtmp
->changed_val
.l
3094 && vtmp
->changed_val
.l
[i
])
3095 : (vtmp
->current_val
.l
3096 && vtmp
->current_val
.l
[i
])); i
++);
3097 if(i
== cl
&& (vtmp
->is_changed_val
3098 ? vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]
3099 : vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]))
3102 vtmp
= &wps_global
->vars
[V_NEWS_SPEC
];
3103 for(j
= 0; i
+ j
< cl
&& (vtmp
->is_changed_val
3104 ? (vtmp
->changed_val
.l
3105 && vtmp
->changed_val
.l
[j
])
3106 : (vtmp
->current_val
.l
3107 && vtmp
->current_val
.l
[j
])); j
++);
3109 if(in_folder_spec
|| (i
+ j
== cl
&& (vtmp
->is_changed_val
3110 ? vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
]
3111 : vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
]))){
3112 ctxt
= new_context(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[in_folder_spec
? i
: j
]
3113 : vtmp
->current_val
.l
[in_folder_spec
? i
: j
], NULL
);
3114 Tcl_ListObjAppendElement(interp
,
3115 Tcl_GetObjResult(interp
),
3116 Tcl_NewStringObj(ctxt
->nickname
? ctxt
->nickname
: "", -1));
3117 Tcl_ListObjAppendElement(interp
,
3118 Tcl_GetObjResult(interp
),
3119 Tcl_NewStringObj(ctxt
->label
? ctxt
->label
: "", -1));
3120 Tcl_ListObjAppendElement(interp
,
3121 Tcl_GetObjResult(interp
),
3122 Tcl_NewStringObj(ctxt
->server
? ctxt
->server
: "", -1));
3125 strncpy(tpath
, (ctxt
->context
[0] == '{'
3126 && (p
= strchr(ctxt
->context
, '}')))
3128 : ctxt
->context
, sizeof(tpath
));
3129 tpath
[sizeof(tpath
)-1] = '\0';
3130 if((p
= strstr(tpath
, "%s")) != NULL
)
3133 Tcl_ListObjAppendElement(interp
,
3134 Tcl_GetObjResult(interp
),
3135 Tcl_NewStringObj(tpath
, -1));
3136 Tcl_ListObjAppendElement(interp
,
3137 Tcl_GetObjResult(interp
),
3138 Tcl_NewStringObj(ctxt
->dir
&& ctxt
->dir
->view
.user
3139 ? ctxt
->dir
->view
.user
: "", -1));
3140 free_context(&ctxt
);
3147 else if(!strcmp(s1
, "rawsig")){
3148 struct variable
*vtmp
;
3149 char *cstring_version
, *sig
, *line
;
3153 vtmp
= &wps_global
->vars
[V_LITERAL_SIG
];
3154 if(vtmp
->is_changed_val
? vtmp
->changed_val
.p
3155 : wps_global
->VAR_LITERAL_SIG
){
3157 wtmp_20k_buf
[0] = '\0';
3158 Tcl_ListObjGetElements(interp
, objv
[2], &nSig
, &objSig
);
3159 for(i
= 0; i
< nSig
&& i
< SIG_MAX_LINES
; i
++)
3160 if((line
= Tcl_GetStringFromObj(objSig
[i
], NULL
)) != NULL
)
3161 snprintf(wtmp_20k_buf
+ strlen(wtmp_20k_buf
), SIZEOF_20KBUF
- strlen(wtmp_20k_buf
), "%.*s\n", SIG_MAX_COLS
, line
);
3163 sig
= cpystr(wtmp_20k_buf
);
3165 if((cstring_version
= string_to_cstring(sig
)) != NULL
){
3166 if(vtmp
->changed_val
.p
)
3167 fs_give((void **)&vtmp
->changed_val
.p
);
3168 vtmp
->is_changed_val
= 1;
3169 vtmp
->changed_val
.p
= cstring_version
;
3172 fs_give((void **) &sig
);
3177 for(i
= 0; peTSig
[i
]; i
++)
3178 fs_give((void **)&peTSig
[i
]);
3179 fs_give((void **)&peTSig
);
3181 Tcl_ListObjGetElements(interp
, objv
[2], &nSig
, &objSig
);
3182 peTSig
= (char **)fs_get(sizeof(char)*(nSig
+ 1));
3183 for(i
= 0; i
< nSig
; i
++){
3184 line
= Tcl_GetStringFromObj(objSig
[i
], NULL
);
3185 peTSig
[i
] = cpystr(line
? line
: "");
3191 else if(!strcmp(s1
, "colorget")){
3193 char tvname
[256], hexcolor
[256];
3194 struct variable
*vtmp
;
3195 if(!(varname
= Tcl_GetStringFromObj(objv
[2], NULL
))){
3198 if(strcmp("viewer-hdr-colors", varname
) == 0){
3199 SPEC_COLOR_S
*hcolors
, *thc
;
3201 char hexcolor
[256], *tstr
= NULL
;
3203 if(wps_global
->vars
[V_VIEW_HDR_COLORS
].is_changed_val
)
3204 hcolors
= spec_colors_from_varlist(wps_global
->vars
[V_VIEW_HDR_COLORS
].changed_val
.l
, 0);
3206 hcolors
= spec_colors_from_varlist(wps_global
->VAR_VIEW_HDR_COLORS
, 0);
3207 for(thc
= hcolors
; thc
; thc
= thc
->next
){
3208 resObj
= Tcl_NewListObj(0,NULL
);
3209 Tcl_ListObjAppendElement(interp
, resObj
,
3210 Tcl_NewStringObj(thc
->spec
, -1));
3211 hex_colorstr(hexcolor
, thc
->fg
);
3212 Tcl_ListObjAppendElement(interp
, resObj
,
3213 Tcl_NewStringObj(hexcolor
, -1));
3214 hex_colorstr(hexcolor
, thc
->bg
);
3215 Tcl_ListObjAppendElement(interp
, resObj
,
3216 Tcl_NewStringObj(hexcolor
, -1));
3217 Tcl_ListObjAppendElement(interp
, resObj
,
3218 Tcl_NewStringObj(thc
->val
3219 ? tstr
= pattern_to_string(thc
->val
)
3221 if(tstr
) fs_give((void **)&tstr
);
3222 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
3225 fs_give((void **)&hcolors
);
3231 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-foreground-color");
3233 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
3234 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
3238 if(!vtmp
->name
) return(TCL_ERROR
);
3239 if(vtmp
->is_list
) return(TCL_ERROR
);
3241 colorp
= (vtmp
->is_changed_val
&& vtmp
->changed_val
.p
)
3242 ? vtmp
->changed_val
.p
3243 : (vtmp
->current_val
.p
) ? vtmp
->current_val
.p
3244 : vtmp
->global_val
.p
;
3247 hex_colorstr(hexcolor
, colorp
);
3248 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
3249 Tcl_NewStringObj(hexcolor
, -1));
3252 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
3253 Tcl_NewStringObj("", -1));
3255 snprintf(tvname
, sizeof(tvname
), "%.200s%.50s", varname
, "-background-color");
3257 if((vtmp
->name
&& strucmp(vtmp
->name
, tvname
)) || !vtmp
->name
)
3258 for(vtmp
= &wps_global
->vars
[V_NORM_FORE_COLOR
];
3259 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
3263 if(!vtmp
->name
) return(TCL_ERROR
);
3264 if(vtmp
->is_list
) return(TCL_ERROR
);
3266 colorp
= (vtmp
->is_changed_val
&& vtmp
->changed_val
.p
)
3267 ? vtmp
->changed_val
.p
3268 : (vtmp
->current_val
.p
) ? vtmp
->current_val
.p
3269 : vtmp
->global_val
.p
;
3272 hex_colorstr(hexcolor
, colorp
);
3273 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
3274 Tcl_NewStringObj(hexcolor
, -1));
3277 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
3278 Tcl_NewStringObj("", -1));
3282 else if(!strcmp(s1
, "cldel")){
3284 struct variable
*vtmp
;
3287 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
)
3289 vtmp
= &wps_global
->vars
[V_FOLDER_SPEC
];
3290 for(i
= 0; i
< cl
&& (vtmp
->is_changed_val
3291 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3292 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
])); i
++);
3293 if(!(i
== cl
&& (vtmp
->is_changed_val
3294 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3295 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
])))){
3296 vtmp
= &wps_global
->vars
[V_NEWS_SPEC
];
3297 for(j
= 0; i
+ j
< cl
&& (vtmp
->is_changed_val
3298 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3299 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
]));
3301 if(!(vtmp
->is_changed_val
3302 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3303 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
])))
3307 for(n
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[n
])
3308 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[n
]); n
++);
3309 newl
= (char **)fs_get(n
*(sizeof(char *)));
3310 for(n
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[n
])
3311 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[n
]); n
++){
3313 newl
[n
] = cpystr(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[n
]
3314 : vtmp
->current_val
.l
[n
]);
3316 newl
[n
-1] = cpystr(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[n
]
3317 : vtmp
->current_val
.l
[n
]);
3320 vtmp
->is_changed_val
= 1;
3321 for(n
= 0; vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[n
]; n
++)
3322 fs_give((void **) &vtmp
->changed_val
.l
[n
]);
3323 if(vtmp
->changed_val
.l
) fs_give((void **)&vtmp
->changed_val
.l
);
3324 vtmp
->changed_val
.l
= newl
;
3328 else if(!strcmp(s1
, "columns")){
3332 if(Tcl_GetIntFromObj(interp
, objv
[2], &n
) != TCL_ERROR
3333 && n
>= MIN_SCREEN_COLS
3334 && n
< (MAX_SCREEN_COLS
- 1)
3335 && wps_global
->ttyo
->screen_cols
!= n
){
3336 clear_index_cache(sp_inbox_stream(), 0);
3337 wps_global
->ttyo
->screen_cols
= n
;
3338 set_variable(V_WP_COLUMNS
, p
= int2string(n
), 0, 0, Main
);
3339 Tcl_SetResult(interp
, p
, TCL_VOLATILE
);
3342 Tcl_SetResult(interp
, int2string(wps_global
->ttyo
->screen_cols
), TCL_VOLATILE
);
3346 else if(!strcmp(s1
, "reset")){
3349 if((p
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
3350 if(!strcmp(p
,"pinerc")){
3351 struct variable
*var
;
3354 /* new pinerc structure, copy location pointers */
3355 prc
= new_pinerc_s(wps_global
->prc
->name
);
3356 prc
->type
= wps_global
->prc
->type
;
3357 prc
->rd
= wps_global
->prc
->rd
;
3358 prc
->outstanding_pinerc_changes
= 1;
3360 /* tie off original pinerc struct and free it */
3361 wps_global
->prc
->rd
= NULL
;
3362 wps_global
->prc
->outstanding_pinerc_changes
= 0;
3363 free_pinerc_s(&wps_global
->prc
);
3365 /* set global->prc to new struct with no pinerc_lines
3366 * and fool write_pinerc into not writing changed vars
3368 wps_global
->prc
= prc
;
3371 * write at least one var into nearly empty pinerc
3372 * and clear user's var settings. clear global cause
3373 * they'll get reset in peInitVars
3375 for(var
= wps_global
->vars
; var
->name
!= NULL
; var
++){
3376 var
->been_written
= ((var
- wps_global
->vars
) != V_LAST_VERS_USED
);
3378 free_list_array(&var
->main_user_val
.l
);
3379 free_list_array(&var
->global_val
.l
);
3382 fs_give((void **)&var
->main_user_val
.p
);
3383 fs_give((void **)&var
->global_val
.p
);
3387 write_pinerc(wps_global
, Main
, WRP_NOUSER
| WRP_PRESERV_WRITTEN
);
3389 peInitVars(wps_global
);
3396 if(!strcmp(s1
, "varset")){
3397 char *varname
= Tcl_GetStringFromObj(objv
[2], NULL
);
3398 struct variable
*vtmp
;
3399 char **tstrlist
= NULL
, *line
, *tline
;
3401 int i
, strlistpos
, numlistvals
;
3403 if(varname
== NULL
) return(TCL_ERROR
);
3404 for(vtmp
= wps_global
->vars
;
3405 vtmp
->name
&& strucmp(vtmp
->name
, varname
);
3409 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
3412 if(Tcl_ListObjGetElements(interp
, objv
[3], &numlistvals
,
3415 vtmp
->is_changed_val
= 1;
3417 if(vtmp
->changed_val
.l
){
3418 for(i
= 0; vtmp
->changed_val
.l
[i
]; i
++)
3419 fs_give((void **)&vtmp
->changed_val
.l
[i
]);
3420 fs_give((void **)&vtmp
->changed_val
.l
);
3423 tstrlist
= (char **)fs_get((numlistvals
+ 1) * sizeof(char *));
3424 for(i
= 0, strlistpos
= 0; i
< numlistvals
; i
++){
3425 if((line
= Tcl_GetStringFromObj(objVal
[i
], 0)) != NULL
){
3426 tline
= cpystr(line
);
3427 removing_leading_and_trailing_white_space(tline
);
3429 tstrlist
[strlistpos
++] = cpystr(tline
);
3430 fs_give((void **) &tline
);
3434 tstrlist
[strlistpos
] = NULL
;
3435 vtmp
->changed_val
.l
= tstrlist
;
3438 if(vtmp
->changed_val
.p
)
3439 fs_give((void **)&vtmp
->changed_val
.p
);
3441 if((line
= Tcl_GetStringFromObj(objVal
[0], 0)) != NULL
){
3442 tline
= cpystr(line
);
3443 if(strucmp(vtmp
->name
, "reply-indent-string"))
3444 removing_leading_and_trailing_white_space(tline
);
3445 if(!strcmp(tline
, "\"\"")){
3448 else if(tline
[0] == '\0'){
3449 fs_give((void **)&tline
);
3452 vtmp
->changed_val
.p
= cpystr(tline
);
3453 fs_give((void **)&tline
);
3457 vtmp
->changed_val
.p
= cpystr("");
3462 else if(!strcmp(s1
, "feature")){
3464 int i
, set
, wasset
= 0;
3470 * ARGS: featurename -
3471 * value - new value to assign flag
3473 * Returns: 1 if named feature set, 0 otherwise
3476 if((featurename
= Tcl_GetStringFromObj(objv
[2], NULL
))
3477 && Tcl_GetIntFromObj(interp
, objv
[3], &set
) != TCL_ERROR
)
3478 for(i
= 0; (feature
= feature_list(i
)); i
++)
3479 if(!strucmp(featurename
, feature
->name
)){
3480 wps_global
->vars
[V_FEATURE_LIST
].is_changed_val
= 1;
3481 wasset
= F_CH_ON(feature
->id
);
3482 F_CH_SET(feature
->id
, set
);
3486 Tcl_SetResult(interp
, int2string(wasset
), TCL_VOLATILE
);
3489 else if(!strcmp(s1
, "clshuff")){
3490 char *dir
, *tstr
, **newl
;
3491 int cl
, up
= 0, fvarn
, nvarn
, icnt
, i
;
3492 struct variable
*fvar
, *nvar
, *vtmp
;
3494 if(!(dir
= Tcl_GetStringFromObj(objv
[2], NULL
)))
3496 if(Tcl_GetIntFromObj(interp
, objv
[3], &cl
) == TCL_ERROR
)
3498 if(!strcmp(dir
, "up"))
3500 else if(!strcmp(dir
, "down"))
3504 fvar
= &wps_global
->vars
[V_FOLDER_SPEC
];
3505 nvar
= &wps_global
->vars
[V_NEWS_SPEC
];
3506 for(fvarn
= 0; fvar
->is_changed_val
? (fvar
->changed_val
.l
&& fvar
->changed_val
.l
[fvarn
])
3507 : (fvar
->current_val
.l
&& fvar
->current_val
.l
[fvarn
]); fvarn
++);
3508 for(nvarn
= 0; nvar
->is_changed_val
? (nvar
->changed_val
.l
&& nvar
->changed_val
.l
[nvarn
])
3509 : (nvar
->current_val
.l
&& nvar
->current_val
.l
[nvarn
]); nvarn
++);
3514 else if(cl
>= fvarn
&& cl
< nvarn
+ fvarn
){
3520 if(vtmp
== nvar
&& icnt
== 0 && up
){
3521 newl
= (char **)fs_get((fvarn
+ 2)*sizeof(char *));
3522 for(i
= 0; fvar
->is_changed_val
? (fvar
->changed_val
.l
&& fvar
->changed_val
.l
[i
])
3523 : (fvar
->current_val
.l
&& fvar
->current_val
.l
[i
]); i
++)
3524 newl
[i
] = cpystr(fvar
->is_changed_val
? fvar
->changed_val
.l
[i
]
3525 : fvar
->current_val
.l
[i
]);
3526 newl
[i
++] = cpystr(nvar
->is_changed_val
? nvar
->changed_val
.l
[0]
3527 : nvar
->current_val
.l
[0]);
3529 fvar
->is_changed_val
= 1;
3530 for(i
= 0; fvar
->changed_val
.l
&& fvar
->changed_val
.l
[i
]; i
++)
3531 fs_give((void **)&fvar
->changed_val
.l
[i
]);
3532 if(fvar
->changed_val
.l
) fs_give((void **)&fvar
->changed_val
.l
);
3533 fvar
->changed_val
.l
= newl
;
3534 newl
= (char **)fs_get(nvarn
*sizeof(char *));
3535 for(i
= 1; nvar
->is_changed_val
? (nvar
->changed_val
.l
&& nvar
->changed_val
.l
[i
])
3536 : (nvar
->current_val
.l
&& nvar
->current_val
.l
[i
]); i
++)
3537 newl
[i
-1] = cpystr(nvar
->is_changed_val
? nvar
->changed_val
.l
[i
]
3538 : nvar
->current_val
.l
[i
]);
3540 nvar
->is_changed_val
= 1;
3541 for(i
= 0; nvar
->changed_val
.l
&& nvar
->changed_val
.l
[i
]; i
++)
3542 fs_give((void **)&nvar
->changed_val
.l
[i
]);
3543 if(nvar
->changed_val
.l
) fs_give((void **)&nvar
->changed_val
.l
);
3544 nvar
->changed_val
.l
= newl
;
3548 else if(vtmp
== fvar
&& icnt
== fvarn
- 1 && !up
){
3549 newl
= (char **)fs_get(fvarn
*sizeof(char *));
3550 for(i
= 0; fvar
->is_changed_val
? (fvar
->changed_val
.l
&& fvar
->changed_val
.l
[i
+1])
3551 : (fvar
->current_val
.l
&& fvar
->current_val
.l
[i
+1]); i
++)
3552 newl
[i
] = cpystr(fvar
->is_changed_val
? fvar
->changed_val
.l
[i
]
3553 : fvar
->current_val
.l
[i
]);
3555 tstr
= cpystr(fvar
->is_changed_val
? fvar
->changed_val
.l
[i
]
3556 : fvar
->current_val
.l
[i
]);
3557 fvar
->is_changed_val
= 1;
3558 for(i
= 0; fvar
->changed_val
.l
&& fvar
->changed_val
.l
[i
]; i
++)
3559 fs_give((void **)&fvar
->changed_val
.l
[i
]);
3560 if(fvar
->changed_val
.l
) fs_give((void **)&fvar
->changed_val
.l
);
3561 fvar
->changed_val
.l
= newl
;
3562 newl
= (char **)fs_get((nvarn
+2)*sizeof(char *));
3564 for(i
= 0; nvar
->is_changed_val
? (nvar
->changed_val
.l
&& nvar
->changed_val
.l
[i
])
3565 : (nvar
->current_val
.l
&& nvar
->current_val
.l
[i
]); i
++)
3566 newl
[i
+1] = cpystr(nvar
->is_changed_val
? nvar
->changed_val
.l
[i
]
3567 : nvar
->current_val
.l
[i
]);
3569 nvar
->is_changed_val
= 1;
3570 for(i
= 0; nvar
->changed_val
.l
&& nvar
->changed_val
.l
[i
]; i
++)
3571 fs_give((void **)&nvar
->changed_val
.l
[i
]);
3572 if(nvar
->changed_val
.l
) fs_give((void **)&nvar
->changed_val
.l
);
3573 nvar
->changed_val
.l
= newl
;
3578 newl
= (char **)fs_get(((vtmp
== fvar
? fvarn
: nvarn
) + 1)*sizeof(char *));
3579 for(i
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3580 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]); i
++)
3581 newl
[i
] = cpystr(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[i
]
3582 : vtmp
->current_val
.l
[i
]);
3584 vtmp
->is_changed_val
= 1;
3585 for(i
= 0; vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
]; i
++)
3586 fs_give((void **)&vtmp
->changed_val
.l
[i
]);
3587 if(vtmp
->changed_val
.l
) fs_give((void **)&vtmp
->changed_val
.l
);
3588 vtmp
->changed_val
.l
= newl
;
3591 tstr
= vtmp
->changed_val
.l
[icnt
-1];
3592 vtmp
->changed_val
.l
[icnt
-1] = vtmp
->changed_val
.l
[icnt
];
3593 vtmp
->changed_val
.l
[icnt
] = tstr
;
3596 tstr
= vtmp
->changed_val
.l
[icnt
+1];
3597 vtmp
->changed_val
.l
[icnt
+1] = vtmp
->changed_val
.l
[icnt
];
3598 vtmp
->changed_val
.l
[icnt
] = tstr
;
3604 if(!strcmp(s1
, "cledit") || !strcmp(s1
, "cladd")){
3605 int add
= 0, cl
, quotes_needed
= 0, i
, j
, newn
;
3606 char *nick
, *server
, *path
, *view
, context_buf
[MAILTMPLEN
*4];
3608 struct variable
*vtmp
;
3610 if(!strcmp(s1
, "cladd")) add
= 1;
3612 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
)
3614 if(!(nick
= Tcl_GetStringFromObj(objv
[3], NULL
)))
3616 if(!(server
= Tcl_GetStringFromObj(objv
[4], NULL
)))
3618 if(!(path
= Tcl_GetStringFromObj(objv
[5], NULL
)))
3620 if(!(view
= Tcl_GetStringFromObj(objv
[6], NULL
)))
3622 removing_leading_and_trailing_white_space(nick
);
3623 removing_leading_and_trailing_white_space(server
);
3624 removing_leading_and_trailing_white_space(path
);
3625 removing_leading_and_trailing_white_space(view
);
3626 if(strchr(nick
, ' '))
3628 if(strlen(nick
)+strlen(server
)+strlen(path
)+strlen(view
) >
3629 MAILTMPLEN
* 4 - 20) { /* for good measure */
3630 Tcl_SetResult(interp
, "info too long", TCL_VOLATILE
);
3633 if(3 + strlen(nick
) + strlen(server
) + strlen(path
) +
3634 strlen(view
) > MAILTMPLEN
+ 4){
3635 Tcl_SetResult(interp
, "collection fields too long", TCL_VOLATILE
);
3638 snprintf(context_buf
, sizeof(context_buf
), "%s%s%s%s%s%s[%s]", quotes_needed
?
3639 "\"" : "", nick
, quotes_needed
? "\"" : "",
3640 strlen(nick
) ? " " : "",
3641 server
, path
, view
);
3643 vtmp
= &wps_global
->vars
[V_NEWS_SPEC
];
3644 if(!(vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[0])
3645 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[0])))
3646 vtmp
= &wps_global
->vars
[V_FOLDER_SPEC
];
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
++);
3650 newl
= (char **)fs_get((newn
+ 1)*sizeof(char *));
3651 for(i
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3652 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
]); i
++)
3653 newl
[i
] = cpystr(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[i
]
3654 : vtmp
->current_val
.l
[i
]);
3655 newl
[i
++] = cpystr(context_buf
);
3659 vtmp
= &wps_global
->vars
[V_FOLDER_SPEC
];
3660 for(i
= 0; i
< cl
&& (vtmp
->is_changed_val
3661 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3662 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
])); i
++);
3663 if(!(i
== cl
&& (vtmp
->is_changed_val
3664 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[i
])
3665 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[i
])))){
3666 vtmp
= &wps_global
->vars
[V_NEWS_SPEC
];
3667 for(j
= 0; i
+ j
< cl
&& (vtmp
->is_changed_val
3668 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3669 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
]));
3671 if(!(vtmp
->is_changed_val
3672 ? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3673 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
])))
3677 for(j
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3678 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
]); j
++);
3679 newl
= (char **)fs_get(j
* sizeof(char *));
3680 for(j
= 0; vtmp
->is_changed_val
? (vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
])
3681 : (vtmp
->current_val
.l
&& vtmp
->current_val
.l
[j
]); j
++){
3683 newl
[j
] = cpystr(context_buf
);
3685 newl
[j
] = cpystr(vtmp
->is_changed_val
? vtmp
->changed_val
.l
[j
]
3686 : vtmp
->current_val
.l
[j
]);
3690 vtmp
->is_changed_val
= 1;
3691 for(j
= 0; vtmp
->changed_val
.l
&& vtmp
->changed_val
.l
[j
]; j
++)
3692 fs_give((void **)&vtmp
->changed_val
.l
[j
]);
3693 if(vtmp
->changed_val
.l
) fs_give((void **)&vtmp
->changed_val
.l
);
3694 vtmp
->changed_val
.l
= newl
;
3699 err
= "PEInfo: Too many arguments";
3701 Tcl_SetResult(interp
, err
, TCL_STATIC
);
3707 peWriteSig(Tcl_Interp
*interp
, char *file
, Tcl_Obj
**objv
)
3709 int try_cache
, e
, i
, n
, nSig
;
3710 char datebuf
[200], *sig
, *line
;
3715 if(!(file
&& IS_REMOTE(file
))){
3716 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote signature file: %s",
3717 file
? file
: "<null>");
3718 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3723 * We could parse the name here to find what type it is. So far we
3724 * only have type RemImap.
3726 rd
= rd_create_remote(RemImap
, file
, (void *)REMOTE_SIG_SUBTYPE
,
3727 NULL
, "Error: ", "Can't fetch remote signature.");
3729 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Can't create stream for sig file: %s", file
);
3730 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3734 try_cache
= rd_read_metadata(rd
);
3736 if(rd
->access
== MaybeRorW
){
3737 if(rd
->read_status
== 'R')
3738 rd
->access
= ReadOnly
;
3740 rd
->access
= ReadWrite
;
3743 if(rd
->access
!= NoExists
){
3745 rd_check_remvalid(rd
, 1L);
3748 * If the cached info says it is readonly but
3749 * it looks like it's been fixed now, change it to readwrite.
3751 if(rd
->read_status
== 'R'){
3753 * We go to this trouble since readonly sigfiles
3754 * are likely a mistake. They are usually supposed to be
3755 * readwrite so we open it and check if it's been fixed.
3757 rd_check_readonly_access(rd
);
3758 if(rd
->read_status
== 'W'){
3759 rd
->access
= ReadWrite
;
3760 rd
->flags
|= REM_OUTOFDATE
;
3763 rd_close_remdata(&rd
);
3764 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Readonly sig file: %s", file
);
3765 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3770 if(rd
->flags
& REM_OUTOFDATE
){
3771 if(rd_update_local(rd
) != 0){
3773 dprint((1, "pinerc_remote_open: rd_update_local failed"));
3775 * Don't give up altogether. We still may be
3776 * able to use a cached copy.
3780 dprint((7, "%s: copied remote to local (%ld)",
3781 rd
->rn
, (long)rd
->last_use
));
3785 if(rd
->access
== ReadWrite
)
3786 rd
->flags
|= DO_REMTRIM
;
3789 /* If we couldn't get to remote folder, try using the cached copy */
3790 if(rd
->access
== NoExists
|| rd
->flags
& REM_OUTOFDATE
){
3791 rd_close_remdata(&rd
);
3792 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Unavailable sig file: %s", file
);
3793 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3800 wtmp_20k_buf
[0] = '\0';
3802 Tcl_ListObjGetElements(interp
, objv
[0], &nSig
, &objSig
);
3803 for(i
= 0; i
< nSig
&& i
< SIG_MAX_LINES
; i
++){
3804 if((line
= Tcl_GetStringFromObj(objSig
[i
], NULL
)) != NULL
)
3805 snprintf(wtmp_20k_buf
+ strlen(wtmp_20k_buf
), SIZEOF_20KBUF
- strlen(wtmp_20k_buf
), "%.*s\n",
3806 SIG_MAX_COLS
, line
);
3810 for(i
= 0; peTSig
[i
] && i
< SIG_MAX_LINES
; i
++) {
3811 snprintf(wtmp_20k_buf
+ strlen(wtmp_20k_buf
), SIZEOF_20KBUF
- strlen(wtmp_20k_buf
), "%.*s\n",
3812 SIG_MAX_COLS
, peTSig
[i
]);
3814 for(i
= 0; peTSig
[i
]; i
++)
3815 fs_give((void **)&peTSig
[i
]);
3816 fs_give((void **)&peTSig
);
3821 sig
= cpystr(wtmp_20k_buf
);
3823 if((fp
= fopen(rd
->lf
, "w")) != NULL
)
3824 n
= fwrite(sig
, strlen(sig
), 1, fp
);
3826 fs_give((void **) &sig
);
3830 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Sig copy failure1: %s: %s",
3831 rd
->lf
, error_description(errno
));
3832 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3833 rd_close_remdata(&rd
);
3841 rd_close_remdata(&rd
);
3842 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Sig copy open failure2: %s: %s",
3843 rd
->lf
, error_description(errno
));
3844 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3850 if(!rd
->t
.i
.stream
){
3853 rd
->t
.i
.stream
= context_open(NULL
, NULL
, rd
->rn
, 0L, &retflags
);
3856 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
3857 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Sig update failure: %s: %s",
3858 rd
->lf
, error_description(errno
));
3859 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
3860 rd_close_remdata(&rd
);
3864 rd_update_metadata(rd
, datebuf
);
3865 rd
->read_status
= 'W';
3866 rd_close_remdata(&rd
);
3872 NAMEVAL_S
*sort_key_rules(index
)
3875 static NAMEVAL_S is_rules
[] = {
3885 {"Arrival/Reverse", 0},
3886 {"Date/Reverse", 0},
3887 {"Subject/Reverse", 0},
3889 {"From/Reverse", 0},
3891 {"size/Reverse", 0},
3892 {"tHread/Reverse", 0},
3893 {"OrderedSubj/Reverse", 0}
3896 return((index
>= 0 && index
< (sizeof(is_rules
)/sizeof(is_rules
[0])))
3897 ? &is_rules
[index
] : NULL
);
3900 NAMEVAL_S
*wp_indexheight_rules(index
)
3903 static NAMEVAL_S is_rules
[] = {
3904 {"normal font", "24", 0},
3905 {"smallest font", "20", 0},
3906 {"small font", "22", 0},
3907 {"large font", "28", 0},
3908 {"largest font", "30", 0}
3911 return((index
>= 0 && index
< (sizeof(is_rules
)/sizeof(is_rules
[0])))
3912 ? &is_rules
[index
] : NULL
);
3917 * PEDebugCmd - turn on/off and set various debugging options
3920 PEDebugCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
3924 if(!--objc
){ /* only one arg? */
3925 Tcl_WrongNumArgs(interp
, 1, objv
, "?args?");
3927 else if((s
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
3928 if(!strucmp(s
, "level")){
3932 if(Tcl_GetIntFromObj(interp
, objv
[2], &level
) != TCL_OK
)
3940 dprint((1, "Debug level %d", level
));
3943 dprint((1, "PEDebug ending"));
3948 Tcl_SetResult(interp
, int2string(debug
), TCL_VOLATILE
);
3951 else if(!strucmp(s
, "write")){
3952 if(objc
== 2 && (s
= Tcl_GetStringFromObj(objv
[2], NULL
))){
3954 * script debugging has a high priority since
3955 * statements can be added/removed on the fly
3956 * AND are NOT present by default
3958 dprint((SYSDBG_INFO
, "SCRIPT: %s", s
));
3963 else if(!strucmp(s
, "imap")){
3966 if(Tcl_GetIntFromObj(interp
, objv
[2], &level
) != TCL_OK
)
3971 wps_global
->debug_imap
= 0;
3972 if(wps_global
->mail_stream
)
3973 mail_nodebug(wps_global
->mail_stream
);
3976 else if(level
> 0 && level
< 5){
3978 wps_global
->debug_imap
= level
;
3979 if(wps_global
->mail_stream
)
3980 mail_debug(wps_global
->mail_stream
);
3987 Tcl_SetResult(interp
, "Unknown PEDebug request", TCL_STATIC
);
3995 * PESessionCmd - Export TCL Session-wide command set
3998 PESessionCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
4000 char *op
, *err
= "Unknown PESession option";
4001 char *pe_user
, *pe_host
;
4004 dprint((2, "PESessionCmd"));
4006 if((op
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
4007 if(!strcmp(op
, "open")){
4008 char *s
, *pinerc
, *pineconf
= NULL
;
4011 * CMD: open user remote-pinerc local-default-config
4013 * Initiate a session
4015 * Returns: error string on error, nothing otherwise
4018 if(objc
< 4 || objc
> 5){
4019 Tcl_WrongNumArgs(interp
, 1, objv
, "user password pinerc");
4023 if(!(s
= Tcl_GetStringFromObj(objv
[2], &l
))){
4024 Tcl_SetResult(interp
, "Unknown User", TCL_STATIC
);
4030 pe_user
= cpystr(s
);
4032 #if defined(HAVE_SETENV)
4033 rv
= setenv("WPUSER", pe_user
, 1);
4034 #elif defined(HAVE_PUTENV)
4036 static char putenvbuf
[PUTENV_MAX
];
4038 if(l
+ 8 < PUTENV_MAX
){
4039 if(putenvbuf
[0]) /* only called once, but you never know */
4040 snprintf(putenvbuf
+ 7, PUTENV_MAX
- 7, "%s", pe_user
);
4042 snprintf(putenvbuf
, PUTENV_MAX
, "WPUSER=%s", pe_user
);
4044 rv
= putenv(putenvbuf
);
4052 fs_give((void **) &pe_user
);
4053 Tcl_SetResult(interp
, (errno
== ENOMEM
)
4054 ? "Insufficient Environment Space"
4055 : "Cannot set WPUSER in environment", TCL_STATIC
);
4060 if((pinerc
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
4063 if(mail_valid_net_parse(pinerc
, &mb
)){
4064 pe_host
= cpystr(mb
.host
);
4065 pe_alt
= (mb
.sslflag
|| mb
.tlsflag
);
4068 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote Config: %s", pinerc
);
4069 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
4074 Tcl_SetResult(interp
, "Unknown config location", TCL_STATIC
);
4078 if(objc
== 5 && !(pineconf
= Tcl_GetStringFromObj(objv
[4], NULL
))){
4079 Tcl_SetResult(interp
, "Can't determine global config", TCL_STATIC
);
4083 dprint((SYSDBG_INFO
, "session (%s) %s - %s",
4084 pe_user
, pinerc
, pineconf
? pineconf
: "<none>"));
4086 /* credential cache MUST already be seeded */
4088 /* destroy old user context */
4090 /* destroy open stream */
4091 peDestroyStream(wps_global
);
4093 /* destroy old user context */
4094 peDestroyUserContext(&wps_global
);
4097 /* Establish a user context */
4098 if((s
= peCreateUserContext(interp
, pe_user
, pinerc
, pineconf
)) != NULL
){
4099 Tcl_SetResult(interp
, s
, TCL_VOLATILE
);
4103 fs_give((void **) &pe_user
);
4104 fs_give((void **) &pe_host
);
4108 else if(!strcmp(op
, "close")){
4110 /* destroy any open stream */
4111 peDestroyStream(wps_global
);
4113 /* destroy user context */
4114 peDestroyUserContext(&wps_global
);
4117 Tcl_SetResult(interp
, "BYE", TCL_STATIC
);
4120 else if(!strcmp(op
, "creds")){
4125 err
= "creds: insufficient args";
4127 else if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
4128 && (folder
= Tcl_GetStringFromObj(objv
[3], NULL
))){
4133 * CMD: creds <collection-index> <folder> [user passwd]
4135 * Test for valid credentials to access given folder
4137 * Returns: 1 if so, 0 otherwise
4140 for(i
= 0, cp
= wps_global
? wps_global
->context_list
: NULL
;
4141 i
< 1 || cp
!= NULL
;
4145 char tmp
[MAILTMPLEN
], *p
;
4148 if(folder
[0] == '\0'){
4149 if(cp
->use
& CNTXT_INCMNG
)
4152 folder
= "fake-fake";
4154 else if((cp
->use
& CNTXT_INCMNG
)
4155 && (p
= folder_is_nick(folder
, FOLDERS(cp
), FN_NONE
)))
4159 if(!rv
&& context_allowed(context_apply(tmp
, cp
, folder
, sizeof(tmp
)))){
4162 if(mail_valid_net_parse(tmp
, &mb
)){
4163 if(objc
== 4){ /* check creds */
4164 if(!*mb
.user
&& (p
= alpine_get_user(mb
.host
, (mb
.sslflag
|| mb
.tlsflag
))))
4167 if(alpine_have_passwd(mb
.user
, mb
.host
, (mb
.sslflag
|| mb
.tlsflag
)))
4170 else if(objc
== 6){ /* set creds */
4171 char *user
, *passwd
;
4173 if((user
= Tcl_GetStringFromObj(objv
[4], NULL
))
4174 && (passwd
= Tcl_GetStringFromObj(objv
[5], NULL
))){
4175 if(*mb
.user
&& strcmp(mb
.user
, user
)){
4176 err
= "creds: mismatched user names";
4180 alpine_set_passwd(user
, passwd
, mb
.host
,
4183 || (wps_global
? F_ON(F_PREFER_ALT_AUTH
, wps_global
) : 0));
4187 err
= "creds: unable to read credentials";
4192 err
= "creds: invalid args";
4198 (void) Tcl_ListObjAppendElement(interp
,
4199 Tcl_GetObjResult(interp
),
4204 err
= "creds: Unrecognized collection ID";
4207 err
= "creds: failure to acquire folder and collection ID";
4209 else if(!strcmp(op
, "nocred")){
4214 err
= "No Session active";
4217 err
= "nocred: wrong number of args";
4219 else if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
4220 && (folder
= Tcl_GetStringFromObj(objv
[3], NULL
))){
4225 * CMD: nocred <collection-index> <folder>
4227 * Test for valid credentials to access given folder
4229 * Returns: 1 if so, 0 otherwise
4232 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4235 char tmp
[MAILTMPLEN
], *p
;
4237 if((cp
->use
& CNTXT_INCMNG
)
4238 && (p
= folder_is_nick(folder
, FOLDERS(cp
), FN_NONE
)))
4241 if(context_allowed(context_apply(tmp
, cp
, folder
, sizeof(tmp
)))){
4244 if(mail_valid_net_parse(tmp
, &mb
)){
4245 if(!*mb
.user
&& (p
= alpine_get_user(mb
.host
, (mb
.sslflag
|| mb
.tlsflag
))))
4248 alpine_clear_passwd(mb
.user
, mb
.host
);
4252 (void) Tcl_ListObjAppendElement(interp
,
4253 Tcl_GetObjResult(interp
),
4258 err
= "creds: Unrecognized collection ID";
4261 err
= "creds: failure to acquire folder and collection ID";
4263 else if(!strcmp(op
, "acceptcert")){
4267 if((certhost
= Tcl_GetStringFromObj(objv
[2], NULL
))){
4268 for(p
= &peCertHosts
; *p
; p
= &(*p
)->next
)
4271 *p
= new_strlist(certhost
);
4274 err
= "PESession: no server name";
4276 else if(!strcmp(op
, "random")){
4278 err
= "PESession: random <length>";
4283 if(Tcl_GetIntFromObj(interp
,objv
[2],&l
) != TCL_ERROR
){
4285 Tcl_SetResult(interp
, peRandomString(s
,l
,PRS_MIXED_CASE
), TCL_STATIC
);
4289 err
= "PESession: random length too long";
4292 err
= "PESession: can't get random length";
4295 else if(!strcmp(op
, "authdriver")){
4297 err
= "PESession: authdriver {add | remove} drivername";
4301 if((cmd
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
4302 if((driver
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
4303 if(!strcmp(cmd
,"enable")){
4304 err
= "PESession: authdriver enable disabled for the nonce";
4306 else if(!strcmp(cmd
,"disable")){
4307 if(mail_parameters(NULL
, DISABLE_AUTHENTICATOR
, (void *) driver
)){
4308 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Authentication driver %.30s disabled", driver
);
4309 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
4313 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "PESession: Can't disable %.30s", driver
);
4314 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
4319 err
= "PESession: unknown authdriver operation";
4322 err
= "PESession: Can't read driver name";
4325 err
= "PESesions: Can't read authdriver operation";
4328 else if(!strcmp(op
, "abandon")){
4330 * CMD: abandon [timeout]
4336 err
= "PESession: abandon [timeout]";
4340 if(Tcl_GetLongFromObj(interp
, objv
[2], &t
) == TCL_OK
){
4341 /* ten second minimum and max of default */
4342 if(t
> 0 && t
<= PE_INPUT_TIMEOUT
){
4343 gPEAbandonTimeout
= t
;
4347 err
= "unrecognized timeout";
4350 err
= "Can't read timeout";
4353 else if(!strcmp(op
, "noexpunge")){
4355 * CMD: noexpunge <state>
4361 err
= "PESession: noexpunge <state>";
4365 if(Tcl_GetIntFromObj(interp
, objv
[2], &onoff
) == TCL_OK
){
4366 if(onoff
== 0 || onoff
== 1){
4367 wps_global
->noexpunge_on_close
= onoff
;
4371 err
= "unrecognized on/off state";
4374 err
= "Can't read on/off state";
4377 else if(!strcmp(op
, "setpassphrase")){
4382 err
= "PESession: setpassphrase <state>";
4384 else if((passphrase
= Tcl_GetStringFromObj(objv
[2], NULL
))){
4385 if(wps_global
&& wps_global
->smime
){
4386 strncpy((char *) wps_global
->smime
->passphrase
, passphrase
,
4387 sizeof(wps_global
->smime
->passphrase
));
4388 wps_global
->smime
->passphrase
[sizeof(wps_global
->smime
->passphrase
)-1] = '\0';
4389 wps_global
->smime
->entered_passphrase
= 1;
4390 wps_global
->smime
->need_passphrase
= 0;
4396 err
= "S/MIME not configured for this server";
4399 else if(!strcmp(op
, "expungecheck")) {
4401 * Return open folders and how many deleted messages they have
4403 * return looks something like a list of these:
4404 * {folder-name number-deleted isinbox isincoming}
4411 err
= "PESession: expungecheck <type>";
4414 type
= Tcl_GetStringFromObj(objv
[2], NULL
);
4415 if(type
&& (strcmp(type
, "current") == 0 || strcmp(type
, "quit") == 0)){
4417 if(wps_global
->mail_stream
!= sp_inbox_stream()
4418 || strcmp(type
, "current") == 0){
4419 delete_count
= count_flagged(wps_global
->mail_stream
, F_DEL
);
4420 resObj
= Tcl_NewListObj(0, NULL
);
4421 Tcl_ListObjAppendElement(interp
, resObj
,
4422 Tcl_NewStringObj(pretty_fn(wps_global
->cur_folder
), -1));
4423 Tcl_ListObjAppendElement(interp
, resObj
,
4424 Tcl_NewIntObj(delete_count
));
4425 Tcl_ListObjAppendElement(interp
, resObj
,
4426 Tcl_NewIntObj((wps_global
->mail_stream
4427 == sp_inbox_stream())
4429 Tcl_ListObjAppendElement(interp
, resObj
,
4430 Tcl_NewIntObj((wps_global
->context_current
->use
& CNTXT_INCMNG
)
4432 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
4435 if(strcmp(type
, "quit") == 0){
4436 delete_count
= count_flagged(sp_inbox_stream(), F_DEL
);
4437 resObj
= Tcl_NewListObj(0, NULL
);
4438 Tcl_ListObjAppendElement(interp
, resObj
,
4439 Tcl_NewStringObj("INBOX", -1));
4440 Tcl_ListObjAppendElement(interp
, resObj
,
4441 Tcl_NewIntObj(delete_count
));
4442 Tcl_ListObjAppendElement(interp
, resObj
,
4444 Tcl_ListObjAppendElement(interp
, resObj
,
4446 Tcl_ListObjAppendElement(interp
,
4447 Tcl_GetObjResult(interp
), resObj
);
4452 err
= "PESession: expungecheck unknown type";
4455 else if(!strcmp(op
, "mailcheck")) {
4459 * ARGS: reload -- "1" if we're reloading
4460 * (vs. just checking newmail as a side effect
4461 * of building a new page)
4463 * Return list of folders with new or expunged messages
4465 * return looks something like a list of these:
4466 * {new-count newest-uid announcement-msg}
4468 int reload
, force
= UFU_NONE
, rv
;
4469 time_t now
= time(0);
4472 if(objc
< 3 || Tcl_GetIntFromObj(interp
, objv
[2], &reload
) == TCL_ERROR
)
4475 /* minimum 10 second between IMAP pings */
4476 if(!time_of_last_input() || now
- time_of_last_input() > 10){
4482 peED
.interp
= interp
;
4484 /* check for new mail */
4485 new_mail(force
, reload
? GoodTime
: VeryBadTime
, NM_STATUS_MSG
);
4487 if(!reload
){ /* announced */
4488 zero_new_mail_count();
4494 err
= "PESession: mailcheck <reload>";
4498 Tcl_SetResult(interp
, err
, TCL_STATIC
);
4505 * PEFolderChange - create context's directory chain
4506 * corresponding to list of given obj's
4508 * NOTE: caller should call reset_context_folders(cp) to
4509 * clean up data structures this creates before returning
4512 PEFolderChange(Tcl_Interp
*interp
, CONTEXT_S
*cp
, int objc
, Tcl_Obj
*CONST objv
[])
4518 for(i
= 0; i
< objc
; i
++) {
4519 folder
= Tcl_GetStringFromObj(objv
[i
], NULL
);
4521 Tcl_SetResult(interp
, "PEFolderChange: Can't read folder", TCL_VOLATILE
);
4522 reset_context_folders(cp
);
4526 fp
= next_folder_dir(cp
, folder
, 0, NULL
); /* BUG: mail_stream? */
4527 fp
->desc
= folder_lister_desc(cp
, fp
);
4528 fp
->delim
= cp
->dir
->delim
;
4530 fp
->status
|= CNTXT_SUBDIR
;
4538 * PEMakeFolderString:
4541 PEMakeFolderString(Tcl_Interp
*interp
, CONTEXT_S
*cp
, int objc
, Tcl_Obj
*CONST objv
[], char **ppath
)
4544 unsigned long size
,len
;
4545 char *portion
,*path
;
4548 for(i
= 0; i
< objc
; i
++) {
4549 portion
= Tcl_GetStringFromObj(objv
[i
], NULL
);
4551 Tcl_SetResult(interp
, "PEMakeFolderString: Can't read folder",
4556 size
+= strlen(portion
);
4559 path
= (char*) fs_get(size
+ 1);
4561 for(i
= 0; i
< objc
; i
++) {
4562 portion
= Tcl_GetStringFromObj(objv
[i
], NULL
);
4563 len
= strlen(portion
);
4564 if(i
) path
[size
++] = cp
->dir
->delim
;
4565 memcpy(path
+ size
, portion
, len
);
4569 if(ppath
) *ppath
= path
; else fs_give((void**) &path
);
4575 * PEFolderCmd - export various bits of folder information
4578 PEFolderCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
4580 char *op
, errbuf
[256], *err
= "Unknown PEFolder request";
4582 dprint((2, "PEFolderCmd"));
4585 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
4587 else if((op
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
4590 if(!strcmp(op
, "current")){
4597 * Returns: string representing the name of the
4601 for(i
= 0, cp
= wps_global
->context_list
; cp
&& cp
!= wps_global
->context_current
; i
++, cp
= cp
->next
)
4604 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewIntObj(cp
? i
: 0)) == TCL_OK
4605 && Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(wps_global
->cur_folder
,-1)) == TCL_OK
)
4610 else if(!strcmp(op
, "collections")){
4617 * Returns: List of currently configured collections
4619 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
){
4622 objv
[0] = Tcl_NewIntObj(i
);
4623 objv
[1] = Tcl_NewStringObj(cp
->nickname
? cp
->nickname
: "", -1);
4624 objv
[2] = Tcl_NewStringObj(cp
->label
? cp
->label
: "", -1);
4626 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
4627 Tcl_NewListObj(3, objv
));
4632 else if(!strcmp(op
, "defaultcollection")){
4636 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4637 if(cp
->use
& CNTXT_SAVEDFLT
){
4638 Tcl_SetResult(interp
, int2string(i
), TCL_STATIC
);
4642 err
= "PEFolder: isincoming: Invalid collection ID";
4644 else if(!strcmp(op
, "clextended")){
4647 char tpath
[MAILTMPLEN
], *p
;
4652 * Returns: Extended list of current collections
4655 * 0) Collection Number
4658 * 3) Basically this is a flag to say if we can edit
4664 * had to get rid of this cause the args are changed
4666 * if(strcmp("extended",
4667 * Tcl_GetStringFromObj(objv[2], NULL))){
4668 * Tcl_SetResult(interp, "invalid argument", TCL_VOLATILE);
4669 * return(TCL_ERROR);
4672 for(i
= 0, cp
= wps_global
->context_list
; cp
;
4673 i
++, cp
= cp
->next
){
4676 objv
[0] = Tcl_NewIntObj(i
);
4677 objv
[1] = Tcl_NewStringObj(cp
->nickname
?
4678 cp
->nickname
: "", -1);
4679 objv
[2] = Tcl_NewStringObj(cp
->label
?
4680 cp
->label
: "", -1);
4681 objv
[3] = Tcl_NewIntObj(cp
->var
.v
? 1 : 0);
4682 objv
[4] = Tcl_NewStringObj(cp
->server
?
4683 cp
->server
: "", -1);
4686 strncpy(tpath
, (cp
->context
[0] == '{'
4687 && (p
= strchr(cp
->context
, '}')))
4689 : cp
->context
, sizeof(tpath
));
4690 tpath
[sizeof(tpath
)-1] = '\0';
4691 if((p
= strstr(tpath
, "%s")) != NULL
)
4694 objv
[5] = Tcl_NewStringObj(tpath
, -1);
4695 objv
[6] = Tcl_NewStringObj(cp
->dir
&&
4696 cp
->dir
->view
.user
?
4697 cp
->dir
->view
.user
:
4699 Tcl_ListObjAppendElement(interp
,
4700 Tcl_GetObjResult(interp
),
4701 Tcl_NewListObj(7, objv
));
4707 else if(objc
== 3 && !strcmp(op
, "delimiter")){
4709 char delim
[2] = {'\0', '\0'};
4712 if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
4713 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4715 if(cp
->dir
&& cp
->dir
->delim
)
4716 delim
[0] = cp
->dir
->delim
;
4721 Tcl_SetResult(interp
, delim
[0] ? delim
: "/", TCL_VOLATILE
);
4725 err
= "PEFolder: delimiter: Can't read collection ID";
4727 else if(objc
== 3 && !strcmp(op
, "isincoming")){
4731 if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
4732 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4734 Tcl_SetResult(interp
, int2string(((cp
->use
& CNTXT_INCMNG
) != 0)), TCL_STATIC
);
4738 err
= "PEFolder: isincoming: Invalid collection ID";
4741 err
= "PEFolder: isincoming: Can't read collection ID";
4743 else if(objc
== 4 && !strcmp(op
, "unread")){
4744 char *folder
, tmp
[MAILTMPLEN
];
4745 MAILSTREAM
*mstream
;
4747 long colid
, i
, count
= 0, flags
= (F_UNSEEN
| F_UNDEL
);
4752 * Returns: number of unread messages in given
4755 if(Tcl_GetLongFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
4756 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4761 if((folder
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
4762 /* short circuit INBOX */
4763 if(colid
== 0 && !strucmp(folder
, "inbox")){
4764 count
= count_flagged(sp_inbox_stream(), flags
);
4768 * BUG: some sort of caching to prevent open() fore each call?
4769 * does stream cache offset this?
4771 if(!(context_allowed(context_apply(tmp
, cp
, folder
, sizeof(tmp
)))
4772 && (mstream
= same_stream_and_mailbox(tmp
, wps_global
->mail_stream
)))){
4775 wps_global
->noshow_error
= 1;
4777 mstream
= context_open(cp
, NULL
, folder
,
4778 SP_USEPOOL
| SP_TEMPUSE
| OP_READONLY
| OP_SHORTCACHE
,
4780 wps_global
->noshow_error
= 0;
4783 count
= count_flagged(mstream
, flags
);
4786 pine_mail_close(mstream
);
4789 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
4794 err
= "PEFolder: unread: Invalid collection ID";
4797 err
= "PEFolder: unread: Can't read collection ID";
4799 else if(objc
== 5 && !strcmp(op
, "empty")){
4803 * Returns: number of expunge messages
4805 * Arguments: <colnum> <folder> <what>
4806 * where <what> is either <uid>, 'selected', or 'all'
4809 MAILSTREAM
*stream
= NULL
;
4812 int colid
, i
, our_stream
= 0;
4813 long uid
, raw
, count
= 0L;
4814 char *errstr
= NULL
, *what
, *folder
, *p
, tmp
[MAILTMPLEN
];
4816 if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
4817 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4818 if(i
== colid
) break;
4822 if((folder
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
4823 if((what
= Tcl_GetStringFromObj(objv
[4], NULL
)) != NULL
){
4825 if(!((context_allowed(context_apply(tmp
, cp
, folder
, sizeof(tmp
)))
4826 && (stream
= same_stream_and_mailbox(tmp
, wps_global
->mail_stream
)))
4827 || (stream
= same_stream_and_mailbox(tmp
, sp_inbox_stream())))){
4831 stream
= context_open(cp
, NULL
, folder
, SP_USEPOOL
| SP_TEMPUSE
| OP_SHORTCACHE
, &retflags
);
4835 msgmap
= sp_msgmap(stream
);
4837 if(!strucmp(what
, "all")){
4838 if(mn_get_total(msgmap
)){
4839 agg_select_all(stream
, msgmap
, NULL
, 1);
4840 errstr
= peApplyFlag(stream
, msgmap
, 'd', 0, &count
);
4842 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
4846 /* little complicated since we don't display deleted state and
4847 * don't want to expunge what's not intended.
4848 * remember what's deleted and restore state on the ones left
4849 * when we're done. shouldn't happen much.
4850 * NOTE: "uid" is NOT a UID in this loop
4852 for(uid
= 1L; uid
<= mn_get_total(msgmap
); uid
++){
4853 raw
= mn_m2raw(msgmap
, uid
);
4854 if(!get_lflag(stream
, msgmap
, uid
, MN_EXLD
)
4855 && (mc
= mail_elt(stream
, raw
)) != NULL
4857 set_lflag(stream
, msgmap
, uid
, MN_STMP
, 1);
4858 mail_flag(stream
, long2string(raw
), "\\DELETED", 0L);
4861 set_lflag(stream
, msgmap
, uid
, MN_STMP
, 0);
4864 if(!strucmp(what
,"selected")){
4865 if(any_lflagged(msgmap
, MN_SLCT
)){
4866 if(!(errstr
= peApplyFlag(stream
, msgmap
, 'd', 0, &count
)))
4867 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
4874 for(p
= what
; *p
; p
++)
4875 if(isdigit((unsigned char) *p
)){
4876 uid
= (uid
* 10) + (*p
- '0');
4879 errstr
= "Invalid uid value";
4884 /* uid is a UID here */
4885 mail_flag(stream
, long2string(uid
), "\\DELETED", ST_SET
| ST_UID
);
4886 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
4891 /* restore deleted on what didn't get expunged */
4892 for(uid
= 1L; uid
<= mn_get_total(msgmap
); uid
++){
4893 raw
= mn_m2raw(msgmap
, uid
);
4894 if(get_lflag(stream
, msgmap
, uid
, MN_STMP
)){
4895 set_lflag(stream
, msgmap
, uid
, MN_STMP
, 0);
4896 mail_flag(stream
, long2string(raw
), "\\DELETED", ST_SET
);
4902 pine_mail_close(stream
);
4905 errstr
= "no stream";
4908 errstr
= "Cannot get which ";
4911 errstr
= "Cannot get folder";
4914 errstr
= "Invalid collection";
4917 Tcl_SetResult(interp
, errstr
, TCL_VOLATILE
);
4921 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
4924 else if(!strcmp(op
, "export")){
4928 * Returns: success or failure after writing given
4929 * folder to given local file.
4932 * 0) Collection Number
4934 * 2) Destination file
4942 char *folder
, *dfile
, seq
[64], tmp
[MAILTMPLEN
];
4945 if(Tcl_GetLongFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
4946 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
4951 if((folder
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
4952 if((dfile
= Tcl_GetStringFromObj(objv
[4], NULL
)) != NULL
){
4953 if(mail_parameters(NULL
, ENABLE_DRIVER
, "unix")){
4955 snprintf(tmp
, sizeof(tmp
), "#driver.unix/%s", dfile
);
4957 if(pine_mail_create(NULL
, tmp
)){
4959 err
= NULL
; /* reset error condition */
4962 * if not current folder, open a stream, setup the
4963 * stuff to write the raw header/text by hand
4964 * with berkeley delimiters since we don't want
4965 * a local mailbox driver lunk in.
4968 * - BUG: what about logins?
4971 if(!(context_allowed(context_apply(tmp
, cp
, folder
, sizeof(tmp
)))
4972 && (src
= same_stream_and_mailbox(tmp
, wps_global
->mail_stream
)))){
4976 src
= context_open(cp
, NULL
, folder
,
4977 SP_USEPOOL
| SP_TEMPUSE
| OP_READONLY
| OP_SHORTCACHE
,
4981 if(src
&& src
->nmsgs
){
4985 pkg
.msgmax
= src
->nmsgs
;
4986 pkg
.flags
= pkg
.date
= NIL
;
4989 snprintf (seq
,sizeof(seq
),"1:%lu",src
->nmsgs
);
4990 mail_fetchfast (src
, seq
);
4992 wps_global
->noshow_error
= 1;
4993 if(!mail_append_multiple (NULL
, dfile
,
4994 peAppendMsg
, (void *) &pkg
)){
4995 snprintf(err
= errbuf
, sizeof(errbuf
), "PEFolder: export: %.200s",
4996 wps_global
->c_client_error
);
4999 wps_global
->noshow_error
= 0;
5002 pine_mail_close(src
);
5005 err
= "PEFolder: export: can't open mail folder";
5011 err
= "PEFolder: export: can't create destination";
5013 if(!mail_parameters(NULL
, DISABLE_DRIVER
, "unix"))
5014 err
= "PEFolder: export: can't disable driver";
5017 err
= "PEFolder: export: can't enable driver";
5020 err
= "PEFolder: export: can't read file name";
5023 err
= "PEFolder: export: can't read folder name";
5026 err
= "PEFolder: export: Invalid collection ID";
5029 err
= "PEFolder:export: Can't read collection ID";
5032 err
= "PEFolder: export <colid> <folder> <file>";
5034 else if(!strcmp(op
, "import")){
5038 * Returns: success or failure after writing given
5039 * folder to given local file.
5043 * 1) destination collection number
5044 * 2) destination folder
5048 MAILSTREAM
*src
, *dst
;
5052 char *folder
, *sfile
, seq
[64];
5054 /* get source file with a little sanity check */
5055 if((sfile
= Tcl_GetStringFromObj(objv
[2], NULL
))
5056 && *sfile
== '/' && !strstr(sfile
, "..")){
5057 if(mail_parameters(NULL
, ENABLE_DRIVER
, "unix")){
5059 wps_global
->noshow_error
= 1; /* don't queue error msg */
5060 err
= NULL
; /* reset error condition */
5062 /* make sure sfile contains valid mail */
5063 if((src
= mail_open(NULL
, sfile
, 0L)) != NULL
){
5065 if(Tcl_GetLongFromObj(interp
,objv
[3],&colid
) != TCL_ERROR
){
5066 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
5071 if((folder
= Tcl_GetStringFromObj(objv
[4], NULL
)) != NULL
){
5074 if(context_create(cp
, NULL
, folder
)
5075 && (dst
= context_open(cp
, NULL
, folder
, SP_USEPOOL
| SP_TEMPUSE
, &retflags
))){
5081 pkg
.msgmax
= src
->nmsgs
;
5082 pkg
.flags
= pkg
.date
= NIL
;
5085 snprintf (seq
,sizeof(seq
),"1:%lu",src
->nmsgs
);
5086 mail_fetchfast (src
, seq
);
5088 if(!context_append_multiple(cp
, dst
, folder
,
5089 peAppendMsg
, (void *) &pkg
,
5090 wps_global
->mail_stream
)){
5091 snprintf(err
= errbuf
, sizeof(errbuf
), "PEFolder: import: %.200s",
5092 wps_global
->c_client_error
);
5097 pine_mail_close(dst
);
5100 snprintf(err
= errbuf
, sizeof(errbuf
), "PEFolder: import: %.200s",
5101 wps_global
->c_client_error
);
5104 err
= "PEFolder: import: can't read folder name";
5107 err
= "PEFolder:import: invalid collection id";
5110 err
= "PEFolder: import: can't read collection id";
5116 snprintf(err
= errbuf
, sizeof(errbuf
), "PEFolder: import: %.200s",
5117 wps_global
->c_client_error
);
5119 wps_global
->noshow_error
= 0;
5121 if(!mail_parameters(NULL
, DISABLE_DRIVER
, "unix") && !err
)
5122 err
= "PEFolder: import: can't disable driver";
5128 err
= "PEFolder: import: can't enable driver";
5131 err
= "PEFolder: import: can't read file name";
5134 err
= "PEFolder: import <file> <colid> <folder>";
5142 * 3 or more arguments, 3rd is the collection ID, rest
5146 if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
5147 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
5148 if(i
== colid
) break;
5150 else if((colstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
5151 if(!strcmp("default", colstr
))
5152 cp
= default_save_context(wps_global
->context_list
);
5160 if(!strcmp(op
, "list")){
5161 int i
, fcount
, bflags
= BFL_NONE
;
5163 if(PEFolderChange(interp
, cp
, objc
- 3, objv
+ 3) == TCL_ERROR
)
5166 if(cp
->use
& CNTXT_NEWS
)
5169 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
5171 pePrepareForAuthException();
5173 build_folder_list(NULL
, cp
, "*", NULL
, bflags
);
5175 if((aes
= peAuthException()) != NULL
){
5176 Tcl_SetResult(interp
, aes
, TCL_VOLATILE
);
5177 reset_context_folders(cp
);
5181 if((fcount
= folder_total(FOLDERS(cp
))) != 0){
5182 for(i
= 0; i
< fcount
; i
++){
5184 FOLDER_S
*f
= folder_entry(i
, FOLDERS(cp
));
5190 if(f
->hasnochildren
&& !f
->haschildren
)
5196 || (cp
->use
& CNTXT_INCMNG
))
5201 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", type
,
5202 f
->nickname
? f
->nickname
: f
->name
);
5206 reset_context_folders(cp
);
5209 else if(!strucmp(op
, "exists")){
5210 char *folder
, *errstr
= NULL
;
5214 Tcl_SetResult(interp
, "PEFolder exists: No folder specified", TCL_VOLATILE
);
5217 folder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
);
5219 Tcl_SetResult(interp
, "PEFolder exists: Can't read folder", TCL_VOLATILE
);
5223 if(PEFolderChange(interp
, cp
, objc
- 4, objv
+ 3) == TCL_ERROR
)
5226 wps_global
->c_client_error
[0] = '\0';
5227 pePrepareForAuthException();
5229 rv
= folder_name_exists(cp
, folder
, NULL
);
5232 if((errstr
= peAuthException()) == NULL
){
5233 if(wps_global
->c_client_error
[0])
5234 errstr
= wps_global
->c_client_error
;
5236 errstr
= "Indeterminate Error";
5240 Tcl_SetResult(interp
, errstr
? errstr
: int2string((int)(rv
& FEX_ISFILE
)), TCL_VOLATILE
);
5241 return(errstr
? TCL_ERROR
: TCL_OK
);
5243 else if(!strucmp(op
, "fullname")){
5244 char *folder
, *fullname
;
5247 Tcl_SetResult(interp
, "PEFolder fullname: No folder specified", TCL_VOLATILE
);
5250 folder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
);
5252 Tcl_SetResult(interp
, "PEFolder fullname: Can't read folder", TCL_VOLATILE
);
5256 if(PEFolderChange(interp
, cp
, objc
- 4, objv
+ 3) == TCL_ERROR
)
5260 Tcl_Obj
*obj
= Tcl_NewStringObj((fullname
= folder_is_nick(folder
, FOLDERS(cp
)))
5261 ? fullname
: folder
, -1);
5262 (void) Tcl_ListObjAppendElement(interp
,
5263 Tcl_GetObjResult(interp
),
5266 Tcl_SetResult(interp
,
5267 (fullname
= folder_is_nick(folder
, FOLDERS(cp
), FN_NONE
)) ? fullname
: folder
,
5273 else if(!strucmp(op
, "create")){
5276 folder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
);
5278 Tcl_SetResult(interp
, "PEFolder create: Can't read folder", TCL_VOLATILE
);
5282 if(PEFolderChange(interp
, cp
, objc
- 4, objv
+ 3) == TCL_ERROR
)
5285 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
5286 pePrepareForAuthException();
5288 if(!context_create(cp
, NULL
, folder
)){
5289 if((aes
= peAuthException()) != NULL
){
5290 Tcl_SetResult(interp
, aes
, TCL_VOLATILE
);
5293 Tcl_SetResult(interp
,
5294 (wps_global
->last_error
[0])
5295 ? wps_global
->last_error
5296 : (wps_global
->c_client_error
[0])
5297 ? wps_global
->c_client_error
5298 : "Unable to create folder",
5302 reset_context_folders(cp
);
5306 Tcl_SetResult(interp
, "OK", TCL_STATIC
);
5307 reset_context_folders(cp
);
5310 else if(!strucmp(op
, "delete")){
5311 int fi
, readonly
, close_opened
= 0;
5312 char *folder
, *fnamep
, *target
= NULL
, *aes
;
5313 MAILSTREAM
*del_stream
= NULL
, *strm
= NULL
;
5315 PINERC_S
*prc
= NULL
;
5318 folder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
);
5320 Tcl_SetResult(interp
, "PEFolder delete: Can't read folder", TCL_VOLATILE
);
5324 if(PEFolderChange(interp
, cp
, objc
- 4, objv
+ 3) == TCL_ERROR
)
5327 /* so we can check for folder's various properties */
5328 build_folder_list(NULL
, cp
, folder
, NULL
, BFL_NONE
);
5330 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
5332 pePrepareForAuthException();
5334 /* close open folder, then delete */
5336 if((fi
= folder_index(folder
, cp
, FI_FOLDER
)) < 0
5337 || (fp
= folder_entry(fi
, FOLDERS(cp
))) == NULL
){
5338 Tcl_SetResult(interp
, "Cannot find folder to delete", TCL_STATIC
);
5339 reset_context_folders(cp
);
5343 if(!((cp
->use
& CNTXT_INCMNG
) && fp
->name
5344 && check_for_move_mbox(fp
->name
, NULL
, 0, &target
))){
5348 dprint((4, "=== delete_folder(%s) ===\n", folder
? folder
: "?"));
5350 ew
= config_containing_inc_fldr(fp
);
5351 if(wps_global
->restricted
)
5356 prc
= wps_global
->prc
;
5359 prc
= wps_global
->post_prc
;
5365 readonly
= prc
? prc
->readonly
: 1;
5368 if(prc
&& prc
->quit_to_edit
&& (cp
->use
& CNTXT_INCMNG
)){
5369 Tcl_SetResult(interp
, "Must Exit Alpine to Change Configuration", TCL_STATIC
);
5370 reset_context_folders(cp
);
5374 if(cp
== wps_global
->context_list
5375 && !(cp
->dir
&& cp
->dir
->ref
)
5376 && strucmp(folder
, wps_global
->inbox_name
) == 0){
5377 Tcl_SetResult(interp
, "Cannot delete special folder", TCL_STATIC
);
5378 reset_context_folders(cp
);
5381 else if(readonly
&& (cp
->use
& CNTXT_INCMNG
)){
5382 Tcl_SetResult(interp
, "Folder not in editable config file", TCL_STATIC
);
5383 reset_context_folders(cp
);
5387 && (strm
=context_already_open_stream(cp
,fp
->name
,AOS_NONE
)))
5390 && (strm
=context_already_open_stream(NULL
,target
,AOS_NONE
)))){
5391 if(strm
== wps_global
->mail_stream
)
5394 else if(fp
->isdir
|| fp
->isdual
){ /* NO DELETE if directory isn't EMPTY */
5395 FDIR_S
*fdirp
= next_folder_dir(cp
,folder
,TRUE
,NULL
);
5400 else if(fp
->hasnochildren
)
5403 ret
= folder_total(fdirp
->folders
) > 0;
5404 free_fdir(&fdirp
, 1);
5408 Tcl_SetResult(interp
, "Cannot delete non-empty directory", TCL_STATIC
);
5409 reset_context_folders(cp
);
5414 * Folder by the same name exist, so delete both...
5416 Tcl_SetResult(interp, "Cannot delete: folder is also a directory", TCL_STATIC);
5417 reset_context_folders(cp);
5423 if(cp
->use
& CNTXT_INCMNG
){
5424 Tcl_SetResult(interp
, "Cannot delete incoming folder", TCL_STATIC
);
5425 reset_context_folders(cp
);
5429 dprint((2,"deleting \"%s\" (%s) in context \"%s\"\n",
5430 fp
->name
? fp
->name
: "?",
5431 fp
->nickname
? fp
->nickname
: "",
5432 cp
->context
? cp
->context
: "?"));
5435 * Close it, NULL the pointer, and let do_broach_folder fixup
5438 pine_mail_actually_close(strm
);
5440 do_broach_folder(wps_global
->inbox_name
,
5441 wps_global
->context_list
,
5442 NULL
, DB_INBOXWOCNTXT
);
5447 * Use fp->name since "folder" may be a nickname...
5449 if(wps_global
->mail_stream
5450 && context_same_stream(cp
, fp
->name
, wps_global
->mail_stream
))
5451 del_stream
= wps_global
->mail_stream
;
5455 if(!context_delete(cp
, del_stream
, fnamep
)){
5456 if((aes
= peAuthException()) != NULL
){
5457 Tcl_SetResult(interp
, aes
, TCL_VOLATILE
);
5460 Tcl_SetResult(interp
,
5461 (wps_global
->last_error
[0])
5462 ? wps_global
->last_error
5463 : (wps_global
->c_client_error
[0])
5464 ? wps_global
->c_client_error
5465 : "Unable to delete folder",
5469 reset_context_folders(cp
);
5474 Tcl_SetResult(interp
, "OK", TCL_STATIC
);
5475 reset_context_folders(cp
);
5479 * must be at least 5 arguments for the next set of commands
5482 Tcl_SetResult(interp
, "PEFolder: not enough arguments", TCL_VOLATILE
);
5485 else if(!strucmp(op
, "rename")){
5486 char *folder
,*newfolder
, *aes
;
5488 folder
= Tcl_GetStringFromObj(objv
[objc
- 2], NULL
);
5490 Tcl_SetResult(interp
, "PEFolder rename: Can't read folder", TCL_VOLATILE
);
5494 newfolder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
);
5496 Tcl_SetResult(interp
, "PEFolder rename: Can't read folder", TCL_VOLATILE
);
5500 if(PEFolderChange(interp
, cp
, objc
- 5, objv
+ 3) == TCL_ERROR
)
5503 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
5504 pePrepareForAuthException();
5506 if(!context_rename(cp
, NULL
, folder
, newfolder
)){
5507 if((aes
= peAuthException()) != NULL
){
5508 Tcl_SetResult(interp
, aes
, TCL_VOLATILE
);
5511 Tcl_SetResult(interp
,
5512 (wps_global
->last_error
[0])
5513 ? wps_global
->last_error
5514 : (wps_global
->c_client_error
[0])
5515 ? wps_global
->c_client_error
5516 : "Unable to rename folder",
5519 reset_context_folders(cp
);
5522 Tcl_SetResult(interp
, "OK", TCL_STATIC
);
5523 reset_context_folders(cp
);
5528 err
= "PEFolder: Unrecognized collection ID";
5532 err
= "No User Context Established";
5535 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
5541 * PEMailboxCmd - export various bits of mailbox information
5544 PEMailboxCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
5546 char *op
, errbuf
[256], *err
= "Unknown PEMailbox operation";
5548 dprint((5, "PEMailboxCmd"));
5551 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
5553 else if((op
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
5554 if(!strucmp(op
, "open")){
5559 peED
.uid
= 0; /* forget cached embedded data */
5562 * CMD: open <context-index> <folder>
5567 Tcl_SetResult(interp
, (!sp_dead_stream(wps_global
->mail_stream
)) ? "0" : "1", TCL_VOLATILE
);
5571 if(Tcl_GetIntFromObj(interp
,objv
[2],&colid
) != TCL_ERROR
){
5572 if((folder
= Tcl_GetStringFromObj(objv
[objc
- 1], NULL
)) != NULL
) {
5573 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
5575 if(PEMakeFolderString(interp
, cp
, objc
- 3, objv
+ 3,
5579 dprint((1, "* PEMailbox open dir=%s folder=%s",cp
->dir
->ref
,folder
));
5581 return(peCreateStream(interp
, cp
, folder
, FALSE
));
5584 err
= "open: Unrecognized collection ID";
5587 err
= "open: Can't read folder";
5590 err
= "open: Can't get collection ID";
5592 else if(!strcmp(op
, "indexformat")){
5596 * Returns: list of lists where:
5597 * * the first element is the name of the
5598 * field which may be "From", "Subject"
5599 * "Date" or the empty string.
5600 * * the second element which is either
5601 * the percentage width or empty string
5604 return(peIndexFormat(interp
));
5606 else if(wps_global
&& wps_global
->mail_stream
){
5607 if(!strcmp(op
, "select")){
5608 return(peSelect(interp
, objc
- 2, &((Tcl_Obj
**) objv
)[2], MN_SLCT
));
5610 else if(!strcmp(op
, "search")){
5611 return(peSelect(interp
, objc
- 2, &((Tcl_Obj
**) objv
)[2], MN_SRCH
));
5613 else if(!strucmp(op
, "apply")){
5614 return(peApply(interp
, objc
- 2, &((Tcl_Obj
**) objv
)[2]));
5616 else if(!strcmp(op
, "expunge")){
5620 * Returns: OK after having removed deleted messages
5622 char *streamstr
= NULL
;
5626 if(objc
== 3) streamstr
= Tcl_GetStringFromObj(objv
[2], NULL
);
5628 || (streamstr
&& (strcmp(streamstr
, "current") == 0))){
5629 stream
= wps_global
->mail_stream
;
5630 msgmap
= sp_msgmap(stream
);
5632 else if(streamstr
&& (strcmp(streamstr
, "inbox") == 0)){
5633 stream
= sp_inbox_stream();
5634 msgmap
= sp_msgmap(stream
);
5636 else return(TCL_ERROR
);
5637 wps_global
->last_error
[0] = '\0';
5640 msgno_exclude_deleted(stream
, msgmap
, NULL
);
5641 clear_index_cache(sp_inbox_stream(), 0);
5644 * This is kind of surprising at first. For most sort
5645 * orders, if the whole set is sorted, then any subset
5646 * is also sorted. Not so for OrderedSubject sort.
5647 * If you exclude the first message of a subject group
5648 * then you change the date that group is to be sorted on.
5650 if(mn_get_sort(msgmap
) == SortSubject2
)
5651 refresh_sort(wps_global
->mail_stream
, msgmap
, FALSE
);
5654 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
5656 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
5659 else if(!strcmp(op
, "trashdeleted")){
5663 * Returns: OK after moving deleted messages to Trash and expunging
5669 char *streamstr
= NULL
, tmp
[MAILTMPLEN
];
5670 long n
, tomove
= 0L;
5672 if(objc
== 3) streamstr
= Tcl_GetStringFromObj(objv
[2], NULL
);
5674 || (streamstr
&& (strcmp(streamstr
, "current") == 0))){
5675 stream
= wps_global
->mail_stream
;
5676 msgmap
= sp_msgmap(stream
);
5678 else if(streamstr
&& (strcmp(streamstr
, "inbox") == 0)){
5679 stream
= sp_inbox_stream();
5680 msgmap
= sp_msgmap(stream
);
5682 else return(TCL_ERROR
);
5684 wps_global
->last_error
[0] = '\0';
5685 if(IS_NEWS(stream
) && stream
->rdonly
){
5686 msgno_exclude_deleted(stream
, msgmap
, NULL
);
5687 clear_index_cache(sp_inbox_stream(), 0);
5690 * This is kind of surprising at first. For most sort
5691 * orders, if the whole set is sorted, then any subset
5692 * is also sorted. Not so for OrderedSubject sort.
5693 * If you exclude the first message of a subject group
5694 * then you change the date that group is to be sorted on.
5696 if(mn_get_sort(msgmap
) == SortSubject2
)
5697 refresh_sort(wps_global
->mail_stream
, msgmap
, FALSE
);
5700 if(!(cp
= default_save_context(wps_global
->context_list
)))
5701 cp
= wps_global
->context_list
;
5703 /* copy to trash if we're not in trash */
5704 if(wps_global
->VAR_TRASH_FOLDER
5705 && wps_global
->VAR_TRASH_FOLDER
[0]
5706 && context_allowed(context_apply(tmp
, cp
, wps_global
->VAR_TRASH_FOLDER
, sizeof(tmp
)))
5707 && !same_stream_and_mailbox(tmp
, stream
)){
5709 /* save real selected set, and */
5710 for(n
= 1L; n
<= mn_get_total(msgmap
); n
++){
5711 set_lflag(stream
, msgmap
, n
, MN_STMP
, get_lflag(stream
, msgmap
, n
, MN_SLCT
));
5712 /* select deleted */
5713 if(!get_lflag(stream
, msgmap
, n
, MN_EXLD
)
5714 && (mc
= mail_elt(stream
, mn_m2raw(msgmap
,n
))) != NULL
&& mc
->deleted
){
5716 set_lflag(stream
, msgmap
, n
, MN_SLCT
, 1);
5719 set_lflag(stream
, msgmap
, n
, MN_SLCT
, 0);
5722 if(tomove
&& pseudo_selected(stream
, msgmap
)){
5724 /* save deleted to Trash */
5725 n
= save(wps_global
, stream
,
5726 cp
, wps_global
->VAR_TRASH_FOLDER
,
5727 msgmap
, SV_FOR_FILT
| SV_FIX_DELS
);
5729 /* then remove them */
5731 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
5734 restore_selected(msgmap
);
5737 /* restore selected set */
5738 for(n
= 1L; n
<= mn_get_total(msgmap
); n
++)
5739 set_lflag(stream
, msgmap
, n
, MN_SLCT
,
5740 get_lflag(stream
, msgmap
, n
, MN_STMP
));
5744 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
5747 else if(!strcmp(op
, "nextvector")){
5748 long msgno
, count
, countdown
;
5750 char *errstr
= NULL
, *s
;
5751 Tcl_Obj
*rvObj
, *vObj
, *avObj
, **aObj
;
5756 * ARGS: msgno - message number "next" is relative to
5757 * count - how many msgno slots to return
5758 * attrib - (optional) attributes to be returned with each message in vector
5760 * Returns: vector containing next <count> messagenumbers (and optional attributes)
5762 if(objc
== 4 || objc
== 5){
5763 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) == TCL_OK
){
5764 if(Tcl_GetLongFromObj(interp
, objv
[3], &count
) == TCL_OK
){
5766 /* set index range for efficiency */
5767 if(msgno
> 0L && msgno
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
))){
5772 if(objc
== 4 || Tcl_ListObjGetElements(interp
, objv
[4], &aObjN
, &aObj
) == TCL_OK
){
5774 if((rvObj
= Tcl_NewListObj(0, NULL
)) != NULL
&& count
> 0
5775 && !(msgno
< 1L || msgno
> mn_get_total(sp_msgmap(wps_global
->mail_stream
)))){
5776 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
5778 for(countdown
= count
; countdown
> 0; countdown
--){
5779 imapuid_t uid
= mail_uid(wps_global
->mail_stream
, mn_m2raw(sp_msgmap(wps_global
->mail_stream
), msgno
));
5782 if((vObj
= Tcl_NewListObj(0, NULL
)) != NULL
){
5783 Tcl_ListObjAppendElement(interp
, vObj
, Tcl_NewLongObj(msgno
));
5784 peAppListF(interp
, vObj
, "%lu", uid
);
5787 if((avObj
= Tcl_NewListObj(0, NULL
)) != NULL
){
5788 for(i
= 0; i
< aObjN
; i
++){
5789 if((s
= Tcl_GetStringFromObj(aObj
[i
], NULL
)) != NULL
){
5790 if(!strcmp(s
, "statusbits")){
5791 char *s
= peMsgStatBitString(wps_global
, wps_global
->mail_stream
,
5792 sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
),
5793 gPeITop
, gPeICount
, &fetched
);
5794 Tcl_ListObjAppendElement(interp
, avObj
, Tcl_NewStringObj(s
, -1));
5796 else if(!strcmp(s
, "statuslist")){
5797 Tcl_Obj
*nObj
= peMsgStatNameList(interp
, wps_global
, wps_global
->mail_stream
,
5798 sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
),
5799 gPeITop
, gPeICount
, &fetched
);
5800 Tcl_ListObjAppendElement(interp
, avObj
, nObj
);
5802 else if(!strcmp(s
, "status")){
5807 raw
= peSequenceNumber(uid
);
5809 if(!((mc
= mail_elt(wps_global
->mail_stream
, raw
)) && mc
->valid
)){
5810 mail_fetch_flags(wps_global
->mail_stream
,
5811 ulong2string(uid
), FT_UID
);
5812 mc
= mail_elt(wps_global
->mail_stream
, raw
);
5815 stat
[0] = mc
->deleted
? '1' : '0';
5816 stat
[1] = mc
->recent
? '1' : '0';
5817 stat
[2] = mc
->seen
? '1' : '0';
5819 Tcl_ListObjAppendElement(interp
, avObj
, Tcl_NewStringObj(stat
,3));
5821 else if(!strcmp(s
, "indexparts")){
5824 if((iObj
= Tcl_NewListObj(0, NULL
)) != NULL
5825 && peAppendIndexParts(interp
, uid
, iObj
, &fetched
) == TCL_OK
5826 && Tcl_ListObjAppendElement(interp
, avObj
, iObj
) == TCL_OK
){
5831 else if(!strucmp(s
, "indexcolor")){
5832 if(peAppendIndexColor(interp
, uid
, avObj
, &fetched
) != TCL_OK
)
5837 errstr
= "nextvector: can't read attributes";
5842 Tcl_ListObjAppendElement(interp
, vObj
, avObj
);
5845 errstr
= "nextvector: can't allocate attribute return vector";
5851 errstr
= "nextvector: can't allocate new vector";
5855 Tcl_ListObjAppendElement(interp
, rvObj
, vObj
);
5857 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
++)
5860 if(msgno
> mn_get_total(sp_msgmap(wps_global
->mail_stream
)))
5866 /* append result vector */
5867 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), rvObj
);
5868 /* Everything is coerced to UTF-8 */
5869 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
5870 Tcl_NewStringObj("UTF-8", -1));
5875 errstr
= "nextvector: can't read attribute list";
5878 errstr
= "nextvector: can't read count";
5881 errstr
= "nextvector: can't read message number";
5884 errstr
= "nextvector: Incorrect number of arguments";
5887 Tcl_SetResult(interp
, errstr
, TCL_STATIC
);
5892 if(!strcmp(op
, "messagecount")){
5896 * Returns: count of messages in open mailbox
5898 Tcl_SetResult(interp
,
5899 long2string(mn_get_total(sp_msgmap(wps_global
->mail_stream
))),
5903 else if(!strcmp(op
, "firstinteresting")){
5905 * CMD: firstinteresting
5907 * Returns: message number associated with
5908 * "incoming-startup-rule" which had better
5909 * be the "current" message since it was set
5910 * in do_broach_folder and shouldn't have been
5911 * changed otherwise (expunged screw us?)
5913 Tcl_SetResult(interp
,
5914 long2string(mn_get_cur(sp_msgmap(wps_global
->mail_stream
))),
5918 else if(!strcmp(op
, "selected")){
5922 * Returns: count of selected messages in open mailbox
5925 Tcl_SetResult(interp
,
5926 long2string(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SLCT
)),
5930 else if(!strcmp(op
, "searched")){
5934 * Returns: count of searched messages in open mailbox
5937 Tcl_SetResult(interp
,
5938 long2string(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SRCH
)),
5942 else if(!strcmp(op
, "mailboxname")){
5946 * Returns: string representing the name of the
5949 Tcl_SetResult(interp
, wps_global
->cur_folder
, TCL_VOLATILE
);
5952 else if(!strcmp(op
, "close")){
5956 * Returns: with global mail_stream closed
5958 peDestroyStream(wps_global
);
5961 else if(!strcmp(op
, "newmailreset")){
5963 zero_new_mail_count();
5964 sp_set_mail_box_changed(wps_global
->mail_stream
, 0);
5965 sp_set_expunge_count(wps_global
->mail_stream
, 0L);
5969 else if(!strcmp(op
, "newmailstatmsg")){
5971 char subject
[500], subjtxt
[500], from
[500], intro
[500], *s
= "";
5974 * CMD: newmailstatmsg
5978 * Returns: text for new mail message
5982 if(sp_mail_box_changed(wps_global
->mail_stream
)
5983 && (count
= sp_mail_since_cmd(wps_global
->mail_stream
))){
5985 for(newest
= wps_global
->mail_stream
->nmsgs
; newest
> 1L; newest
--)
5986 if(!get_lflag(wps_global
->mail_stream
, NULL
, newest
, MN_EXLD
))
5990 format_new_mail_msg(NULL
, count
,
5991 pine_mail_fetchstructure(wps_global
->mail_stream
,
5993 intro
, from
, subject
, subjtxt
, sizeof(subject
));
5995 snprintf(s
= wtmp_20k_buf
, SIZEOF_20KBUF
, "%s %s %s", intro
, from
, subjtxt
);
5999 Tcl_SetResult(interp
, s
, TCL_VOLATILE
);
6002 else if(!strcmp(op
, "savedefault")){
6003 return(peSaveDefault(interp
, 0L, 0, NULL
));
6005 else if(!strcmp(op
, "gotodefault")){
6006 return(peGotoDefault(interp
, 0L, NULL
));
6008 else if(!strcmp(op
, "zoom")){
6009 Tcl_SetResult(interp
,
6010 long2string((any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
) > 0L)
6011 ? any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SLCT
) : 0L),
6015 else if(!strcmp(op
, "focus")){
6016 Tcl_SetResult(interp
,
6017 long2string((any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
) > 0L)
6018 ? any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SRCH
) : 0L),
6022 else if(!strcmp(op
, "first")){
6023 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
)){
6026 for(n
= 1L; n
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); n
++)
6027 if(!get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_HIDE
)){
6028 Tcl_SetResult(interp
, long2string(n
), TCL_VOLATILE
);
6032 unzoom_index(wps_global
, wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
));
6036 Tcl_SetResult(interp
, int2string(1), TCL_VOLATILE
);
6039 else if(!strucmp(op
, "current")){
6041 unsigned long u
= 0;
6048 * Returns: list of current msg {<sequence> <uid>}
6051 if(mn_total_cur(sp_msgmap(wps_global
->mail_stream
)) <= 0
6052 || ((n
= mn_get_cur(sp_msgmap(wps_global
->mail_stream
))) > 0
6053 && (u
= mail_uid(wps_global
->mail_stream
, mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
))) > 0)){
6054 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(long2string(n
), -1));
6055 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(ulong2string(u
), -1));
6059 err
= "Cannot get current";
6061 else if(!strcmp(op
, "last")){
6062 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
)){
6065 for(n
= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); n
> 0L; n
--)
6066 if(!get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_HIDE
)){
6067 Tcl_SetResult(interp
, long2string(n
), TCL_VOLATILE
);
6072 Tcl_SetResult(interp
, long2string(mn_get_total(sp_msgmap(wps_global
->mail_stream
))), TCL_VOLATILE
);
6076 Tcl_SetResult(interp
, "Can't set last message number", TCL_STATIC
);
6079 else if(!strucmp(op
, "sortstyles")){
6084 * Returns: list of supported sort styles
6087 for(i
= 0; wps_global
->sort_types
[i
] != EndofList
; i
++)
6088 if(Tcl_ListObjAppendElement(interp
,
6089 Tcl_GetObjResult(interp
),
6090 Tcl_NewStringObj(sort_name(wps_global
->sort_types
[i
]), -1)) != TCL_OK
)
6095 else if(!strucmp(op
, "sort")){
6096 return(peAppendCurrentSort(interp
));
6098 else if(!strucmp(op
, "state")){
6099 if(!wps_global
->mail_stream
|| sp_dead_stream(wps_global
->mail_stream
))
6100 Tcl_SetResult(interp
, "closed", TCL_STATIC
);
6101 else if(wps_global
->mail_stream
->rdonly
&& !IS_NEWS(wps_global
->mail_stream
))
6102 Tcl_SetResult(interp
, "readonly", TCL_STATIC
);
6104 Tcl_SetResult(interp
, "ok", TCL_STATIC
);
6108 else if(!strucmp(op
, "excludedeleted")){
6109 msgno_exclude_deleted(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), NULL
);
6114 if(!strcmp(op
, "uid")){
6118 * Return uid of given message number
6120 * CMD: uid <msgnumber>
6123 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) != TCL_OK
)
6124 return(TCL_ERROR
); /* conversion problem? */
6126 if((raw
= mn_m2raw(sp_msgmap(wps_global
->mail_stream
), msgno
)) > 0L){
6127 raw
= mail_uid(wps_global
->mail_stream
, raw
);
6128 Tcl_SetResult(interp
, long2string(raw
), TCL_VOLATILE
);
6132 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Invalid UID for message %ld", msgno
);
6133 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
6136 else if(!strcmp(op
, "newmail")){
6137 int reload
, force
= UFU_NONE
, rv
;
6138 time_t now
= time(0);
6143 * ARGS: reload -- "1" if we're reloading
6144 * (vs. just checking newmail as a side effect
6145 * of building a new page)
6150 if(Tcl_GetIntFromObj(interp
, objv
[2], &reload
) == TCL_ERROR
)
6153 /* minimum 10 second between IMAP pings */
6154 if(!time_of_last_input() || now
- time_of_last_input() > 10){
6159 /* check for new mail */
6160 new_mail(force
, reload
? GoodTime
: VeryBadTime
, NM_NONE
);
6162 rv
= peNewMailResult(interp
);
6164 if(!reload
) /* announced */
6165 zero_new_mail_count();
6169 else if(!strcmp(op
, "flagcount")){
6182 * Returns: count - number of message thusly flagged
6185 if(Tcl_ListObjGetElements(interp
, objv
[2], &objlc
, &objlv
) == TCL_OK
){
6187 if((flag
= Tcl_GetStringFromObj(*objlv
++, NULL
)) != NULL
){
6188 if(!strucmp(flag
, "deleted")){
6191 if(!strucmp(flag
, "undeleted")){
6194 else if(!strucmp(flag
, "seen")){
6197 else if(!strucmp(flag
, "unseen")){
6200 else if(!strucmp(flag
, "flagged")){
6203 else if(!strucmp(flag
, "unflagged")){
6206 else if(!strucmp(flag
, "answered")){
6209 else if(!strucmp(flag
, "unanswered")){
6212 else if(!strucmp(flag
, "recent")){
6215 else if(!strucmp(flag
, "unrecent")){
6216 flags
|= F_UNRECENT
;
6221 count
= count_flagged(wps_global
->mail_stream
, flags
);
6224 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
6227 else if(!strcmp(op
, "zoom")){
6229 long n
, zoomed
= 0L;
6234 * Set/clear HID bits of non SLCT messages as requested.
6235 * PEMailbox [first | last | next] are sensitive to these flags.
6237 * ARGS: newstate - 1 or 0
6239 * Returns: count of zoomed messages
6242 if(Tcl_GetIntFromObj(interp
, objv
[2], &newstate
) != TCL_ERROR
){
6244 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
)))){
6245 zoom_index(wps_global
, wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MN_SLCT
);
6250 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
))
6251 unzoom_index(wps_global
, wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
));
6255 Tcl_SetResult(interp
, long2string(zoomed
), TCL_VOLATILE
);
6258 else if(!strcmp(op
, "focus")){
6260 long n
, zoomed
= 0L;
6265 * Set/clear HID bits of non MN_SRCH messages as requested.
6266 * PEMailbox [first | last | next] are sensitive to MN_HIDE flag
6268 * ARGS: newstate - 1 or 0
6270 * Returns: count of zoomed messages
6273 if(Tcl_GetIntFromObj(interp
, objv
[2], &newstate
) != TCL_ERROR
){
6275 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
))))
6276 zoom_index(wps_global
, wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MN_SRCH
);
6281 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
))
6282 unzoom_index(wps_global
, wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
));
6286 Tcl_SetResult(interp
, long2string(zoomed
), TCL_VOLATILE
);
6289 else if(!strcmp(op
, "next")){
6295 * ARGS: msgno - message number "next" is relative to
6297 * Returns: previous state
6300 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) != TCL_ERROR
){
6301 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
6302 mn_inc_cur(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MH_NONE
);
6303 Tcl_SetResult(interp
, long2string(mn_get_cur(sp_msgmap(wps_global
->mail_stream
))), TCL_VOLATILE
);
6307 Tcl_SetResult(interp
, "next can't read message number", TCL_STATIC
);
6312 if(!strucmp(op
, "sort")){
6313 int i
, reversed
= 0;
6317 * CMD: sort sortstyle reversed
6319 * Returns: OK with the side-effect of message
6320 * numbers now reflecting the requested
6324 if((sort
= Tcl_GetStringFromObj(objv
[2], NULL
))
6325 && Tcl_GetIntFromObj(interp
, objv
[3], &reversed
) != TCL_ERROR
){
6326 /* convert sort string into */
6327 for(i
= 0; wps_global
->sort_types
[i
] != EndofList
; i
++)
6328 if(strucmp(sort_name(wps_global
->sort_types
[i
]), sort
) == 0){
6329 if(sp_unsorted_newmail(wps_global
->mail_stream
)
6330 || !(wps_global
->sort_types
[i
] == mn_get_sort(sp_msgmap(wps_global
->mail_stream
))
6331 && mn_get_revsort(sp_msgmap(wps_global
->mail_stream
)) == reversed
))
6332 sort_folder(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
),
6333 wps_global
->sort_types
[i
],
6340 return(peAppendCurrentSort(interp
));
6342 else if(!strucmp(op
, "selected")){
6343 return(peSelected(interp
, objc
- 2, &((Tcl_Obj
**) objv
)[2], MN_SLCT
));
6345 else if(!strucmp(op
, "searched")){
6346 return(peSelected(interp
, objc
- 2, &((Tcl_Obj
**) objv
)[2], MN_SRCH
));
6348 else if(!strcmp(op
, "next")){
6354 * ARGS: msgno - message number "next" is relative to
6355 * count - how many to increment it
6357 * Returns: previous state
6360 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) != TCL_ERROR
6361 && Tcl_GetLongFromObj(interp
, objv
[3], &count
) != TCL_ERROR
){
6362 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
6365 mn_inc_cur(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MH_NONE
);
6369 mn_dec_cur(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MH_NONE
);
6373 Tcl_SetResult(interp
, long2string(mn_get_cur(sp_msgmap(wps_global
->mail_stream
))), TCL_VOLATILE
);
6377 Tcl_SetResult(interp
, "next can't read message number", TCL_STATIC
);
6380 else if(!strcmp(op
, "x-nextvector")){
6386 * ARGS: msgno - message number "next" is relative to
6387 * count - how many msgno slots to return
6389 * Returns: vector containing next <count> messagenumbers
6392 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) != TCL_ERROR
6393 && Tcl_GetLongFromObj(interp
, objv
[3], &count
) != TCL_ERROR
){
6394 if(count
> 0 && !(msgno
< 1L || msgno
> mn_get_total(sp_msgmap(wps_global
->mail_stream
)))){
6395 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
6398 long n
= mn_get_cur(sp_msgmap(wps_global
->mail_stream
));
6400 if(peAppListF(interp
, Tcl_GetObjResult(interp
),
6401 "%l%l", n
, mail_uid(wps_global
->mail_stream
,
6402 mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
))) != TCL_OK
)
6405 mn_inc_cur(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MH_NONE
);
6407 if(n
== mn_get_cur(sp_msgmap(wps_global
->mail_stream
)))
6415 Tcl_SetResult(interp
, "next can't read message number", TCL_STATIC
);
6418 else if(!strcmp(op
, "messagecount")){
6420 long msgno
, n
, count
= 0L;
6425 * ARGS: [before | after] relative to
6428 * Returns: count of messages before or after given message number
6431 if((relative
= Tcl_GetStringFromObj(objv
[2], NULL
))
6432 && Tcl_GetLongFromObj(interp
, objv
[3], &msgno
) != TCL_ERROR
){
6433 if(msgno
< 1L || msgno
> mn_get_total(sp_msgmap(wps_global
->mail_stream
))){
6434 Tcl_SetResult(interp
, "relative msgno out of range", TCL_STATIC
);
6438 if(!strucmp(relative
, "before")){
6439 for(n
= msgno
- 1; n
> 0L; n
--)
6440 if(!get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_HIDE
))
6443 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
6446 else if(!strucmp(relative
, "after")){
6447 for(n
= msgno
+ 1; n
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); n
++)
6448 if(!get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_HIDE
))
6451 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
6456 Tcl_SetResult(interp
, "can't read range for count", TCL_STATIC
);
6459 else if(!strcmp(op
, "selectvector")){
6465 * ARGS: msgno - message number "next" is relative to
6466 * count - how many msgno slots to return
6468 * Returns: vector containing next <count> messagenumbers
6471 if(Tcl_GetLongFromObj(interp
, objv
[2], &msgno
) != TCL_ERROR
6472 && Tcl_GetLongFromObj(interp
, objv
[3], &count
) != TCL_ERROR
){
6474 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
6476 msgno
= mn_get_cur(sp_msgmap(wps_global
->mail_stream
));
6478 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), msgno
, MN_SLCT
))
6479 if(Tcl_ListObjAppendElement(interp
,
6480 Tcl_GetObjResult(interp
),
6481 Tcl_NewLongObj((long) mail_uid(wps_global
->mail_stream
, msgno
))) != TCL_OK
)
6484 mn_inc_cur(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), MH_NONE
);
6486 if(msgno
== mn_get_cur(sp_msgmap(wps_global
->mail_stream
)))
6494 Tcl_SetResult(interp
, "selectvector: no message number", TCL_STATIC
);
6497 else if(!strucmp(op
, "current")){
6499 long x
, n
= 0, u
= 0;
6504 * ARGS: (number|uid) <msgno>
6506 * Returns: list of current msg {<sequence> <uid>}
6508 if((which
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
6509 if(Tcl_GetLongFromObj(interp
, objv
[3], &x
) == TCL_OK
){
6510 if(!strucmp(which
,"uid")){
6512 n
= peMessageNumber(u
);
6514 else if(!strucmp(which
,"number")){
6516 u
= mail_uid(wps_global
->mail_stream
, mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
));
6520 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), n
);
6521 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(long2string(n
), -1));
6522 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(long2string(u
), -1));
6526 err
= "PEMailbox current: invalid number/uid";
6529 err
= "PEMailbox current: cannot get number";
6532 err
= "PEMailbox current: cannot get which";
6536 err
= "PEMailbox: Too many arguments";
6538 else if(!strucmp(op
, "name") || !strcmp(op
, "close")){
6539 Tcl_SetResult(interp
, "", TCL_STATIC
);
6543 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: %s: No open mailbox",
6544 Tcl_GetStringFromObj(objv
[0], NULL
), op
);
6547 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
6553 peAppendCurrentSort(Tcl_Interp
*interp
)
6555 return((Tcl_ListObjAppendElement(interp
,
6556 Tcl_GetObjResult(interp
),
6557 Tcl_NewStringObj(sort_name(mn_get_sort(sp_msgmap(wps_global
->mail_stream
))), -1)) == TCL_OK
6558 && Tcl_ListObjAppendElement(interp
,
6559 Tcl_GetObjResult(interp
),
6560 Tcl_NewStringObj(mn_get_revsort(sp_msgmap(wps_global
->mail_stream
)) ? "1" : "0", 1)) == TCL_OK
)
6561 ? TCL_OK
: TCL_ERROR
);
6566 peAppendDefaultSort(Tcl_Interp
*interp
)
6568 return((Tcl_ListObjAppendElement(interp
,
6569 Tcl_GetObjResult(interp
),
6570 Tcl_NewStringObj(sort_name(wps_global
->def_sort
), -1)) == TCL_OK
6571 && Tcl_ListObjAppendElement(interp
,
6572 Tcl_GetObjResult(interp
),
6573 Tcl_NewStringObj(wps_global
->def_sort_rev
? "1" : "0", 1)) == TCL_OK
)
6574 ? TCL_OK
: TCL_ERROR
);
6579 peSelect(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
6582 long n
, i
, diff
, msgno
;
6585 extern MAILSTREAM
*mm_search_stream
;
6586 extern long mm_search_count
;
6588 hidden
= any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
) > 0L;
6589 mm_search_stream
= wps_global
->mail_stream
;
6590 mm_search_count
= 0L;
6592 for(n
= 1L; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6593 if((mc
= mail_elt(wps_global
->mail_stream
, n
)) != NULL
){
6601 * ARGS: subcmd subcmdargs
6603 * Returns: flip "matchflag" private bit on all or none
6604 * of the messages in the mailbox
6606 if((subcmd
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
){
6607 if(!strucmp(subcmd
, "all")){
6611 if(matchflag
& MN_SLCT
){
6613 return(peSelectError(interp
, subcmd
));
6615 agg_select_all(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), NULL
, 1);
6617 else if(matchflag
& MN_SRCH
){
6618 for(n
= 1L; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6619 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, matchflag
, 1);
6622 Tcl_SetResult(interp
, "All", TCL_VOLATILE
);
6624 else if(!strucmp(subcmd
, "none")){
6630 if(matchflag
& MN_SLCT
){
6632 return(peSelectError(interp
, subcmd
));
6634 agg_select_all(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), &n
, 0);
6636 else if(matchflag
& MN_SRCH
){
6637 for(n
= 1L; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6638 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, matchflag
, 0);
6641 Tcl_SetResult(interp
, long2string(n
), TCL_VOLATILE
);
6643 else if(!strucmp(subcmd
, "searched")){
6647 for(n
= 1L, i
= 0; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6648 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_SRCH
)){
6650 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_SLCT
, 1);
6653 Tcl_SetResult(interp
, long2string(i
), TCL_VOLATILE
);
6655 else if(!strucmp(subcmd
, "unsearched")){
6659 for(n
= 1L, i
= 0; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6660 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_SRCH
)){
6662 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), n
, MN_SLCT
, 0);
6665 Tcl_SetResult(interp
, long2string(i
), TCL_VOLATILE
);
6668 if(!strucmp(subcmd
, "narrow"))
6670 else if(!strucmp(subcmd
, "broad"))
6673 return(peSelectError(interp
, "invalid scope request"));
6675 if(!(subcmd
= Tcl_GetStringFromObj(objv
[1], NULL
)))
6676 return(peSelectError(interp
, "missing subcommand"));
6678 if(!strucmp(subcmd
, "num")){
6679 if((i
= peSelectNumber(interp
, objc
- 2, &objv
[2], matchflag
)) != TCL_OK
)
6682 else if(!strucmp(subcmd
, "date")){
6683 if((i
= peSelectDate(interp
, objc
- 2, &objv
[2], matchflag
)) != TCL_OK
)
6686 else if(!strucmp(subcmd
, "text")){
6687 if((i
= peSelectText(interp
, objc
- 2, &objv
[2], matchflag
)) != TCL_OK
)
6690 else if(!strucmp(subcmd
, "status")){
6691 if((i
= peSelectStatus(interp
, objc
- 2, &objv
[2], matchflag
)) != TCL_OK
)
6694 else if(!strucmp(subcmd
, "compound")){
6696 int nSearchList
, nSearch
;
6697 Tcl_Obj
**oSearchList
, **oSearch
;
6699 /* BUG: should set up one SEARCHPGM to fit criteria and issue single search */
6701 if(Tcl_ListObjGetElements(interp
, objv
[2], &nSearchList
, &oSearchList
) == TCL_OK
){
6702 for(i
= 0; i
< nSearchList
; i
++){
6703 if(Tcl_ListObjGetElements(interp
, oSearchList
[i
], &nSearch
, &oSearch
) == TCL_OK
){
6704 if((s
= Tcl_GetStringFromObj(oSearch
[0], NULL
)) != NULL
){
6705 if(!strucmp(s
,"date")){
6706 if((n
= peSelectDate(interp
, nSearch
- 1, &oSearch
[1], matchflag
)) != TCL_OK
)
6709 else if(!strucmp(s
,"text")){
6710 if((n
= peSelectText(interp
, nSearch
- 1, &oSearch
[1], matchflag
)) != TCL_OK
)
6713 else if(!strucmp(s
,"status")){
6714 if((n
= peSelectStatus(interp
, nSearch
- 1, &oSearch
[1], matchflag
)) != TCL_OK
)
6718 return(peSelectError(interp
, "unknown compound search"));
6720 /* logical AND the results */
6721 mm_search_count
= 0L;
6722 for(n
= 1L; n
<= wps_global
->mail_stream
->nmsgs
; n
++)
6723 if((mc
= mail_elt(wps_global
->mail_stream
, n
)) != NULL
){
6724 if(mc
->searched
&& mc
->spare7
)
6727 mc
->searched
= mc
->spare7
= 0;
6731 return(peSelectError(interp
, "malformed compound search"));
6734 return(peSelectError(interp
, "malformed compound search"));
6738 return(peSelectError(interp
, "malformed compound search"));
6741 return(peSelectError(interp
, "cmd cmdargs"));
6744 * at this point all interesting messages should
6745 * have searched bit lit
6748 if(narrow
) /* make sure something was selected */
6749 for(i
= 1L; i
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); i
++)
6750 if(mail_elt(wps_global
->mail_stream
,
6751 mn_m2raw(sp_msgmap(wps_global
->mail_stream
), i
))->searched
){
6752 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
))
6759 if(mm_search_count
){
6761 * loop thru all the messages, adjusting local flag bits
6762 * based on their "searched" bit...
6764 for(i
= 1L, msgno
= 0L; i
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); i
++)
6766 /* turning OFF selectedness if the "searched" bit isn't lit. */
6767 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
)){
6768 if(!mail_elt(wps_global
->mail_stream
,
6769 mn_m2raw(sp_msgmap(wps_global
->mail_stream
), i
))->searched
){
6771 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
, 0);
6773 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, MN_HIDE
, 1);
6775 else if(msgno
< mn_get_cur(sp_msgmap(wps_global
->mail_stream
)))
6779 else if(mail_elt(wps_global
->mail_stream
,mn_m2raw(sp_msgmap(wps_global
->mail_stream
),i
))->searched
){
6780 /* turn ON selectedness if "searched" bit is lit. */
6781 if(!get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
)){
6783 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
, 1);
6785 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, MN_HIDE
, 0);
6789 /* if we're zoomed and the current message was unselected */
6791 && get_lflag(wps_global
->mail_stream
,sp_msgmap(wps_global
->mail_stream
),mn_get_cur(sp_msgmap(wps_global
->mail_stream
)),MN_HIDE
))
6792 mn_reset_cur(sp_msgmap(wps_global
->mail_stream
), msgno
);
6795 Tcl_SetResult(interp
, long2string(diff
), TCL_VOLATILE
);
6801 Tcl_SetResult(interp
, "Can't read select option", TCL_STATIC
);
6806 peSelectNumber(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
6809 * Args: [broad | narrow] firstnumber lastnumber
6812 long first
= 0L, last
= 0L, n
;
6815 if(Tcl_GetLongFromObj(interp
, objv
[0], &first
) == TCL_OK
6816 && Tcl_GetLongFromObj(interp
, objv
[1], &last
) == TCL_OK
){
6817 if(last
&& last
< first
){
6823 if(first
>= 1L && first
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
))){
6825 if(last
>= 1L && last
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
))){
6826 for(n
= first
; n
<= last
; n
++)
6827 mm_searched(wps_global
->mail_stream
,
6828 mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
));
6831 return(peSelectError(interp
, "last out of range"));
6834 mm_searched(wps_global
->mail_stream
,
6835 mn_m2raw(sp_msgmap(wps_global
->mail_stream
), first
));
6839 return(peSelectError(interp
, "first out of range"));
6842 return(peSelectError(interp
, "can't read first/last"));
6845 return(peSelectError(interp
, "num first last"));
6851 peSelectDate(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
6854 * Args: [broad | narrow]
6855 * tense - "on", "since", "before"
6856 * year - 4 digit year
6857 * month - abbreviated month "jan", "feb"...
6861 char *tense
, *year
, *month
, *day
, buf
[256];
6864 if((tense
= peSelValTense(objv
[0])) != NULL
){
6865 if((year
= peSelValYear(objv
[1])) != NULL
){
6866 if((month
= peSelValMonth(objv
[2])) != NULL
){
6867 if((day
= peSelValDay(objv
[3])) != NULL
){
6868 snprintf(buf
, sizeof(buf
), "%s %s-%s-%s", tense
, day
, month
, year
);
6869 pine_mail_search_full(wps_global
->mail_stream
, NULL
,
6871 SE_NOPREFETCH
| SE_FREE
);
6874 return(peSelectError(interp
, "<with valid day>"));
6877 return(peSelectError(interp
, "<with valid month>"));
6880 return(peSelectError(interp
, "<with valid year>"));
6883 return(peSelectError(interp
, "<with valid tense>"));
6886 return(peSelectError(interp
, "date tense year monthabbrev daynum"));
6892 peSelectText(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
6895 * Args: [broad | narrow]
6897 * field - to from cc recip partic subj any
6898 * text - free text search string
6904 if((not = peSelValCase(objv
[0])) >= 0){
6905 if((field
= peSelValField(objv
[1])) != '\0'){
6906 if((text
= Tcl_GetStringFromObj(objv
[2], NULL
))
6907 && strlen(text
) < 1024){
6908 /* BUG: fix charset not to be NULL below */
6909 if(agg_text_select(wps_global
->mail_stream
,
6910 sp_msgmap(wps_global
->mail_stream
),
6911 field
, NULL
, not, 0, text
, NULL
, NULL
))
6912 /* BUG: plug in "charset" above? */
6913 return(peSelectError(interp
, "programmer botch"));
6916 return(peSelectError(interp
, "<with search string < 1024>"));
6919 return(peSelectError(interp
, "<with valid field>"));
6922 return(peSelectError(interp
, "<with valid case>"));
6925 return(peSelectError(interp
, "text case field text"));
6931 peSelectStatus(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
6934 * Args: [broad | narrow]
6936 * status - imp new ans del
6942 if((not = peSelValCase(objv
[0])) >= 0){
6943 if((flag
= peSelValFlag(objv
[1])) != '\0'){
6944 if(agg_flag_select(wps_global
->mail_stream
, not, flag
, NULL
))
6945 return(peSelectError(interp
, "programmer botch"));
6948 return(peSelectError(interp
, "<with valid flag>"));
6951 return(peSelectError(interp
, "<with valid case>"));
6954 return(peSelectError(interp
, "status focus case flag"));
6960 peSelValTense(Tcl_Obj
*objp
)
6964 if((tense
= Tcl_GetStringFromObj(objp
, NULL
)) != NULL
){
6965 static char *tenses
[] = {"on", "since", "before", NULL
};
6967 for(pp
= tenses
; *pp
; pp
++)
6968 if(!strucmp(*pp
, tense
))
6977 peSelValYear(Tcl_Obj
*objp
)
6981 return((year
= Tcl_GetStringFromObj(objp
, NULL
))
6982 && strlen(year
) == 4
6983 && isdigit((unsigned char) year
[0])
6984 && isdigit((unsigned char) year
[0])
6985 && isdigit((unsigned char) year
[0])
6992 peSelValMonth(Tcl_Obj
*objp
)
6995 static char *mons
[] = {"jan","feb","mar","apr",
6996 "may","jun","jul","aug",
6997 "sep","oct","nov","dec", NULL
};
6999 if((month
= Tcl_GetStringFromObj(objp
, NULL
)) && strlen(month
) == 3)
7000 for(pp
= mons
; *pp
; pp
++)
7001 if(!strucmp(month
, *pp
))
7009 peSelValDay(Tcl_Obj
*objp
)
7013 return(((day
= Tcl_GetStringFromObj(objp
, NULL
))
7014 && (day
[0] == '0' || day
[0] == '1'
7015 || day
[0] == '2' || day
[0] == '3')
7016 && isdigit((unsigned char) day
[1])
7024 peSelValCase(Tcl_Obj
*objp
)
7028 if((not = Tcl_GetStringFromObj(objp
, NULL
)) != NULL
){
7029 if(!strucmp(not, "ton"))
7031 else if(!strucmp(not, "not"))
7040 peSelValField(Tcl_Obj
*objp
)
7047 } fields
[] = {{"from", 'f'},
7057 if((field
= Tcl_GetStringFromObj(objp
, NULL
)) != NULL
)
7058 for(i
= 0; fields
[i
].field
; i
++)
7059 if(!strucmp(fields
[i
].field
, field
))
7060 return(fields
[i
].type
);
7067 peSelValFlag(Tcl_Obj
*objp
)
7074 } flags
[] = {{"imp", '*'},
7080 if((flag
= Tcl_GetStringFromObj(objp
, NULL
)) != NULL
)
7081 for(i
= 0; flags
[i
].flag
; i
++)
7082 if(!strucmp(flags
[i
].flag
, flag
))
7083 return(flags
[i
].type
);
7089 peSelected(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
, int matchflag
)
7096 * CMD: searched [before | after] #
7098 * Returns: 1 if criteria is true, 0 otherwise
7101 if((range
= Tcl_GetStringFromObj(objv
[0], NULL
))
7102 && Tcl_GetLongFromObj(interp
, objv
[1], &n
) != TCL_ERROR
){
7103 if(!strucmp(range
, "before")){
7104 for(i
= 1L; i
< n
&& i
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); i
++)
7105 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
)){
7110 Tcl_SetResult(interp
, int2string(rv
), TCL_STATIC
);
7113 else if(!strucmp(range
, "after")){
7114 for(i
= n
+ 1L; i
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); i
++)
7115 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), i
, matchflag
)){
7120 Tcl_SetResult(interp
, int2string(rv
), TCL_STATIC
);
7125 Tcl_SetResult(interp
, "searched test failed", TCL_STATIC
);
7131 peSelectError(Tcl_Interp
*interp
, char *usage
)
7135 snprintf(buf
, sizeof(buf
), "should be select %.128s", usage
);
7136 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
7142 peApply(Tcl_Interp
*interp
, int objc
, Tcl_Obj
**objv
)
7147 if(!(n
= any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_SLCT
))){
7148 Tcl_SetResult(interp
, "No messages selected", TCL_STATIC
);
7151 else if((subcmd
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
){
7153 if(!strucmp(subcmd
, "delete")){
7154 /* BUG: is CmdWhere arg always right? */
7155 (void) cmd_delete(wps_global
, sp_msgmap(wps_global
->mail_stream
), MCMD_AGG
| MCMD_SILENT
, NULL
);
7156 Tcl_SetResult(interp
, long2string(n
), TCL_STATIC
);
7159 else if(!strucmp(subcmd
, "undelete")){
7160 (void) cmd_undelete(wps_global
, sp_msgmap(wps_global
->mail_stream
), MCMD_AGG
| MCMD_SILENT
);
7161 Tcl_SetResult(interp
, long2string(n
), TCL_STATIC
);
7166 if(!strucmp(subcmd
, "count")){
7171 long n
, rawno
, count
= 0;
7173 if((flagname
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
7174 for(n
= 1L; n
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); n
++){
7175 rawno
= mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
);
7176 if(get_lflag(wps_global
->mail_stream
, NULL
, rawno
, MN_SLCT
)
7177 && peIsFlagged(wps_global
->mail_stream
,
7178 mail_uid(wps_global
->mail_stream
, rawno
),
7185 Tcl_SetResult(interp
, long2string(count
), TCL_VOLATILE
);
7190 if(!strucmp(subcmd
, "flag")){
7192 * Args: case - on not
7193 * flag - imp new ans del
7199 if((not = peSelValCase(objv
[1])) >= 0){
7200 if((flag
= peSelValFlag(objv
[2])) != '\0'){
7201 result
= peApplyFlag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), flag
, not, &flagged
);
7203 Tcl_SetResult(interp
, int2string(flagged
), TCL_VOLATILE
);
7207 return(peApplyError(interp
, result
));
7210 return(peApplyError(interp
, "invalid flag"));
7213 return(peApplyError(interp
, "invalid case"));
7215 else if(!strucmp(subcmd
, "save")){
7218 * folder - imp new ans del
7221 int colid
, flgs
= 0, i
;
7225 if(Tcl_GetIntFromObj(interp
, objv
[1], &colid
) != TCL_ERROR
){
7227 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
7229 if((folder
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7230 if(pseudo_selected(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
))){
7232 if(!READONLY_FOLDER(wps_global
->mail_stream
)
7233 && F_OFF(F_SAVE_WONT_DELETE
, wps_global
))
7236 if(colid
== 0 && !strucmp(folder
, "inbox"))
7237 flgs
|= SV_INBOXWOCNTXT
;
7239 i
= save(wps_global
, wps_global
->mail_stream
,
7240 cp
, folder
, sp_msgmap(wps_global
->mail_stream
), flgs
);
7242 err
= (i
== mn_total_cur(sp_msgmap(wps_global
->mail_stream
))) ? NULL
: "problem saving";
7244 restore_selected(sp_msgmap(wps_global
->mail_stream
));
7246 return(peApplyError(interp
, err
));
7248 Tcl_SetResult(interp
, long2string(i
), TCL_VOLATILE
);
7252 return(peApplyError(interp
, "can't select"));
7255 return(peApplyError(interp
, "no folder name"));
7258 return(peApplyError(interp
, "bad colid"));
7261 return(peApplyError(interp
, "invalid case"));
7263 else if(!strucmp(subcmd
, "copy")){
7266 * folder - imp new ans del
7269 int colid
, flgs
= 0, i
;
7273 if(Tcl_GetIntFromObj(interp
, objv
[1], &colid
) != TCL_ERROR
){
7275 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
7277 if((folder
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7278 if(pseudo_selected(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
))){
7280 if(colid
== 0 && !strucmp(folder
, "inbox"))
7281 flgs
|= SV_INBOXWOCNTXT
;
7283 i
= save(wps_global
, wps_global
->mail_stream
,
7284 cp
, folder
, sp_msgmap(wps_global
->mail_stream
), flgs
);
7286 err
= (i
== mn_total_cur(sp_msgmap(wps_global
->mail_stream
))) ? NULL
: "problem copying";
7288 restore_selected(sp_msgmap(wps_global
->mail_stream
));
7290 return(peApplyError(interp
, err
));
7292 Tcl_SetResult(interp
, long2string(i
), TCL_VOLATILE
);
7296 return(peApplyError(interp
, "can't select"));
7299 return(peApplyError(interp
, "no folder name"));
7302 return(peApplyError(interp
, "bad colid"));
7305 return(peApplyError(interp
, "invalid case"));
7307 else if(!strucmp(subcmd
, "move")){
7310 * folder - imp new ans del
7313 int colid
, flgs
= 0, i
;
7317 if(Tcl_GetIntFromObj(interp
, objv
[1], &colid
) != TCL_ERROR
){
7319 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
7321 if((folder
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7322 if(pseudo_selected(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
))){
7326 if(colid
== 0 && !strucmp(folder
, "inbox"))
7327 flgs
|= SV_INBOXWOCNTXT
;
7329 i
= save(wps_global
, wps_global
->mail_stream
,
7330 cp
, folder
, sp_msgmap(wps_global
->mail_stream
), flgs
);
7332 err
= (i
== mn_total_cur(sp_msgmap(wps_global
->mail_stream
))) ? NULL
: "problem moving";
7334 restore_selected(sp_msgmap(wps_global
->mail_stream
));
7336 return(peApplyError(interp
, err
));
7338 Tcl_SetResult(interp
, long2string(i
), TCL_VOLATILE
);
7342 return(peApplyError(interp
, "can't select"));
7345 return(peApplyError(interp
, "no folder name"));
7348 return(peApplyError(interp
, "bad colid"));
7351 return(peApplyError(interp
, "invalid case"));
7353 else if(!strucmp(subcmd
, "spam")){
7358 char *spamaddr
, *spamsubj
= NULL
;
7361 if((spamaddr
= Tcl_GetStringFromObj(objv
[1], NULL
))
7362 && (spamsubj
= Tcl_GetStringFromObj(objv
[2], NULL
))){
7363 for(n
= 1L; n
<= mn_get_total(sp_msgmap(wps_global
->mail_stream
)); n
++){
7364 rawno
= mn_m2raw(sp_msgmap(wps_global
->mail_stream
), n
);
7365 if(get_lflag(wps_global
->mail_stream
, NULL
, rawno
, MN_SLCT
)){
7366 char errbuf
[WP_MAX_POST_ERROR
+ 1], *rs
= NULL
;
7368 if((rs
= peSendSpamReport(rawno
, spamaddr
, spamsubj
, errbuf
)) != NULL
){
7369 Tcl_SetResult(interp
, rs
, TCL_VOLATILE
);
7376 Tcl_SetResult(interp
, "OK", TCL_VOLATILE
);
7382 return(peApplyError(interp
, "unknown option"));
7387 peApplyFlag(MAILSTREAM
*stream
, MSGNO_S
*msgmap
, char flag
, int not, long *flagged
)
7389 char *seq
, *flagstr
;
7394 flagstr
= "\\FLAGGED";
7395 flags
= not ? 0L : ST_SET
;
7396 flagid
= not ? F_FLAG
: F_UNFLAG
;
7400 flags
= not ? ST_SET
: 0L;
7401 flagid
= not ? F_UNSEEN
: F_SEEN
;
7404 flagstr
= "\\ANSWERED";
7405 flags
= not ? 0L : ST_SET
;
7406 flagid
= not ? F_ANS
: F_UNANS
;
7409 flagstr
= "\\DELETED";
7410 flags
= not ? 0L : ST_SET
;
7411 flagid
= not ? F_DEL
: F_UNDEL
;
7414 return("unknown flag");
7418 if(pseudo_selected(stream
, msgmap
)){
7419 if((seq
= currentf_sequence(stream
, msgmap
, flagid
, flagged
, 1, NULL
, NULL
)) != NULL
){
7420 mail_flag(stream
, seq
, flagstr
, flags
);
7421 fs_give((void **) &seq
);
7424 restore_selected(msgmap
);
7428 return("can't select");
7433 peApplyError(Tcl_Interp
*interp
, char *usage
)
7437 snprintf(buf
, sizeof(buf
), "apply error: %.128s", usage
);
7438 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
7444 * peIndexFormat - Return with interp's result object set to
7445 * represent the index line's format as a list of
7446 * index-field-name, percentage-width pairs
7449 peIndexFormat(Tcl_Interp
*interp
)
7451 INDEX_COL_S
*cdesc
= NULL
;
7452 char *name
, wbuf
[4], *dname
;
7454 for(cdesc
= wps_global
->index_disp_format
;
7455 cdesc
->ctype
!= iNothing
;
7458 switch(cdesc
->ctype
){
7477 case iDate
: case iSDate
: case iSTime
: case iLDate
:
7478 case iS1Date
: case iS2Date
: case iS3Date
: case iS4Date
: case iDateIso
:
7480 case iSDateIso
: case iSDateIsoS
:
7481 case iSDateS1
: case iSDateS2
:
7482 case iSDateS3
: case iSDateS4
:
7484 case iSDateTimeIso
: case iSDateTimeIsoS
:
7485 case iSDateTimeS1
: case iSDateTimeS2
:
7486 case iSDateTimeS3
: case iSDateTimeS4
:
7488 case iSDateTimeIso24
: case iSDateTimeIsoS24
:
7489 case iSDateTimeS124
: case iSDateTimeS224
:
7490 case iSDateTimeS324
: case iSDateTimeS424
:
7491 case iCurDate
: case iCurDateIso
: case iCurDateIsoS
:
7492 case iCurTime24
: case iCurTime12
:
7497 case iCurDay
: case iCurDay2Digit
:
7498 case iCurDayOfWeek
: case iCurDayOfWeekAbb
:
7502 case iCurMon
: case iCurMon2Digit
:
7503 case iCurMonLong
: case iCurMonAbb
:
7507 case iTime24
: case iTime12
: case iTimezone
:
7512 case iDay2Digit
: case iDayOfWeek
: case iDayOfWeekAbb
:
7516 case iMonAbb
: case iMon2Digit
:
7520 case iYear
: case iYear2Digit
:
7521 case iCurYear
: case iCurYear2Digit
:
7530 case iFromToNotNews
:
7545 name
= "Recipients";
7561 name
= "Attachments";
7573 case iOpeningTextNQ
:
7582 case iShortSubject
:
7583 case iShortSubjKey
:
7584 case iSubjKeyInitText
:
7585 case iShortSubjKeyInit
:
7594 case iNewsAndRecips
:
7595 name
= "News/Recip";
7598 case iRecipsAndNews
:
7599 name
= "Recip/News";
7607 if(cdesc
->width
> 0){
7608 int p
= ((cdesc
->width
* 100) / FAKE_SCREEN_WIDTH
);
7610 snprintf(wbuf
, sizeof(wbuf
), "%d%%", p
);
7615 if(peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s%s", name
, wbuf
, dname
) != TCL_OK
)
7624 peNewMailResult(Tcl_Interp
*interp
)
7626 unsigned long n
, uid
;
7628 if(sp_mail_box_changed(wps_global
->mail_stream
)){
7629 if((n
= sp_mail_since_cmd(wps_global
->mail_stream
)) != 0L){
7630 /* first element is count of new messages */
7631 if(Tcl_ListObjAppendElement(interp
,
7632 Tcl_GetObjResult(interp
),
7633 Tcl_NewLongObj(n
)) != TCL_OK
)
7636 /* second element is UID of most recent message */
7637 for(uid
= wps_global
->mail_stream
->nmsgs
; uid
> 1L; uid
--)
7638 if(!get_lflag(wps_global
->mail_stream
, NULL
, uid
, MN_EXLD
))
7642 Tcl_ResetResult(interp
);
7643 Tcl_SetResult(interp
, "0 0 0", TCL_STATIC
);
7647 uid
= mail_uid(wps_global
->mail_stream
, uid
);
7649 if(Tcl_ListObjAppendElement(interp
,
7650 Tcl_GetObjResult(interp
),
7651 Tcl_NewLongObj(uid
)) != TCL_OK
)
7655 if(Tcl_ListObjAppendElement(interp
,
7656 Tcl_GetObjResult(interp
),
7657 Tcl_NewIntObj(0)) != TCL_OK
)
7660 /* zero is UID of new message */
7661 if(Tcl_ListObjAppendElement(interp
,
7662 Tcl_GetObjResult(interp
),
7663 Tcl_NewIntObj(0)) != TCL_OK
)
7667 /* third element is expunge count */
7668 if(Tcl_ListObjAppendElement(interp
,
7669 Tcl_GetObjResult(interp
),
7670 Tcl_NewLongObj(sp_expunge_count(wps_global
->mail_stream
)
7671 ? sp_expunge_count(wps_global
->mail_stream
)
7677 Tcl_SetResult(interp
, "0 0 0", TCL_STATIC
);
7683 /* * * * * * * * Start of Per-Thread/SubThread access functions * * * * * * * */
7687 * PEThreadCmd - access/manipulate various pieces of thread state
7690 PEThreadCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
7692 char *err
, errbuf
[256], *cmd
, *op
;
7696 dprint((2, "PEThreadCmd"));
7698 snprintf(err
= errbuf
, sizeof(errbuf
), "Unknown %s request",
7699 Tcl_GetStringFromObj(objv
[0], NULL
));
7701 if(!(wps_global
&& wps_global
->mail_stream
)){
7702 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: No open mailbox",
7703 Tcl_GetStringFromObj(objv
[0], NULL
));
7706 Tcl_WrongNumArgs(interp
, 1, objv
, "uid cmd ?args?");
7708 else if(Tcl_GetLongFromObj(interp
, objv
[1], &uidl
) != TCL_OK
){
7709 return(TCL_ERROR
); /* conversion problem? */
7711 else if(!peSequenceNumber(uidl
)){
7712 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: UID %ld doesn't exist",
7713 Tcl_GetStringFromObj(objv
[0], NULL
), uidl
);
7715 else if((cmd
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7718 if(!strucmp(cmd
,"info")){
7719 #define WP_MAX_THRD_PREFIX 256
7722 char tstr
[WP_MAX_THRD_PREFIX
];
7724 if((raw
= peSequenceNumber(uid
)) != 0L){
7726 * translate PINETHRD_S data into
7728 if((pthrd
= msgno_thread_info(wps_global
->mail_stream
, raw
, NULL
, THD_TOP
)) != NULL
){
7731 /* BUG: build tstr form pthrd */
7734 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
7735 Tcl_NewStringObj(tstr
, -1));
7739 Tcl_SetResult(interp
, "0", TCL_STATIC
);
7746 if(!strucmp(cmd
,"flag")){
7747 if((op
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
7748 if(!strucmp(op
,"deleted")){
7751 if(Tcl_GetIntFromObj(interp
, objv
[4], &value
) != TCL_ERROR
){
7757 if(!(n
= peSequenceNumber(uid
))){
7758 Tcl_SetResult(interp
, "Unrecognized UID", TCL_STATIC
);
7762 flag
= cpystr("\\DELETED");
7763 mail_flag(wps_global
->mail_stream
, long2string(n
), flag
, (value
? ST_SET
: 0L));
7764 fs_give((void **) &flag
);
7766 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
7767 Tcl_NewStringObj(ulong2string(uid
), -1));
7769 if(++n
<= wps_global
->mail_stream
->nmsgs
){
7770 uid
= mail_uid(wps_global
->mail_stream
, n
);
7775 if((pthrd
= msgno_thread_info(wps_global
->mail_stream
, n
, NULL
,THD_TOP
)) != NULL
){
7787 Tcl_SetResult(interp
, err
, TCL_STATIC
);
7793 /* * * * * * * * Start of Per-Message access functions * * * * * * * */
7797 static struct _message_cmds
{
7802 int (*f
)(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
7804 } message_cmds
[] = {
7805 {"size", 1, {{3, peMessageSize
}}},
7806 {"date", 2, {{3, peMessageDate
}, {4, peMessageDate
}}},
7807 {"subject", 1, {{3, peMessageSubject
}}},
7808 {"fromaddr", 1, {{3, peMessageFromAddr
}}},
7809 {"toaddr", 1, {{3, peMessageToAddr
}}},
7810 {"ccaddr", 1, {{3, peMessageCcAddr
}}},
7811 {"status", 1, {{3, peMessageStatus
}}},
7812 {"statusbits", 1, {{3, peMessageStatusBits
}}},
7813 {"charset", 1, {{3, peMessageCharset
}}},
7814 {"number", 1, {{3, peMsgnoFromUID
}}},
7817 {"text", 1, {{3, peMessageText
}}},
7818 {"header", 1, {{3, peMessageHeader
}}},
7819 {"attachments", 1, {{3, peMessageAttachments
}}},
7820 {"body", 3, {{3, peMessageBody
}, {4, peMessageBody
}}},
7821 {"cid", 1, {{4, peMessagePartFromCID
}}},
7822 {"flag", 2, {{4, peGetFlag
}, {5, peSetFlag
}}},
7823 {"replyheaders", 2, {{3, peReplyHeaders
},{4, peReplyHeaders
}}},
7824 {"replytext", 2, {{4, peReplyText
}, {5, peReplyText
}}},
7825 {"forwardheaders", 2, {{3, peForwardHeaders
}, {4, peForwardHeaders
}}},
7826 {"forwardtext", 2, {{3, peForwardText
}, {4, peForwardText
}}},
7828 {"select", 2, {{3, peMsgSelect
}, {4, peMsgSelect
}}},
7829 {"detach", 1, {{5, peDetach
}}},
7830 {"attachinfo", 1, {{4, peAttachInfo
}}},
7831 {"savedefault", 1, {{3, peSaveDefault
}}},
7832 {"save", 1, {{5, peSave
}}},
7833 {"copy", 1, {{5, peCopy
}}},
7834 {"move", 1, {{5, peMove
}}},
7835 {"takeaddr", 1, {{3, peTakeaddr
}}},
7836 {"takefrom", 1, {{3, peTakeFrom
}}},
7837 {"replyquote", 1, {{3, peReplyQuote
}}},
7838 {"bounce", 2, {{4, peMessageBounce
},{5, peMessageBounce
}}},
7839 {"spam", 1, {{5, peMessageSpamNotice
}}},
7840 {"needpasswd", 1, {{3, peMessageNeedPassphrase
}}},
7848 * PEMessageCmd - export various bits of message information
7850 * NOTE: all exported commands are of the form:
7852 * PEMessage <uid> <cmd> <args>
7855 PEMessageCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
7857 char *err
, errbuf
[256], *cmd
;
7862 dprint((5, "PEMessageCmd"));
7864 snprintf(err
= errbuf
, sizeof(errbuf
), "Unknown %s request",
7865 Tcl_GetStringFromObj(objv
[0], NULL
));
7867 if(!(wps_global
&& wps_global
->mail_stream
)){
7868 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: No open mailbox",
7869 Tcl_GetStringFromObj(objv
[0], NULL
));
7872 Tcl_WrongNumArgs(interp
, 0, objv
, "PEMessage <uid> cmd ?args?");
7874 else if(Tcl_GetLongFromObj(interp
, objv
[1], &uidl
) != TCL_OK
){
7875 return(TCL_ERROR
); /* conversion problem? */
7877 else if(!peMessageNumber(uidl
)){
7878 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: UID %ld doesn't exist",
7879 Tcl_GetStringFromObj(objv
[0], NULL
), uidl
);
7881 else if((cmd
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7883 for(i
= 0; message_cmds
[i
].cmd
; i
++)
7884 if(!strcmp(cmd
, message_cmds
[i
].cmd
)){
7885 for(j
= 0; j
< message_cmds
[i
].hcount
; j
++)
7886 if(message_cmds
[i
].h
[j
].argcount
== objc
)
7887 return((*message_cmds
[i
].h
[j
].f
)(interp
, uid
, objc
- 3,
7888 &((Tcl_Obj
**)objv
)[3]));
7890 snprintf(err
= errbuf
, sizeof(errbuf
),
7891 "PEMessage: %s: mismatched argument count", cmd
);
7896 Tcl_SetResult(interp
, err
, TCL_STATIC
);
7902 * return the uid's ordinal number within the CURRENT SORT
7905 peMessageNumber(imapuid_t uid
)
7907 return(mn_raw2m(sp_msgmap(wps_global
->mail_stream
), peSequenceNumber(uid
)));
7911 * return the uid's RAW message number (for c-client reference, primarily)
7914 peSequenceNumber(imapuid_t uid
)
7916 return(mail_msgno(wps_global
->mail_stream
, uid
));
7921 peMessageSize(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7925 if((raw
= peSequenceNumber(uid
))
7926 && pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
)){
7927 Tcl_SetResult(interp
,
7928 long2string(mail_elt(wps_global
->mail_stream
,
7933 Tcl_SetResult(interp
, "0", TCL_STATIC
);
7940 peMessageDate(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7947 if((raw
= peSequenceNumber(uid
))
7948 && (env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
))){
7949 if(objc
== 1 && objv
[0]){
7950 if(mail_parse_date(&mc
, env
->date
)){
7951 if((cmd
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
){
7952 if(!strucmp(cmd
,"day")){
7953 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%02d", mc
.day
);
7954 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
7957 else if(!strucmp(cmd
,"month")){
7958 Tcl_SetResult(interp
, month_abbrev(mc
.month
), TCL_VOLATILE
);
7961 else if(!strucmp(cmd
,"year")){
7962 Tcl_SetResult(interp
, int2string(mc
.year
+ BASEYEAR
), TCL_VOLATILE
);
7966 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "peMessageDate cmd: %.20s", cmd
);
7967 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
7971 Tcl_SetResult(interp
, "peMessageDate: can't get command", TCL_STATIC
);
7974 Tcl_SetResult(interp
, "peMessageDate: can't parse date", TCL_STATIC
);
7977 Tcl_SetResult(interp
, env
->date
? (char *) env
->date
: "", TCL_VOLATILE
);
7982 Tcl_SetResult(interp
, "Can't get message structure", TCL_STATIC
);
7989 peMessageFromAddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7991 return(peMessageField(interp
, uid
, "from"));
7996 peMessageToAddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7998 return(peMessageField(interp
, uid
, "to"));
8003 peMessageCcAddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8005 return(peMessageField(interp
, uid
, "cc"));
8010 peMessageSubject(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8012 return(peMessageField(interp
, uid
, "subject"));
8017 peMessageField(Tcl_Interp
*interp
, imapuid_t uid
, char *field
)
8023 if((raw
= peSequenceNumber(uid
))
8024 && (env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
))){
8025 if(!strucmp(field
, "from")){
8026 if(env
->from
&& env
->from
->mailbox
)
8027 snprintf(s
= wtmp_20k_buf
, SIZEOF_20KBUF
, "%.256s%s%.256s", env
->from
->mailbox
,
8028 (env
->from
->host
) ? "@" : "", (env
->from
->host
) ? env
->from
->host
: "");
8030 else if(!strucmp(field
, "to")){
8031 if(env
->to
&& env
->to
->mailbox
)
8032 snprintf(s
= wtmp_20k_buf
, SIZEOF_20KBUF
, "%.256s%s%.256s", env
->to
->mailbox
,
8033 (env
->to
->host
) ? "@" : "", (env
->to
->host
) ? env
->to
->host
: "");
8035 else if(!strucmp(field
, "cc")){
8036 if(env
->cc
&& env
->cc
->mailbox
)
8037 snprintf(s
= wtmp_20k_buf
, SIZEOF_20KBUF
, "%.256s%s%.256s", env
->cc
->mailbox
,
8038 (env
->cc
->host
) ? "@" : "", (env
->cc
->host
) ? env
->cc
->host
: "");
8040 else if(!strucmp(field
, "subject")){
8042 snprintf(s
= wtmp_20k_buf
, SIZEOF_20KBUF
, "%.256s", env
->subject
);
8045 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Unknown message field: %.20s", field
);
8046 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
8050 Tcl_SetResult(interp
, s
, TCL_VOLATILE
);
8054 Tcl_SetResult(interp
, "Can't read message envelope", TCL_STATIC
);
8060 peMessageStatus(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8065 if((raw
= peSequenceNumber(uid
)) != 0L){
8066 if(!((mc
= mail_elt(wps_global
->mail_stream
, raw
))
8068 mail_fetch_flags(wps_global
->mail_stream
,
8069 ulong2string(uid
), FT_UID
);
8070 mc
= mail_elt(wps_global
->mail_stream
, raw
);
8074 Tcl_ListObjAppendElement(interp
,
8075 Tcl_GetObjResult(interp
),
8076 Tcl_NewStringObj("Deleted", -1));
8079 Tcl_ListObjAppendElement(interp
,
8080 Tcl_GetObjResult(interp
),
8081 Tcl_NewStringObj("Answered", -1));
8084 Tcl_ListObjAppendElement(interp
,
8085 Tcl_GetObjResult(interp
),
8086 Tcl_NewStringObj("New", -1));
8089 Tcl_ListObjAppendElement(interp
,
8090 Tcl_GetObjResult(interp
),
8091 Tcl_NewStringObj("Important", -1));
8099 peMessageCharset(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8101 /* everything coming out of pith better be utf-8 */
8102 Tcl_SetResult(interp
, "UTF-8", TCL_STATIC
);
8108 peMessageNeedPassphrase(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8111 return((wps_global
&& wps_global
->smime
&& wps_global
->smime
->need_passphrase
) ? TCL_OK
: TCL_ERROR
);
8119 peMsgnoFromUID(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8121 Tcl_SetResult(interp
, long2string(peMessageNumber(uid
)), TCL_VOLATILE
);
8127 * peInterpWritec - collect filtered output, appending to the
8128 * command's result list on each EOL
8131 peInterpWritec(int c
)
8133 unsigned char ch
= (unsigned char) (0xff & c
);
8136 return(peInterpFlush() == TCL_OK
);
8138 so_writec(ch
, peED
.store
);
8145 * peInterpFlush - write accumulated line to result object mapping
8146 * embedded data into exportable tcl list members
8152 char *line
, *p
, *tp
, *tp2
, col1
[32], col2
[32];
8153 Tcl_Obj
*lobjp
, *objColor
, *objPair
;
8155 line
= (char *) so_text(peED
.store
);
8157 if((lobjp
= Tcl_NewListObj(0, NULL
)) != NULL
){
8158 if((p
= strindex(line
, TAG_EMBED
)) != NULL
){
8163 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", line
);
8172 for(n
= 0, i
= *++p
; i
> 0; i
--)
8173 n
= (n
* 10) + (*++p
- '0');
8175 line
= ++p
; /* prepare for next section of line */
8180 if((h
= get_handle(peED
.handles
, n
)) != NULL
)
8184 Tcl_Obj
*llObj
, *rObj
;
8186 llObj
= Tcl_NewListObj(0, NULL
);
8187 Tcl_ListObjAppendElement(peED
.interp
, llObj
, Tcl_NewStringObj("img", -1));
8189 rObj
= Tcl_NewListObj(0, NULL
);
8190 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.img
.src
? h
->h
.img
.src
: "", -1));
8191 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.img
.alt
? h
->h
.img
.alt
: "", -1));
8193 Tcl_ListObjAppendElement(peED
.interp
, llObj
, rObj
);
8195 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, llObj
);
8203 Tcl_Obj
*llObj
, *rObj
;
8205 llObj
= Tcl_NewListObj(0, NULL
);
8206 Tcl_ListObjAppendElement(peED
.interp
, llObj
, Tcl_NewStringObj("urlstart", -1));
8208 rObj
= Tcl_NewListObj(0, NULL
);
8209 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.url
.path
? h
->h
.url
.path
: "", -1));
8210 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.url
.name
? h
->h
.url
.name
: "", -1));
8212 Tcl_ListObjAppendElement(peED
.interp
, llObj
, rObj
);
8214 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, llObj
);
8221 Tcl_Obj
*alObj
, *rObj
, *tObj
, *stObj
, *fnObj
, *eObj
;
8223 alObj
= Tcl_NewListObj(0, NULL
);
8224 Tcl_ListObjAppendElement(peED
.interp
, alObj
, Tcl_NewStringObj("attach", -1));
8226 peGetMimeTyping(mail_body(wps_global
->mail_stream
,
8227 peSequenceNumber(peED
.uid
),
8228 (unsigned char *) h
->h
.attach
->number
),
8229 &tObj
, &stObj
, &fnObj
, &eObj
);
8232 rObj
= Tcl_NewListObj(0, NULL
);
8233 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewLongObj(peED
.uid
));
8234 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.attach
->number
, -1));
8235 Tcl_ListObjAppendElement(peED
.interp
, rObj
, tObj
);
8236 Tcl_ListObjAppendElement(peED
.interp
, rObj
, stObj
);
8237 Tcl_ListObjAppendElement(peED
.interp
, rObj
, fnObj
);
8238 Tcl_ListObjAppendElement(peED
.interp
, rObj
, eObj
);
8240 Tcl_ListObjAppendElement(peED
.interp
, alObj
, rObj
);
8242 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, alObj
);
8256 if((tp
= peColorStr(++p
, col1
)) && (strcmp(tp
, peED
.color
.fg
) || strcmp(tp
, peED
.color
.fgdef
))){
8258 if(p
[11] == TAG_EMBED
8259 && p
[12] == TAG_BGCOLOR
8260 && (tp2
= peColorStr(p
+ 13, col2
))){
8261 objColor
= Tcl_NewListObj(0, NULL
);
8262 objPair
= Tcl_NewListObj(0, NULL
);
8263 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8264 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8265 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp2
, -1));
8266 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8267 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8268 strcpy(peED
.color
.bg
, tp2
);
8271 else if(strcmp(peED
.color
.bg
, peED
.color
.bgdef
)){
8272 objColor
= Tcl_NewListObj(0, NULL
);
8273 objPair
= Tcl_NewListObj(0, NULL
);
8274 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8275 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8276 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(peED
.color
.bgdef
, -1));
8277 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8278 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8279 strcpy(peED
.color
.bg
, peED
.color
.bgdef
);
8282 peAppListF(peED
.interp
, lobjp
, "%s%s", "fgcolor", tp
);
8284 strcpy(peED
.color
.fg
, tp
);
8291 if((tp
= peColorStr(++p
, col1
)) && (strcmp(tp
, peED
.color
.bg
) || strcmp(tp
, peED
.color
.bgdef
))){
8293 if(p
[11] == TAG_EMBED
8294 && p
[12] == TAG_FGCOLOR
8295 && (tp2
= peColorStr(p
+ 13, col2
))){
8296 objColor
= Tcl_NewListObj(0, NULL
);
8297 objPair
= Tcl_NewListObj(0, NULL
);
8298 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8299 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp2
, -1));
8300 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8301 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8302 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8303 strcpy(peED
.color
.fg
, tp2
);
8306 else if(strcmp(peED
.color
.fg
, peED
.color
.fgdef
)){
8307 objColor
= Tcl_NewListObj(0, NULL
);
8308 objPair
= Tcl_NewListObj(0, NULL
);
8309 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8310 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(peED
.color
.fgdef
, -1));
8311 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8312 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8313 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8314 strcpy(peED
.color
.fg
, peED
.color
.fgdef
);
8317 peAppListF(peED
.interp
, lobjp
, "%s%s", "bgcolor", tp
);
8319 strcpy(peED
.color
.bg
, tp
);
8326 peAppListF(peED
.interp
, lobjp
, "%s%s", "italic", "on");
8330 case TAG_ITALICOFF
:
8331 peAppListF(peED
.interp
, lobjp
, "%s%s", "italic", "off");
8336 peAppListF(peED
.interp
, lobjp
, "%s%s", "bold", "on");
8341 peAppListF(peED
.interp
, lobjp
, "%s%s", "bold", "off");
8346 peAppListF(peED
.interp
, lobjp
, "%s%s", "underline", "on");
8351 peAppListF(peED
.interp
, lobjp
, "%s%s", "underline", "off");
8356 peAppListF(peED
.interp
, lobjp
, "%s%s", "strikethru", "on");
8360 case TAG_STRIKEOFF
:
8361 peAppListF(peED
.interp
, lobjp
, "%s%s", "strikethru", "off");
8366 peAppListF(peED
.interp
, lobjp
, "%s%s", "bigfont", "on");
8371 peAppListF(peED
.interp
, lobjp
, "%s%s", "bigfont", "off");
8376 peAppListF(peED
.interp
, lobjp
, "%s%s", "smallfont", "on");
8381 peAppListF(peED
.interp
, lobjp
, "%s%s", "smallfont", "off");
8386 case TAG_HANDLEOFF
:
8388 peAppListF(peED
.interp
, lobjp
, "%s%s", "urlend", "");
8391 /* fall thru and advance "line" */
8399 while((p
= strindex(line
, TAG_EMBED
)) != NULL
);
8402 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", line
);
8405 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", line
);
8408 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", "");
8410 if(Tcl_ListObjAppendElement(peED
.interp
, peED
.obj
, lobjp
) == TCL_OK
){
8411 so_truncate(peED
.store
, 0L);
8421 * peInterpWritec - collect filtered output, appending to the
8422 * command's result list on each EOL
8432 peColorStr(char *s
, char *b
)
8440 for(j
= 0; j
< 3; j
++, s
++)
8441 if(isdigit((unsigned char) *s
))
8442 color
= (color
* 10) + (*s
- '0');
8444 s
++; /* advance past ',' */
8446 sprintf(b
+ strlen(b
), "%2.2x", color
);
8460 * returns a list of elements
8463 peMessageHeader(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8467 int flags
, rv
= TCL_OK
;
8474 * ONLY full header mode (raw) output should get written to the
8475 * writec function we pass format_header. If there's something
8476 * in the store after formatting ,we'll write it to the Tcl result
8477 * then, not as its accumulated
8479 peED
.interp
= interp
;
8480 peED
.obj
= Tcl_NewStringObj("", -1);
8483 so_seek(peED
.store
, 0L, 0);
8485 peED
.store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
8487 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_NOHTMLREL
| FM_HTMLRELATED
;
8490 peED
.color
.fg
[0] = '\0';
8491 if((color
= pico_get_last_fg_color()) && (color
= color_to_asciirgb(color
))){
8492 peInterpWritec(TAG_EMBED
);
8493 peInterpWritec(TAG_FGCOLOR
);
8494 gf_puts(color
, peInterpWritec
);
8495 strcpy(peED
.color
.fgdef
, peColorStr(color
, wtmp_20k_buf
));
8498 peED
.color
.bg
[0] = '\0';
8499 if((color
= pico_get_last_bg_color()) && (color
= color_to_asciirgb(color
))){
8500 peInterpWritec(TAG_EMBED
);
8501 peInterpWritec(TAG_BGCOLOR
);
8502 gf_puts(color
, peInterpWritec
);
8503 strcpy(peED
.color
.bgdef
, peColorStr(color
,wtmp_20k_buf
));
8509 raw
= peSequenceNumber(uid
);
8510 if(peED
.uid
!= uid
){
8514 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
8515 if(!((peED
.env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, &peED
.body
))
8516 && (mc
= mail_elt(wps_global
->mail_stream
, raw
)))){
8519 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
8520 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate");
8522 dprint((1, "ERROR fetching %s of msg %ld: %s",
8523 peED
.env
? "elt" : "env", mn_get_cur(sp_msgmap(wps_global
->mail_stream
)),
8524 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate"));
8526 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8530 zero_atmts(wps_global
->atmts
);
8532 if(wps_global
&& wps_global
->smime
&& wps_global
->smime
->need_passphrase
)
8533 wps_global
->smime
->need_passphrase
= 0;
8535 fiddle_smime_message(peED
.body
, raw
);
8537 describe_mime(peED
.body
, "", 1, 1, 0, flags
);
8541 /* NO HANDLES init_handles(&peED.handles);*/
8544 * Collect header pieces into lists via the passed custom formatter. Collect
8545 * everything else in the storage object passed. The latter should only end up
8546 * with raw header data.
8548 * BUG: DEAL WITH COLORS
8551 HD_INIT(&h
, wps_global
->VAR_VIEW_HEADERS
, wps_global
->view_all_except
, FE_DEFAULT
);
8552 if(format_header(wps_global
->mail_stream
, raw
, NULL
, peED
.env
, &h
,
8553 NULL
, NULL
, flags
, peFormatEnvelope
, peInterpWritec
) != 0){
8556 snprintf(buf
, sizeof(buf
), "Error formatting header %ld", peMessageNumber(uid
));
8559 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8565 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "%s%s%o", "raw", "", peED
.obj
);
8567 so_give(&peED
.store
);
8572 peFormatEnvelope(MAILSTREAM
*s
, long int n
, char *sect
, ENVELOPE
*e
, gf_io_t pc
, long int which
, char *oacs
, int flags
)
8574 char *p2
, buftmp
[MAILTMPLEN
];
8580 if((which
& FE_DATE
) && e
->date
) {
8581 if((objHdr
= Tcl_NewListObj(0, NULL
)) != NULL
){
8582 snprintf(buftmp
, sizeof(buftmp
), "%s", (char *) e
->date
);
8583 buftmp
[sizeof(buftmp
)-1] = '\0';
8584 p2
= (char *)rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
, SIZEOF_20KBUF
, buftmp
);
8585 peFormatEnvelopeText("Date", p2
);
8587 /* BUG: how does error feedback bubble back up? */
8590 if((which
& FE_FROM
) && e
->from
)
8591 peFormatEnvelopeAddress(s
, n
, sect
, "From", e
->from
, flags
, oacs
, pc
);
8593 if((which
& FE_REPLYTO
) && e
->reply_to
&& (!e
->from
|| !address_is_same(e
->reply_to
, e
->from
)))
8594 peFormatEnvelopeAddress(s
, n
, sect
, "Reply-To", e
->reply_to
, flags
, oacs
, pc
);
8596 if((which
& FE_TO
) && e
->to
)
8597 peFormatEnvelopeAddress(s
, n
, sect
, "To", e
->to
, flags
, oacs
, pc
);
8599 if((which
& FE_CC
) && e
->cc
)
8600 peFormatEnvelopeAddress(s
, n
, sect
, "Cc", e
->cc
, flags
, oacs
, pc
);
8602 if((which
& FE_BCC
) && e
->bcc
)
8603 peFormatEnvelopeAddress(s
, n
, sect
, "Bcc", e
->bcc
, flags
, oacs
, pc
);
8605 if((which
& FE_RETURNPATH
) && e
->return_path
)
8606 peFormatEnvelopeAddress(s
, n
, sect
, "Return-Path", e
->return_path
, flags
, oacs
, pc
);
8608 if((which
& FE_NEWSGROUPS
) && e
->newsgroups
)
8609 peFormatEnvelopeNewsgroups("Newsgroups", e
->newsgroups
, flags
, pc
);
8611 if((which
& FE_FOLLOWUPTO
) && e
->followup_to
)
8612 peFormatEnvelopeNewsgroups("Followup-To", e
->followup_to
, flags
, pc
);
8614 if((which
& FE_SUBJECT
) && e
->subject
&& e
->subject
[0]){
8615 if((objHdr
= Tcl_NewListObj(0, NULL
)) != NULL
){
8616 char *freeme
= NULL
;
8618 p2
= iutf8ncpy((char *)(wtmp_20k_buf
+10000),
8619 (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf
, 10000, e
->subject
),
8620 SIZEOF_20KBUF
-10000);
8622 if(flags
& FM_DISPLAY
8623 && (wps_global
->display_keywords_in_subject
8624 || wps_global
->display_keywordinits_in_subject
)){
8626 /* don't bother if no keywords are defined */
8627 if(some_user_flags_defined(s
))
8628 p2
= freeme
= prepend_keyword_subject(s
, n
, p2
,
8629 wps_global
->display_keywords_in_subject
? KW
: KWInit
,
8630 NULL
, wps_global
->VAR_KW_BRACES
);
8633 peFormatEnvelopeText("Subject", p2
);
8636 fs_give((void **) &freeme
);
8640 if((which
& FE_SENDER
) && e
->sender
&& (!e
->from
|| !address_is_same(e
->sender
, e
->from
)))
8641 peFormatEnvelopeAddress(s
, n
, sect
, "Sender", e
->sender
, flags
, oacs
, pc
);
8643 if((which
& FE_MESSAGEID
) && e
->message_id
){
8644 p2
= iutf8ncpy((char *)(wtmp_20k_buf
+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf
, 10000, e
->message_id
), SIZEOF_20KBUF
-10000);
8645 peFormatEnvelopeText("Message-ID", p2
);
8648 if((which
& FE_INREPLYTO
) && e
->in_reply_to
){
8649 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);
8650 peFormatEnvelopeText("In-Reply-To", p2
);
8653 if((which
& FE_REFERENCES
) && e
->references
) {
8654 p2
= iutf8ncpy((char *)(wtmp_20k_buf
+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf
, 10000, e
->references
), SIZEOF_20KBUF
-10000);
8655 peFormatEnvelopeText("References", p2
);
8661 * appends caller's result with: {"text" field_name {field_value}}
8664 peFormatEnvelopeText(char *field_name
, char *field_value
)
8666 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "%s%s%s", "text", field_name
, field_value
);
8671 * appends caller's result with: {"addr" field_name {{{personal} {mailbox}} ... }}
8672 * {"rawaddr" field_name {{raw_address} ... }}
8675 peFormatEnvelopeAddress(MAILSTREAM
*stream
, long int msgno
, char *section
, char *field_name
,
8676 struct mail_address
*addr
, int flags
, char *oacs
, gf_io_t pc
)
8678 char *ptmp
, *mtmp
, *atype
= "addr";
8681 Tcl_Obj
*objAddrList
= NULL
;
8684 extern const char *rspecials
;
8685 extern const char *rspecials_minus_quote_and_dot
;
8691 * quickly run down address list to make sure none are patently bogus.
8692 * If so, just blat raw field out.
8694 for(atmp
= addr
; stream
&& atmp
; atmp
= atmp
->next
)
8695 if(atmp
->host
&& atmp
->host
[0] == '.'){
8696 char *field
, *fields
[2];
8699 if((objAddrList
= Tcl_NewListObj(0,NULL
)) == NULL
)
8700 return; /* BUG: handle list creation failure */
8703 fields
[0] = cpystr(field_name
);
8704 if((ptmp
= strchr(fields
[0], ':')) != NULL
)
8707 if((field
= pine_fetchheader_lines(stream
, msgno
, section
, fields
)) != NULL
){
8710 for(t
= h
= field
; *h
; t
++)
8711 if(*t
== '\015' && *(t
+1) == '\012'){
8712 *t
= '\0'; /* tie off line */
8714 Tcl_ListObjAppendElement(peED
.interp
, objAddrList
, Tcl_NewStringObj(h
,-1));
8716 if(!*(h
= (++t
) + 1)) /* set new h and skip CRLF */
8717 break; /* no more to write */
8719 else if(!*t
){ /* shouldn't happen much */
8721 Tcl_ListObjAppendElement(peED
.interp
, objAddrList
, Tcl_NewStringObj(h
,-1));
8726 fs_give((void **)&field
);
8729 fs_give((void **)&fields
[0]);
8733 if((objAddrList
= Tcl_NewListObj(0,NULL
)) == NULL
|| (tso
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
)
8734 return; /* BUG: handle list creation failure */
8736 gf_set_so_writec(&tpc
, tso
);
8740 atmp
= addr
->next
; /* remember what's next */
8742 if(!addr
->host
&& addr
->mailbox
){
8743 mtmp
= addr
->mailbox
;
8744 addr
->mailbox
= cpystr((char *)rfc1522_decode_to_utf8(
8745 (unsigned char *)wtmp_20k_buf
,
8746 SIZEOF_20KBUF
, addr
->mailbox
));
8749 ptmp
= addr
->personal
; /* RFC 1522 personal name? */
8750 addr
->personal
= iutf8ncpy((char *)wtmp_20k_buf
, (char *)rfc1522_decode_to_utf8((unsigned char *)(wtmp_20k_buf
+10000), SIZEOF_20KBUF
-10000, addr
->personal
), 10000);
8751 wtmp_20k_buf
[10000-1] = '\0';
8754 /* Logic taken from: pine_rfc822_write_address_noquote(addr, pc, &group); */
8755 if (addr
->host
) { /* ordinary address? */
8756 if (!(addr
->personal
|| addr
->adl
)){
8757 so_seek(tso
, 0L, 0);
8758 pine_rfc822_address (addr
, tpc
);
8759 peAppListF(peED
.interp
, objAddrList
, "%s%o", "", Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
)));
8761 else { /* no, must use phrase <route-addr> form */
8764 if (addr
->personal
){
8765 so_seek(tso
, 0L, 0);
8766 pine_rfc822_cat (addr
->personal
, rspecials_minus_quote_and_dot
, tpc
);
8767 objTmp
= Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
));
8770 so_seek(tso
, 0L, 0);
8771 pine_rfc822_address(addr
, tpc
);
8772 peAppListF(peED
.interp
, objAddrList
, "%o%o", objTmp
, Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
)));
8778 else if (addr
->mailbox
) { /* start of group? */
8779 so_seek(tso
, 0L, 0);
8780 /* yes, write group name */
8781 pine_rfc822_cat (addr
->mailbox
, rspecials
, tpc
);
8782 peAppListF(peED
.interp
, objAddrList
, "%o%s", Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
)), "");
8783 group
= 1; /* in a group */
8785 else if (group
) { /* must be end of group (but be paranoid) */
8786 peAppListF(peED
.interp
, objAddrList
, "%s%s", "", ";");
8787 group
= 0; /* no longer in that group */
8790 addr
->personal
= ptmp
; /* restore old personal ptr */
8791 if(!addr
->host
&& addr
->mailbox
){
8792 fs_give((void **)&addr
->mailbox
);
8793 addr
->mailbox
= mtmp
;
8800 gf_clear_so_writec(tso
);
8804 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "%s%s%o", atype
, field_name
, objAddrList
);
8809 * appends caller's result with: {"news" field_name {{newsgroup1} {newsgroup2} ... }}
8812 peFormatEnvelopeNewsgroups(char *field_name
, char *newsgrps
, int flags
, gf_io_t pc
)
8814 char buf
[MAILTMPLEN
];
8817 Tcl_Obj
*objNewsgroups
;
8819 /* BUG: handle list creation failure */
8820 if(!newsgrps
|| !*newsgrps
|| (objNewsgroups
= Tcl_NewListObj(0,NULL
)) == NULL
)
8823 llen
= strlen(field_name
);
8825 for(next_ng
= newsgrps
; *next_ng
&& *next_ng
!= ','; next_ng
++)
8828 strncpy(buf
, newsgrps
, MIN(next_ng
- newsgrps
, sizeof(buf
)-1));
8829 buf
[MIN(next_ng
- newsgrps
, sizeof(buf
)-1)] = '\0';
8831 Tcl_ListObjAppendElement(peED
.interp
, objNewsgroups
, Tcl_NewStringObj(buf
,-1));
8838 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "news", field_name
, objNewsgroups
);
8843 peMessageAttachments(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8848 Tcl_Obj
*objAtt
, *tObj
, *stObj
, *fnObj
;
8849 int flags
, rv
= TCL_OK
;
8852 peED
.interp
= interp
;
8853 peED
.obj
= Tcl_GetObjResult(interp
);
8855 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_HTML
| FM_NOHTMLREL
| FM_HTMLRELATED
| FM_HIDESERVER
;
8857 raw
= peSequenceNumber(uid
);
8859 if(peED
.uid
!= uid
){
8860 memset(&peED
, 0, sizeof(peED
));
8864 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
8865 if(!((peED
.env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, &peED
.body
))
8866 && (mc
= mail_elt(wps_global
->mail_stream
, raw
)))){
8869 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
8870 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate");
8872 dprint((1, "ERROR fetching %s of msg %ld: %s",
8873 peED
.env
? "elt" : "env", mn_get_cur(sp_msgmap(wps_global
->mail_stream
)),
8874 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate"));
8876 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8880 zero_atmts(wps_global
->atmts
);
8882 if(wps_global
&& wps_global
->smime
&& wps_global
->smime
->need_passphrase
)
8883 wps_global
->smime
->need_passphrase
= 0;
8885 fiddle_smime_message(peED
.body
, raw
);
8887 describe_mime(peED
.body
, "", 1, 1, 0, flags
);
8891 /* package up attachment list */
8892 for(a
= wps_global
->atmts
; rv
== TCL_OK
&& a
->description
!= NULL
; a
++)
8893 if((objAtt
= Tcl_NewListObj(0, NULL
)) != NULL
8894 && (body
= mail_body(wps_global
->mail_stream
, raw
, (unsigned char *) a
->number
)) != NULL
){
8895 peGetMimeTyping(body
, &tObj
, &stObj
, &fnObj
, NULL
);
8897 if(!(peAppListF(interp
, objAtt
, "%s", a
->number
? a
->number
: "") == TCL_OK
8898 && peAppListF(interp
, objAtt
, "%s", a
->shown
? "shown" : "") == TCL_OK
8899 && Tcl_ListObjAppendElement(interp
, objAtt
, tObj
) == TCL_OK
8900 && Tcl_ListObjAppendElement(interp
, objAtt
, stObj
) == TCL_OK
8901 && Tcl_ListObjAppendElement(interp
, objAtt
, fnObj
) == TCL_OK
8902 && peAppListF(interp
, objAtt
, "%s", a
->body
->description
) == TCL_OK
8903 && Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAtt
) == TCL_OK
))
8914 peMessageBody(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8917 int flags
, rv
= TCL_OK
;
8921 peED
.interp
= interp
;
8922 peED
.obj
= Tcl_GetObjResult(interp
);
8925 so_seek(peED
.store
, 0L, 0);
8927 peED
.store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
8929 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_NOHTMLREL
| FM_HTMLRELATED
;
8931 if(objc
== 1 && objv
[0]){ /* flags */
8936 Tcl_ListObjGetElements(interp
, objv
[0], &nFlags
, &objFlags
);
8937 for(i
= 0; i
< nFlags
; i
++){
8938 if((flagstr
= Tcl_GetStringFromObj(objFlags
[i
], NULL
)) == NULL
){
8942 if(!strucmp(flagstr
, "html"))
8943 flags
|= (FM_HTML
| FM_HIDESERVER
);
8944 else if(!strucmp(flagstr
, "images"))
8945 flags
|= (FM_HTMLIMAGES
);
8949 peED
.color
.fg
[0] = '\0';
8950 if((color
= pico_get_last_fg_color()) && (color
= color_to_asciirgb(color
))){
8951 peInterpWritec(TAG_EMBED
);
8952 peInterpWritec(TAG_FGCOLOR
);
8953 gf_puts(color
, peInterpWritec
);
8954 strcpy(peED
.color
.fgdef
, peColorStr(color
, wtmp_20k_buf
));
8957 peED
.color
.bg
[0] = '\0';
8958 if((color
= pico_get_last_bg_color()) && (color
= color_to_asciirgb(color
))){
8959 peInterpWritec(TAG_EMBED
);
8960 peInterpWritec(TAG_BGCOLOR
);
8961 gf_puts(color
, peInterpWritec
);
8962 strcpy(peED
.color
.bgdef
, peColorStr(color
,wtmp_20k_buf
));
8967 init_handles(&peED
.handles
);
8969 raw
= peSequenceNumber(uid
);
8971 if(peED
.uid
!= uid
){
8975 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
8976 if(!((peED
.env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, &peED
.body
))
8977 && (mc
= mail_elt(wps_global
->mail_stream
, raw
)))){
8980 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
8981 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate");
8983 dprint((1, "ERROR fetching %s of msg %ld: %s",
8984 peED
.env
? "elt" : "env", mn_get_cur(sp_msgmap(wps_global
->mail_stream
)),
8985 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate"));
8987 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8991 zero_atmts(wps_global
->atmts
);
8993 if(wps_global
&& wps_global
->smime
&& wps_global
->smime
->need_passphrase
)
8994 wps_global
->smime
->need_passphrase
= 0;
8996 fiddle_smime_message(peED
.body
, raw
);
8998 describe_mime(peED
.body
, "", 1, 1, 0, flags
);
9002 /* format message body */
9007 HD_INIT(&h
, wps_global
->VAR_VIEW_HEADERS
, wps_global
->view_all_except
, FE_DEFAULT
);
9009 /* kind of a hack, the description maybe shouldn't be in the editorial stuff */
9010 if(wps_global
->smime
&& wps_global
->smime
->need_passphrase
)
9011 flags
&= ~FM_NOEDITORIAL
;
9013 if((errstr
= format_body(raw
, peED
.body
, &peED
.handles
, &h
, flags
, FAKE_SCREEN_WIDTH
, peInterpWritec
)) != NULL
){
9014 gf_puts(errstr
, peInterpWritec
);
9021 so_give(&peED
.store
);
9022 free_handles(&peED
.handles
);
9028 peMessageText(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9037 memset(&peED
, 0, sizeof(peED
));
9038 peED
.interp
= interp
;
9039 peED
.obj
= Tcl_GetObjResult(interp
);
9040 peED
.store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
9042 peED
.color
.fg
[0] = '\0';
9043 if((color
= pico_get_last_fg_color()) && (color
= color_to_asciirgb(color
))){
9044 peInterpWritec(TAG_EMBED
);
9045 peInterpWritec(TAG_FGCOLOR
);
9046 gf_puts(color
, peInterpWritec
);
9047 strcpy(peED
.color
.fgdef
, peColorStr(color
, wtmp_20k_buf
));
9050 peED
.color
.bg
[0] = '\0';
9051 if((color
= pico_get_last_bg_color()) && (color
= color_to_asciirgb(color
))){
9052 peInterpWritec(TAG_EMBED
);
9053 peInterpWritec(TAG_BGCOLOR
);
9054 gf_puts(color
, peInterpWritec
);
9055 strcpy(peED
.color
.bgdef
, peColorStr(color
,wtmp_20k_buf
));
9058 raw
= peSequenceNumber(peED
.uid
= uid
);
9060 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
9061 if(!((env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, &body
))
9062 && (mc
= mail_elt(wps_global
->mail_stream
, raw
)))){
9065 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
9066 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate");
9068 dprint((1, "ERROR fetching %s of msg %ld: %s",
9069 env
? "elt" : "env", mn_get_cur(sp_msgmap(wps_global
->mail_stream
)),
9070 wps_global
->last_error
[0] ? wps_global
->last_error
: "Indeterminate"));
9072 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
9076 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_NOHTMLREL
| FM_HTMLRELATED
;
9078 init_handles(&peED
.handles
);
9080 (void) format_message(raw
, env
, body
, &peED
.handles
, flags
, peInterpWritec
);
9084 so_give(&peED
.store
);
9085 free_handles(&peED
.handles
);
9091 * peMessagePartFromCID - return part number assoc'd with given uid and CID
9094 peMessagePartFromCID(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9096 char *cid
, sect_buf
[256];
9101 raw
= peSequenceNumber(peED
.uid
= uid
);
9102 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
9104 if(objv
[0] && (cid
= Tcl_GetStringFromObj(objv
[0], NULL
)) && *cid
!= '\0'){
9105 if((env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, &body
)) != NULL
){
9107 if(peLocateBodyByCID(cid
, sect_buf
, body
)){
9108 Tcl_SetResult(interp
, sect_buf
, TCL_VOLATILE
);
9112 Tcl_SetResult(interp
, wps_global
->last_error
[0] ? wps_global
->last_error
: "Error getting CID", TCL_VOLATILE
);
9122 peLocateBodyByCID(char *cid
, char *section
, BODY
*body
)
9124 if(body
->type
== TYPEMULTIPART
){
9125 char subsection
[256], *subp
;
9127 PART
*part
= body
->nested
.part
;
9129 if(!(part
= body
->nested
.part
))
9133 if(section
&& *section
){
9135 n
< sizeof(subsection
)-20 && (*subp
= section
[n
]); n
++, subp
++)
9143 sprintf(subp
, "%d", n
++);
9144 if(peLocateBodyByCID(cid
, subsection
, &part
->body
)){
9145 strcpy(section
, subsection
);
9149 while((part
= part
->next
) != NULL
);
9154 return((body
&& body
->id
) ? !strcmp(cid
, body
->id
) : 0);
9159 * peGetFlag - Return 1 or 0 based on requested flags current state
9161 * Params: argv[0] == flagname
9164 peGetFlag(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9168 Tcl_SetResult(interp
,
9169 int2string(((flagname
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
)
9170 ? peIsFlagged(wps_global
->mail_stream
, uid
, flagname
)
9178 peIsFlagged(MAILSTREAM
*stream
, imapuid_t uid
, char *flagname
)
9181 long raw
= peSequenceNumber(uid
);
9183 if(!((mc
= mail_elt(stream
, raw
)) && mc
->valid
)){
9184 mail_fetch_flags(stream
, ulong2string(uid
), FT_UID
);
9185 mc
= mail_elt(stream
, raw
);
9188 if(!strucmp(flagname
, "deleted"))
9189 return(mc
->deleted
);
9191 if(!strucmp(flagname
, "new"))
9194 if(!strucmp(flagname
, "important"))
9195 return(mc
->flagged
);
9197 if(!strucmp(flagname
, "answered"))
9198 return(mc
->answered
);
9200 if(!strucmp(flagname
, "recent"))
9208 * peSetFlag - Set requested flags value to 1 or 0
9210 * Params: abjv[0] == flagname
9211 * objv[1] == newvalue
9214 peSetFlag(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9216 char *flagname
, *flagstr
= NULL
;
9219 if((flagname
= Tcl_GetStringFromObj(objv
[0], NULL
))
9220 && Tcl_GetIntFromObj(interp
, objv
[1], &value
) != TCL_ERROR
){
9221 if(!strucmp(flagname
, "deleted")){
9222 flagstr
= "\\DELETED";
9224 else if(!strucmp(flagname
, "new")){
9228 else if(!strucmp(flagname
, "important")){
9229 flagstr
= "\\FLAGGED";
9231 else if(!strucmp(flagname
, "answered")){
9232 flagstr
= "\\ANSWERED";
9234 else if(!strucmp(flagname
, "recent")){
9235 flagstr
= "\\RECENT";
9239 wps_global
->c_client_error
[0] = '\0';
9240 mail_flag(wps_global
->mail_stream
,
9242 flagstr
, (value
? ST_SET
: 0L) | ST_UID
);
9243 if(wps_global
->c_client_error
[0] != '\0'){
9244 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "peSetFlag: %.40s",
9245 wps_global
->c_client_error
);
9246 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
9252 Tcl_SetResult(interp
, value
? "1" : "0", TCL_STATIC
);
9258 * peMsgSelect - Return 1 or 0 based on whether given UID is selected
9260 * Params: argv[0] == selected
9263 peMsgSelect(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9267 if(objc
== 1 && objv
[0]){
9268 if(Tcl_GetIntFromObj(interp
, objv
[0], &value
) != TCL_ERROR
){
9270 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
),
9271 peMessageNumber(uid
), MN_SLCT
, 1);
9272 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
),
9273 peMessageNumber(uid
), MN_HIDE
, 0);
9275 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
),
9276 peMessageNumber(uid
), MN_SLCT
, 0);
9277 /* if zoomed, lite hidden bit */
9278 if(any_lflagged(sp_msgmap(wps_global
->mail_stream
), MN_HIDE
))
9279 set_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
),
9280 peMessageNumber(uid
), MN_HIDE
, 1);
9285 Tcl_SetResult(interp
, "peMsgSelect: can't get value", TCL_STATIC
);
9290 Tcl_SetResult(interp
,
9291 (get_lflag(wps_global
->mail_stream
, NULL
,
9292 peSequenceNumber(uid
),
9301 * peAppendIndexParts - append list of digested index pieces to given object
9307 peAppendIndexParts(Tcl_Interp
*interp
, imapuid_t uid
, Tcl_Obj
*aObj
, int *fetched
)
9309 Tcl_Obj
*objField
, *objElement
, *objp
;
9315 if((h
= build_header_work(wps_global
, wps_global
->mail_stream
,
9316 sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
),
9317 gPeITop
, gPeICount
, fetched
)) != NULL
){
9318 for(f
= h
->ifield
; f
; f
= f
->next
){
9320 if((objField
= Tcl_NewListObj(0, NULL
)) == NULL
)
9323 for(ie
= f
->ielem
; ie
; ie
= ie
->next
){
9325 if((objElement
= Tcl_NewListObj(0, NULL
)) == NULL
)
9330 #if INTERNAL_INDEX_TRUNCATE
9333 ep
= (char *) fs_get((ie
->datalen
+ 1) * sizeof(char));
9334 sprintf(ep
, "%.*s", ie
->wid
, ie
->data
);
9336 /* and other stuff to pack trunc'd element into a new object */
9339 objp
= Tcl_NewStringObj(ie
->data
, ie
->datalen
);
9342 objp
= Tcl_NewStringObj("", -1);
9344 if(Tcl_ListObjAppendElement(interp
, objElement
, objp
) != TCL_OK
)
9351 if((objp
= Tcl_NewListObj(0, NULL
)) == NULL
)
9354 hex_colorstr(hexcolor
, ie
->color
->fg
);
9355 objColor
= Tcl_NewStringObj(hexcolor
, -1);
9356 if(Tcl_ListObjAppendElement(interp
, objp
, objColor
) != TCL_OK
)
9359 hex_colorstr(hexcolor
, ie
->color
->bg
);
9360 objColor
= Tcl_NewStringObj(hexcolor
, -1);
9361 if(Tcl_ListObjAppendElement(interp
, objp
, objColor
) != TCL_OK
)
9365 objp
= Tcl_NewStringObj("", -1);
9367 if(Tcl_ListObjAppendElement(interp
, objElement
, objp
) != TCL_OK
)
9371 * IF we ever want to map the thread characters into nice
9372 * graphical symbols or take advantage of features like clicking
9373 * on a thread element to collapse and such, we need to have
9374 * element tagging. That's what the object creation and append
9375 * are placeholders for
9379 objp
= Tcl_NewStringObj("threadinfo", -1);
9385 objp
= Tcl_NewStringObj(int2string(ie
->type
), -1);
9389 if(objp
&& Tcl_ListObjAppendElement(interp
, objElement
, objp
) != TCL_OK
)
9392 if(Tcl_ListObjAppendElement(interp
, objField
, objElement
) != TCL_OK
)
9396 if(Tcl_ListObjAppendElement(interp
, aObj
, objField
) != TCL_OK
){
9407 * peAppendIndexColor - append index line's foreground/background color
9413 peAppendIndexColor(Tcl_Interp
*interp
, imapuid_t uid
, Tcl_Obj
*aObj
, int *fetched
)
9415 char hexfg
[32], hexbg
[32];
9418 if((h
= build_header_work(wps_global
, wps_global
->mail_stream
,
9419 sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
),
9420 gPeITop
, gPeICount
, fetched
))
9421 && h
->color_lookup_done
9424 hex_colorstr(hexfg
, h
->linecolor
->fg
);
9425 hex_colorstr(hexbg
, h
->linecolor
->bg
);
9427 return(peAppListF(interp
, aObj
, "%s%s", hexfg
, hexbg
));
9430 return(peAppListF(interp
, aObj
, "%s", ""));
9435 * peMessageStatusBits - return list flags indicating pine status bits
9439 * Returns: list of lists where:
9440 * * the first element is the list of
9441 * field elements data
9442 * * the second element is a two element
9443 * list containing the lines foreground
9444 * and background colors
9447 peMessageStatusBits(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9449 Tcl_SetResult(interp
,
9450 peMsgStatBitString(wps_global
, wps_global
->mail_stream
,
9451 sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
),
9452 gPeITop
, gPeICount
, NULL
),
9459 peMsgStatBitString(struct pine
*state
,
9467 static char buf
[36];
9473 raw
= mn_m2raw(msgmap
, msgno
);
9474 if((h
= build_header_work(state
, stream
, msgmap
,
9475 msgno
, top_msgno
, msgcount
, fetched
))
9476 && (mc
= mail_elt(stream
, raw
))){
9477 /* return a string representing a bit field where:
9491 buf
[i
++] = (mc
->seen
) ? '0' : '1';
9492 buf
[i
++] = (mc
->deleted
) ? '1' : '0';
9493 buf
[i
++] = (mc
->answered
) ? '1' : '0';
9494 buf
[i
++] = (mc
->flagged
) ? '1' : '0';
9495 buf
[i
++] = (h
->to_us
) ? '1' : '0';
9496 buf
[i
++] = (h
->cc_us
) ? '1' : '0';
9497 buf
[i
++] = (mc
->recent
) ? '1' : '0';
9498 buf
[i
++] = (user_flag_is_set(stream
, raw
, FORWARDED_FLAG
)) ? '1' : '0';
9505 return("100000000");
9510 peMsgStatNameList(Tcl_Interp
*interp
,
9524 objList
= Tcl_NewListObj(0, NULL
);
9525 raw
= mn_m2raw(msgmap
, msgno
);
9526 if((h
= build_header_work(state
, stream
, msgmap
,
9527 msgno
, top_msgno
, msgcount
, fetched
))
9528 && (mc
= mail_elt(stream
, raw
))){
9530 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("new", -1));
9533 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("deleted", -1));
9536 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("answered", -1));
9539 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("flagged", -1));
9542 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("to_us", -1));
9545 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("cc_us", -1));
9548 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("recent", -1));
9550 if(user_flag_is_set(stream
, raw
, FORWARDED_FLAG
))
9551 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("forwarded", -1));
9553 if(get_lflag(wps_global
->mail_stream
, sp_msgmap(wps_global
->mail_stream
), msgno
, MN_SLCT
))
9554 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("selected", -1));
9562 * peReplyHeaders - return subject used in reply to given message
9566 * Returns: list of header value pairs where headers are:
9567 * In-Reply-To:, Subject:, Cc:
9571 peReplyHeaders(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9574 int flags
= RSF_FORCE_REPLY_TO
| RSF_FORCE_REPLY_ALL
, err
= FALSE
;
9575 char *errmsg
= NULL
, *fcc
= NULL
, *sect
= NULL
;
9576 ENVELOPE
*env
, *outgoing
;
9578 ADDRESS
*saved_from
, *saved_to
, *saved_cc
, *saved_resent
;
9580 saved_from
= (ADDRESS
*) NULL
;
9581 saved_to
= (ADDRESS
*) NULL
;
9582 saved_cc
= (ADDRESS
*) NULL
;
9583 saved_resent
= (ADDRESS
*) NULL
;
9585 raw
= peSequenceNumber(uid
);
9587 /* if we're given a valid section number that
9588 * corresponds to a valid msg/rfc822 body part
9589 * then set up headers in attached message.
9591 if(objc
== 1 && objv
[0]
9592 && (sect
= Tcl_GetStringFromObj(objv
[0], NULL
)) && *sect
!= '\0'
9593 && (body
= mail_body(wps_global
->mail_stream
, raw
, (unsigned char *) sect
))
9594 && body
->type
== TYPEMESSAGE
9595 && !strucmp(body
->subtype
, "rfc822")){
9596 env
= body
->nested
.msg
->env
;
9600 env
= mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
);
9604 if(!reply_harvest(wps_global
, raw
, sect
, env
,
9605 &saved_from
, &saved_to
, &saved_cc
,
9606 &saved_resent
, &flags
)){
9608 Tcl_SetResult(interp
, "", TCL_STATIC
);
9612 outgoing
= mail_newenvelope();
9614 reply_seed(wps_global
, outgoing
, env
,
9615 saved_from
, saved_to
, saved_cc
, saved_resent
,
9616 &fcc
, flags
, &errmsg
);
9619 q_status_message1(SM_ORDER
, 3, 3, "%.200s", errmsg
);
9622 fs_give((void **)&errmsg
);
9625 env
= pine_mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
);
9627 outgoing
->subject
= reply_subject(env
->subject
, NULL
, 0);
9628 outgoing
->in_reply_to
= reply_in_reply_to(env
);
9630 err
= !(peAppListF(interp
, Tcl_GetObjResult(interp
),
9631 "%s%a", "to", outgoing
->to
) == TCL_OK
9632 && peAppListF(interp
, Tcl_GetObjResult(interp
),
9633 "%s%a", "cc", outgoing
->cc
) == TCL_OK
9634 && peAppListF(interp
, Tcl_GetObjResult(interp
),
9635 "%s%s", "in-reply-to", outgoing
->in_reply_to
) == TCL_OK
9636 && peAppListF(interp
, Tcl_GetObjResult(interp
),
9638 rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
,
9639 SIZEOF_20KBUF
, outgoing
->subject
)) == TCL_OK
9640 && (fcc
? peFccAppend(interp
, Tcl_GetObjResult(interp
), fcc
, -1) : TRUE
));
9643 /* Fill in x-reply-uid data and append it */
9644 if(!err
&& wps_global
->mail_stream
->uid_validity
){
9645 char *prefix
= reply_quote_str(env
);
9647 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "(%lu %s)(1 %lu %lu)%s",
9648 strlen(prefix
), prefix
,
9649 wps_global
->mail_stream
->uid_validity
, uid
,
9650 wps_global
->mail_stream
->mailbox
);
9652 fs_give((void **) &prefix
);
9654 err
= peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s",
9655 "x-reply-uid", wtmp_20k_buf
) != TCL_OK
;
9658 mail_free_envelope(&outgoing
);
9664 Tcl_SetResult(interp
, "", TCL_VOLATILE
);
9672 * peReplyText - return subject used in reply to given message
9680 peReplyText(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9683 char *prefix
, *sect
= NULL
;
9686 BODY
*body
= NULL
, *orig_body
;
9688 REDRAFT_POS_S
*redraft_pos
= NULL
;
9689 Tcl_Obj
*objBody
= NULL
, *objAttach
= NULL
;
9691 msgno
= peSequenceNumber(uid
);
9693 if((msgtext
= (void *) so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
9694 Tcl_SetResult(interp
, "Unable to create storage for reply text", TCL_VOLATILE
);
9698 /*--- Grab current envelope ---*/
9699 /* if we're given a valid section number that
9700 * corresponds to a valid msg/rfc822 body part
9701 * then set up to reply the attached message's
9704 if(objc
== 2 && objv
[1]
9705 && (sect
= Tcl_GetStringFromObj(objv
[1], NULL
)) && *sect
!= '\0'
9706 && (body
= mail_body(wps_global
->mail_stream
, msgno
, (unsigned char *) sect
))
9707 && body
->type
== TYPEMESSAGE
9708 && !strucmp(body
->subtype
, "rfc822")){
9709 env
= body
->nested
.msg
->env
;
9710 orig_body
= body
->nested
.msg
->body
;
9714 env
= mail_fetchstructure(wps_global
->mail_stream
, msgno
, &orig_body
);
9715 if(!(env
&& orig_body
)){
9716 Tcl_SetResult(interp
, "Unable to fetch message parts", TCL_VOLATILE
);
9721 if((prefix
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
)
9722 prefix
= cpystr(prefix
);
9724 prefix
= reply_quote_str(env
);
9727 * BUG? Should there be some way to signal to reply_bddy
9728 * that we'd like it to produced format=flowed body text?
9729 * right now it's hardwired to in pine/reply.c
9732 if((body
= reply_body(wps_global
->mail_stream
, env
, orig_body
,
9733 msgno
, sect
, msgtext
, prefix
,
9734 TRUE
, NULL
, TRUE
, &redraft_pos
)) != NULL
){
9736 objBody
= Tcl_NewListObj(0, NULL
);
9738 peSoStrToList(interp
, objBody
, msgtext
);
9740 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objBody
);
9742 /* sniff for attachments */
9743 objAttach
= peMsgAttachCollector(interp
, body
);
9745 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
9748 pine_free_body(&body
);
9751 Tcl_SetResult(interp
, "Can't create body text", TCL_VOLATILE
);
9755 fs_give((void **) &prefix
);
9762 peSoStrToList(Tcl_Interp
*interp
, Tcl_Obj
*obj
, STORE_S
*so
)
9767 for(ep
= (char *) so_text(so
); *ep
; ep
++){
9770 while(*ep
&& *ep
!= '\n')
9773 objp
= Tcl_NewStringObj(sp
, ep
- sp
);
9775 if(Tcl_ListObjAppendElement(interp
, obj
, objp
) != TCL_OK
)
9784 * peForwardHeaders - return subject used in forward of given message
9792 peForwardHeaders(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9797 char *tmp
, *sect
= NULL
;
9801 raw
= peSequenceNumber(uid
);
9803 /* if we're given a valid section number that
9804 * corresponds to a valid msg/rfc822 body part
9805 * then set up headers in attached message.
9807 if(objc
== 1 && objv
[0]
9808 && (sect
= Tcl_GetStringFromObj(objv
[0], NULL
)) && *sect
!= '\0'
9809 && (body
= mail_body(wps_global
->mail_stream
, raw
, (unsigned char *) sect
))
9810 && body
->type
== TYPEMESSAGE
9811 && !strucmp(body
->subtype
, "rfc822")){
9812 env
= body
->nested
.msg
->env
;
9816 env
= mail_fetchstructure(wps_global
->mail_stream
, raw
, NULL
);
9820 tmp
= forward_subject(env
, FS_NONE
);
9821 result
= peAppListF(interp
, Tcl_GetObjResult(interp
),
9822 "%s%s", "subject", tmp
);
9823 fs_give((void **) &tmp
);
9825 /* Fill in x-reply-uid data and append it */
9826 if(result
== TCL_OK
&& wps_global
->mail_stream
->uid_validity
){
9827 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "()(1 %lu %lu)%s",
9828 wps_global
->mail_stream
->uid_validity
, uid
,
9829 wps_global
->mail_stream
->mailbox
);
9830 result
= peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s",
9831 "x-reply-uid", wtmp_20k_buf
) != TCL_OK
;
9837 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
9844 * peForwardText - return body of message used in
9845 * forward of given message
9853 peForwardText(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9856 char *bodtext
, *p
, *sect
= NULL
;
9859 BODY
*body
, *orig_body
;
9861 Tcl_Obj
*objBody
= NULL
, *objAttach
= NULL
;
9863 msgno
= peSequenceNumber(uid
);
9865 if(objc
== 1 && objv
[0])
9866 sect
= Tcl_GetStringFromObj(objv
[0], NULL
);
9868 if((msgtext
= (void *) so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
9869 Tcl_SetResult(interp
, "Unable to create storage for forward text", TCL_VOLATILE
);
9874 if(F_ON(F_FORWARD_AS_ATTACHMENT
, wps_global
)){
9876 long totalsize
= 0L;
9878 /*---- New Body to start with ----*/
9879 body
= mail_newbody();
9880 body
->type
= TYPEMULTIPART
;
9882 /*---- The TEXT part/body ----*/
9883 body
->nested
.part
= mail_newbody_part();
9884 body
->nested
.part
->body
.type
= TYPETEXT
;
9885 body
->nested
.part
->body
.contents
.text
.data
= (unsigned char *) msgtext
;
9887 pp
= &(body
->nested
.part
->next
);
9889 /*---- The Message body subparts ----*/
9890 env
= pine_mail_fetchstructure(wps_global
->mail_stream
, msgno
, NULL
);
9892 if(forward_mime_msg(wps_global
->mail_stream
, msgno
,
9893 (sect
&& *sect
!= '\0') ? sect
: NULL
, env
, pp
, msgtext
)){
9894 totalsize
= (*pp
)->body
.size
.bytes
;
9895 pp
= &((*pp
)->next
);
9899 /*--- Grab current envelope ---*/
9900 /* if we're given a valid section number that
9901 * corresponds to a valid msg/rfc822 body part
9902 * then set up to forward the attached message's
9906 if(sect
&& *sect
!= '\0'
9907 && (body
= mail_body(wps_global
->mail_stream
, msgno
, (unsigned char *) sect
))
9908 && body
->type
== TYPEMESSAGE
9909 && !strucmp(body
->subtype
, "rfc822")){
9910 env
= body
->nested
.msg
->env
;
9911 orig_body
= body
->nested
.msg
->body
;
9915 env
= mail_fetchstructure(wps_global
->mail_stream
, msgno
, &orig_body
);
9916 if(!(env
&& orig_body
)){
9917 Tcl_SetResult(interp
, "Unable to fetch message parts", TCL_VOLATILE
);
9922 body
= forward_body(wps_global
->mail_stream
, env
, orig_body
,
9923 msgno
, sect
, msgtext
, FWD_NONE
);
9927 bodtext
= (char *) so_text(msgtext
);
9929 objBody
= Tcl_NewListObj(0, NULL
);
9931 for(p
= bodtext
; *p
; p
++){
9935 while(*p
&& *p
!= '\n')
9938 objp
= Tcl_NewStringObj(bodtext
, p
- bodtext
);
9940 Tcl_ListObjAppendElement(interp
, objBody
, objp
);
9943 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objBody
);
9945 /* sniff for attachments */
9946 objAttach
= peMsgAttachCollector(interp
, body
);
9947 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
9949 pine_free_body(&body
);
9952 Tcl_SetResult(interp
, "Can't create body text", TCL_VOLATILE
);
9964 * Params: argv[0] == attachment part number
9965 * argv[1] == directory to hold tmp file
9967 * Returns: list containing:
9969 * 0) response: OK or ERROR
9971 * 1) attachment's mime type
9972 * 2) attachment's mime sub-type
9973 * 3) attachment's size in bytes (decoded)
9974 * 4) attachment's given file name (if any)
9975 * 5) tmp file holding raw attachment data
9978 peDetach(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9980 char *part
, *err
, *tfd
, *tfn
= NULL
, *filename
;
9985 Tcl_Obj
*rvobj
, *tObj
, *stObj
, *fnObj
;
9987 if((part
= Tcl_GetStringFromObj(objv
[0], NULL
))
9988 && (raw
= peSequenceNumber(uid
))
9989 && (body
= mail_body(wps_global
->mail_stream
, raw
, (unsigned char *) part
))){
9991 peGetMimeTyping(body
, &tObj
, &stObj
, &fnObj
, NULL
);
9994 if(!(tfd
= Tcl_GetStringFromObj(objv
[1], NULL
)) || *tfd
== '\0'){
9995 tfn
= temp_nam(tfd
= NULL
, "pd");
9997 else if(is_writable_dir(tfd
) == 0){
9998 tfn
= temp_nam(tfd
, "pd");
10003 filename
= Tcl_GetStringFromObj(fnObj
, NULL
);
10004 dprint((5, "PEDetach(name: %s, tmpfile: %s)",
10005 filename
? filename
: "<null>", tfn
));
10007 if((store
= so_get(FileStar
, tfn
, WRITE_ACCESS
|OWNER_ONLY
)) != NULL
){
10008 gf_set_so_writec(&pc
, store
);
10009 err
= detach(wps_global
->mail_stream
, raw
, part
, 0L, NULL
, pc
, NULL
, 0);
10010 gf_clear_so_writec(store
);
10014 err
= "Can't allocate internal storage";
10017 err
= "Can't get message data";
10023 dprint((1, "PEDetach FAIL: %d: %s", errno
, err
));
10024 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Detach (%d): %s", errno
, err
);
10025 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
10029 /* package up response */
10030 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10031 Tcl_NewListObj(1, &tObj
));
10033 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10034 Tcl_NewListObj(1, &stObj
));
10036 rvobj
= Tcl_NewLongObj(name_file_size(tfn
));
10037 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10038 Tcl_NewListObj(1, &rvobj
));
10039 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10040 Tcl_NewListObj(1, &fnObj
));
10041 rvobj
= Tcl_NewStringObj(tfn
, -1);
10042 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10043 Tcl_NewListObj(1, &rvobj
));
10052 * Params: argv[0] == attachment part number
10054 * Returns: list containing:
10056 * 0) response: OK or ERROR
10058 * 1) attachment's mime type
10059 * 2) attachment's mime sub-type
10060 * 3) attachment's size in bytes (decoded)
10061 * 4) attachment's given file name (if any)
10062 * 5) tmp file holding raw attachment data
10065 peAttachInfo(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10071 Tcl_Obj
*tObj
, *stObj
, *fnObj
;
10073 if((part
= Tcl_GetStringFromObj(objv
[0], NULL
))
10074 && (raw
= peSequenceNumber(uid
))
10075 && (body
= mail_body(wps_global
->mail_stream
, raw
, (unsigned char *) part
))){
10077 peGetMimeTyping(body
, &tObj
, &stObj
, &fnObj
, NULL
);
10080 Tcl_SetResult(interp
, "Can't get message data", TCL_STATIC
);
10084 /* package up response */
10087 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), fnObj
);
10090 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
10093 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), stObj
);
10096 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10097 Tcl_NewStringObj((body
->encoding
< ENCMAX
)
10098 ? body_encodings
[body
->encoding
]
10102 if((plist
= rfc2231_newparmlist(body
->parameter
)) != NULL
){
10103 Tcl_Obj
*lObj
= Tcl_NewListObj(0, NULL
);
10106 while(rfc2231_list_params(plist
)){
10107 pObj
[0] = Tcl_NewStringObj(plist
->attrib
, -1);
10108 pObj
[1] = Tcl_NewStringObj(plist
->value
, -1);
10109 Tcl_ListObjAppendElement(interp
, lObj
,
10110 Tcl_NewListObj(2, pObj
));
10113 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), lObj
);
10114 rfc2231_free_parmlist(&plist
);
10117 /* size guesstimate */
10118 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10119 Tcl_NewStringObj(comatose((body
->encoding
== ENCBASE64
)
10120 ? ((body
->size
.bytes
* 3)/4)
10121 : body
->size
.bytes
), -1));
10128 * peSaveDefault - Default saved file name for the given message
10129 * specified collection/folder
10133 * Returns: name of saved message folder or empty string
10137 peSaveDefault(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10140 CONTEXT_S
*cntxt
, *cp
;
10146 if(!(env
= pine_mail_fetchstructure(wps_global
->mail_stream
,
10147 rawno
= peSequenceNumber(uid
),
10149 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
10156 if(!(folder
= save_get_default(wps_global
, env
, rawno
, NULL
, &cntxt
))){
10157 Tcl_SetResult(interp
, "Message expunged!", TCL_VOLATILE
);
10158 return(TCL_ERROR
); /* message expunged! */
10161 for(colid
= 0, cp
= wps_global
->context_list
; cp
&& cp
!= cntxt
; colid
++, cp
= cp
->next
)
10167 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10168 Tcl_NewIntObj(colid
));
10169 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10170 Tcl_NewStringObj(folder
, -1));
10176 * peSaveWork - Save message with given UID in current folder to
10177 * specified collection/folder
10179 * Params: argv[0] == destination context number
10180 * argv[1] == testination foldername
10185 peSaveWork(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
, long sflags
)
10187 int flgs
= 0, i
, colid
;
10188 char *folder
, *err
= NULL
;
10191 if(Tcl_GetIntFromObj(interp
, objv
[0], &colid
) != TCL_ERROR
){
10192 if((folder
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
10193 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
));
10194 for(i
= 0, cp
= wps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
10199 if(!READONLY_FOLDER(wps_global
->mail_stream
)
10200 && (sflags
& PSW_COPY
) != PSW_COPY
10201 && ((sflags
& PSW_MOVE
) == PSW_MOVE
|| F_OFF(F_SAVE_WONT_DELETE
, wps_global
)))
10204 if(colid
== 0 && !strucmp(folder
, "inbox"))
10205 flgs
|= SV_INBOXWOCNTXT
;
10207 if(sflags
& (PSW_COPY
| PSW_MOVE
))
10208 flgs
|= SV_FIX_DELS
;
10210 i
= save(wps_global
, wps_global
->mail_stream
,
10211 cp
, folder
, sp_msgmap(wps_global
->mail_stream
), flgs
);
10213 if(i
== mn_total_cur(sp_msgmap(wps_global
->mail_stream
))){
10214 if(mn_total_cur(sp_msgmap(wps_global
->mail_stream
)) <= 1L){
10215 if(wps_global
->context_list
->next
10216 && context_isambig(folder
)){
10217 char *tag
= (cp
->nickname
&& strlen(cp
->nickname
)) ? cp
->nickname
: (cp
->label
&& strlen(cp
->label
)) ? cp
->label
: "Folders";
10218 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
,
10219 "Message %s %s to \"%.15s%s\" in <%.15s%s>",
10220 long2string(mn_get_cur(sp_msgmap(wps_global
->mail_stream
))),
10221 (sflags
& PSW_MOVE
) ? "moved" : "copied",
10223 (strlen(folder
) > 15) ? "..." : "",
10225 (strlen(tag
) > 15) ? "..." : "");
10228 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
,
10229 "Message %s %s to folder \"%.27s%s\"",
10230 long2string(mn_get_cur(sp_msgmap(wps_global
->mail_stream
))),
10231 (sflags
& PSW_MOVE
) ? "moved" : "copied",
10233 (strlen(folder
) > 27) ? "..." : "");
10236 /* with mn_set_cur above, this *should not* happen */
10237 Tcl_SetResult(interp
, "TOO MANY MESSAGES COPIED", TCL_VOLATILE
);
10241 if(sflags
== PSW_NONE
&& (flgs
& SV_DELETE
)){
10242 strncat(wtmp_20k_buf
, " and deleted", SIZEOF_20KBUF
-strlen(wtmp_20k_buf
)-1);
10243 wtmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
10246 q_status_message(SM_ORDER
, 0, 3, wtmp_20k_buf
);
10250 err
= wps_global
->last_error
;
10253 err
= "open: Unrecognized collection ID";
10256 err
= "open: Can't read folder";
10259 err
= "open: Can't get collection ID";
10261 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
10266 * peSave - Save message with given UID in current folder to
10267 * specified collection/folder
10269 * Params: argv[0] == destination context number
10270 * argv[1] == testination foldername
10272 * NOTE: just a wrapper around peSaveWork
10275 peSave(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10277 return(peSaveWork(interp
, uid
, objc
, objv
, PSW_NONE
));
10282 * peCopy - Copy message with given UID in current folder to
10283 * specified collection/folder
10285 * Params: argv[0] == destination context number
10286 * argv[1] == testination foldername
10288 * NOTE: just a wrapper around peSaveWork that makes sure
10289 * delete-on-save is NOT set
10292 peCopy(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10294 return(peSaveWork(interp
, uid
, objc
, objv
, PSW_COPY
));
10299 * peMove - Move message with given UID in current folder to
10300 * specified collection/folder
10302 * Params: argv[0] == destination context number
10303 * argv[1] == testination foldername
10305 * NOTE: just a wrapper around peSaveWork that makes sure
10306 * delete-on-save IS set so it can be expunged
10309 peMove(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10311 return(peSaveWork(interp
, uid
, objc
, objv
, PSW_MOVE
));
10316 * peGotoDefault - Default Goto command file name for the given message
10317 * specified collection/folder
10321 * Returns: name of Goto command default folder or empty string
10325 peGotoDefault(Tcl_Interp
*interp
, imapuid_t uid
, Tcl_Obj
**objv
)
10327 char *folder
= NULL
;
10328 CONTEXT_S
*cntxt
, *cp
;
10331 cntxt
= broach_get_folder(wps_global
->context_current
, &inbox
, &folder
);
10333 for(colid
= 0, cp
= wps_global
->context_list
; cp
!= cntxt
; colid
++, cp
= cp
->next
)
10339 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10340 Tcl_NewIntObj(colid
));
10341 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10342 Tcl_NewStringObj(folder
? folder
: "", -1));
10350 * Params: argv[0] == attachment part number
10352 * Returns: list containing:
10356 peReplyQuote(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10362 if((env
= pine_mail_fetchstructure(wps_global
->mail_stream
, peSequenceNumber(uid
), NULL
)) != NULL
){
10363 quote
= reply_quote_str(env
);
10364 Tcl_SetResult(interp
, quote
, TCL_VOLATILE
);
10365 fs_give((void **) "e
);
10368 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
10373 Tcl_SetResult(interp
, "> ", TCL_VOLATILE
);
10380 peGetMimeTyping(BODY
*body
, Tcl_Obj
**tObjp
, Tcl_Obj
**stObjp
, Tcl_Obj
**fnObjp
, Tcl_Obj
**extObjp
)
10382 char *ptype
= NULL
, *psubtype
= NULL
, *pfile
= NULL
;
10384 /*------- Figure out suggested file name ----*/
10386 if((pfile
= get_filename_parameter(NULL
, 0, body
, NULL
)) != NULL
){
10388 * if part is generic, see if we can get anything
10389 * more from the suggested filename's extension...
10391 if(body
->type
== TYPEAPPLICATION
10393 || !strucmp(body
->subtype
, "octet-stream"))){
10394 BODY
*fakebody
= mail_newbody();
10396 if(set_mime_type_by_extension(fakebody
, pfile
)){
10397 ptype
= body_type_names(fakebody
->type
);
10398 psubtype
= cpystr(fakebody
->subtype
);
10401 mail_free_body(&fakebody
);
10406 ptype
= body_type_names(body
->type
);
10407 psubtype
= cpystr(body
->subtype
10409 : (body
->type
== TYPETEXT
)
10411 : (body
->type
== TYPEAPPLICATION
)
10417 ptype
= body_type_names(TYPETEXT
);
10418 psubtype
= cpystr("plain");
10422 *extObjp
= Tcl_NewStringObj("", 0);
10424 if(ptype
&& psubtype
&& pfile
){
10427 char extbuf
[32]; /* mailcap.c limits to three */
10429 l
= strlen(ptype
) + strlen(psubtype
) + 1;
10430 mtype
= (char *) fs_get((l
+1) * sizeof(char));
10432 snprintf(mtype
, l
+1, "%s/%s", ptype
, psubtype
);
10434 if(!set_mime_extension_by_type(extbuf
, mtype
)){
10437 for(dotp
= NULL
, p
= pfile
; *p
; p
++)
10442 Tcl_SetStringObj(*extObjp
, dotp
, -1);
10445 Tcl_SetStringObj(*extObjp
, extbuf
, -1);
10447 fs_give((void **) &mtype
);
10452 *tObjp
= Tcl_NewStringObj(ptype
, -1);
10456 *stObjp
= Tcl_NewStringObj(psubtype
, -1);
10458 fs_give((void **) &psubtype
);
10461 *stObjp
= Tcl_NewStringObj("", 0);
10465 *fnObjp
= Tcl_NewStringObj(pfile
, -1);
10467 fs_give((void **) &pfile
);
10470 *fnObjp
= Tcl_NewStringObj("", 0);
10475 * peAppListF - generate a list of elements based on fmt string,
10476 * then append it to the given list object
10480 peAppListF(Tcl_Interp
*interp
, Tcl_Obj
*lobjp
, char *fmt
, ...)
10483 char *p
, *sval
, nbuf
[128];
10487 unsigned long luval
;
10491 Tcl_Obj
*lObj
= NULL
, *sObj
;
10493 if((lObj
= Tcl_NewListObj(0, NULL
)) != NULL
){
10494 va_start(args
, fmt
);
10495 for(p
= fmt
; *p
&& !err
; p
++){
10500 case 'i' : /* int value */
10501 ival
= va_arg(args
, int);
10502 if((sObj
= Tcl_NewIntObj(ival
)) == NULL
)
10507 case 'u' : /* unsigned int value */
10508 uval
= va_arg(args
, unsigned int);
10509 snprintf(nbuf
, sizeof(nbuf
), "%u", uval
);
10510 if((sObj
= Tcl_NewStringObj(nbuf
, -1)) == NULL
)
10515 case 'l' : /* long value */
10518 luval
= va_arg(args
, unsigned long);
10519 snprintf(nbuf
, sizeof(nbuf
), "%lu", luval
);
10520 if((sObj
= Tcl_NewStringObj(nbuf
, -1)) == NULL
)
10524 lval
= va_arg(args
, long);
10525 if((sObj
= Tcl_NewLongObj(lval
)) == NULL
)
10531 case 's' : /* string value */
10532 sval
= va_arg(args
, char *);
10533 sObj
= Tcl_NewStringObj(sval
? sval
: "", -1);
10539 case 'a': /* ADDRESS list */
10540 aval
= va_arg(args
, ADDRESS
*);
10546 len
= est_size(aval
);
10547 tmp
= (char *) fs_get(len
* sizeof(char));
10549 rbuf
.f
= dummy_soutr
;
10553 rbuf
.end
= tmp
+len
-1;
10554 rfc822_output_address_list(&rbuf
, aval
, 0L, NULL
);
10556 p
= (char *) rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
, SIZEOF_20KBUF
, tmp
);
10557 sObj
= Tcl_NewStringObj(p
, strlen(p
));
10558 fs_give((void **) &tmp
);
10561 sObj
= Tcl_NewStringObj("", -1);
10565 case 'p': /* PATTERN_S * */
10566 pval
= va_arg(args
, PATTERN_S
*);
10567 sval
= pattern_to_string(pval
);
10568 sObj
= Tcl_NewStringObj(sval
? sval
: "", -1);
10571 case 'v': /* INTVL_S * */
10572 vval
= va_arg(args
, INTVL_S
*);
10574 for(; vval
!= NULL
; vval
= vval
->next
){
10575 peAppListF(interp
, sObj
, "%l%l", vval
->imin
, vval
->imax
);
10579 sObj
= Tcl_NewListObj(0, NULL
);
10583 case 'o': /* Tcl_Obj * */
10584 sObj
= va_arg(args
, Tcl_Obj
*);
10589 Tcl_ListObjAppendElement(interp
, lObj
, sObj
);
10595 return(lObj
? Tcl_ListObjAppendElement(interp
, lobjp
, lObj
) : TCL_ERROR
);
10599 * pePatAppendID - append list of pattern identity variables to given object
10602 pePatAppendID(Tcl_Interp
*interp
, Tcl_Obj
*patObj
, PAT_S
*pat
)
10606 resObj
= Tcl_NewListObj(0, NULL
);
10607 peAppListF(interp
, resObj
, "%s%s", "nickname", pat
->patgrp
->nick
);
10608 peAppListF(interp
, resObj
, "%s%s", "comment", pat
->patgrp
->comment
);
10609 Tcl_ListObjAppendElement(interp
, patObj
, resObj
);
10614 * pePatAppendPattern - append list of pattern variables to given object
10617 pePatAppendPattern(Tcl_Interp
*interp
, Tcl_Obj
*patObj
, PAT_S
*pat
)
10622 resObj
= Tcl_NewListObj(0, NULL
);
10623 peAppListF(interp
, resObj
, "%s%p", "to", pat
->patgrp
->to
);
10624 peAppListF(interp
, resObj
, "%s%p", "from", pat
->patgrp
->from
);
10625 peAppListF(interp
, resObj
, "%s%p", "sender", pat
->patgrp
->sender
);
10626 peAppListF(interp
, resObj
, "%s%p", "cc", pat
->patgrp
->cc
);
10627 peAppListF(interp
, resObj
, "%s%p", "recip", pat
->patgrp
->recip
);
10628 peAppListF(interp
, resObj
, "%s%p", "partic", pat
->patgrp
->partic
);
10629 peAppListF(interp
, resObj
, "%s%p", "news", pat
->patgrp
->news
);
10630 peAppListF(interp
, resObj
, "%s%p", "subj", pat
->patgrp
->subj
);
10631 peAppListF(interp
, resObj
, "%s%p", "alltext", pat
->patgrp
->alltext
);
10632 peAppListF(interp
, resObj
, "%s%p", "bodytext", pat
->patgrp
->bodytext
);
10633 peAppListF(interp
, resObj
, "%s%p", "keyword", pat
->patgrp
->keyword
);
10634 peAppListF(interp
, resObj
, "%s%p", "charset", pat
->patgrp
->charsets
);
10636 peAppListF(interp
, resObj
, "%s%v", "score", pat
->patgrp
->score
);
10637 peAppListF(interp
, resObj
, "%s%v", "age", pat
->patgrp
->age
);
10638 peAppListF(interp
, resObj
, "%s%v", "size", pat
->patgrp
->size
);
10640 if((ah
= pat
->patgrp
->arbhdr
) != NULL
){
10641 Tcl_Obj
*hlObj
, *hObj
;
10643 hlObj
= Tcl_NewListObj(0, NULL
);
10644 Tcl_ListObjAppendElement(interp
, hlObj
, Tcl_NewStringObj("headers", -1));
10646 for(; ah
; ah
= ah
->next
){
10647 hObj
= Tcl_NewListObj(0, NULL
);
10648 peAppListF(interp
, hObj
, "%s%p", ah
->field
? ah
->field
: "", ah
->p
);
10649 Tcl_ListObjAppendElement(interp
, hlObj
, hObj
);
10652 Tcl_ListObjAppendElement(interp
, resObj
, hlObj
);
10655 switch(pat
->patgrp
->fldr_type
){
10657 peAppListF(interp
, resObj
, "%s%s", "ftype", "any");
10660 peAppListF(interp
, resObj
, "%s%s", "ftype", "news");
10663 peAppListF(interp
, resObj
, "%s%s", "ftype", "email");
10665 case FLDR_SPECIFIC
:
10666 peAppListF(interp
, resObj
, "%s%s", "ftype", "specific");
10670 peAppListF(interp
, resObj
, "%s%p", "folder", pat
->patgrp
->folder
);
10671 peAppListF(interp
, resObj
, "%s%s", "stat_new", pePatStatStr(pat
->patgrp
->stat_new
));
10672 peAppListF(interp
, resObj
, "%s%s", "stat_rec", pePatStatStr(pat
->patgrp
->stat_rec
));
10673 peAppListF(interp
, resObj
, "%s%s", "stat_del", pePatStatStr(pat
->patgrp
->stat_del
));
10674 peAppListF(interp
, resObj
, "%s%s", "stat_imp", pePatStatStr(pat
->patgrp
->stat_imp
));
10675 peAppListF(interp
, resObj
, "%s%s", "stat_ans", pePatStatStr(pat
->patgrp
->stat_ans
));
10676 peAppListF(interp
, resObj
, "%s%s", "stat_8bitsubj", pePatStatStr(pat
->patgrp
->stat_8bitsubj
));
10677 peAppListF(interp
, resObj
, "%s%s", "stat_bom", pePatStatStr(pat
->patgrp
->stat_bom
));
10678 peAppListF(interp
, resObj
, "%s%s", "stat_boy", pePatStatStr(pat
->patgrp
->stat_boy
));
10680 Tcl_ListObjAppendElement(interp
, patObj
, resObj
);
10685 pePatStatStr(int value
)
10688 case PAT_STAT_EITHER
:
10704 * peCreateUserContext - create new wps_global and set it up
10707 peCreateUserContext(Tcl_Interp
*interp
, char *user
, char *config
, char *defconf
)
10710 peDestroyUserContext(&wps_global
);
10712 set_collation(1, 1);
10714 wps_global
= new_pine_struct();
10716 /*----------------------------------------------------------------------
10717 Place any necessary constraints on pith processing
10718 ----------------------------------------------------------------------*/
10720 /* got thru close procedure without expunging */
10721 wps_global
->noexpunge_on_close
= 1;
10723 /* do NOT let user set path to local executable */
10724 wps_global
->vars
[V_SENDMAIL_PATH
].is_user
= 0;
10727 /*----------------------------------------------------------------------
10728 Proceed with reading acquiring user settings
10729 ----------------------------------------------------------------------*/
10730 if(wps_global
->pinerc
)
10731 fs_give((void **) &wps_global
->pinerc
);
10733 if(wps_global
->prc
)
10734 free_pinerc_s(&wps_global
->prc
);
10736 if(!IS_REMOTE(config
)){
10737 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote config: %s", config
);
10738 return(wtmp_20k_buf
);
10741 wps_global
->prc
= new_pinerc_s(config
);
10744 if(wps_global
->pconf
)
10745 free_pinerc_s(&wps_global
->pconf
);
10747 wps_global
->pconf
= new_pinerc_s(defconf
);
10751 * Fake up some user information
10753 wps_global
->ui
.login
= cpystr(user
);
10757 * Prep for IMAP debugging
10759 setup_imap_debug();
10762 /* CHECK FOR AND PASS BACK ANY INIT ERRORS */
10763 return(peLoadConfig(wps_global
));
10769 peDestroyUserContext(struct pine
**pps
)
10772 completely_done_with_adrbks();
10774 free_pinerc_strings(pps
);
10776 imap_flush_passwd_cache(TRUE
);
10778 clear_index_cache(sp_inbox_stream(), 0);
10779 free_newsgrp_cache();
10781 close_patterns(0L);
10783 free_contexts(&wps_global
->context_list
);
10787 free_strlist(&peCertHosts
);
10789 free_pine_struct(pps
);
10794 peLoadConfig(struct pine
*pine_state
)
10797 char *s
, *db
= NULL
;
10798 extern void init_signals(void); /* in signal.c */
10801 return("No global state present");
10804 /*turned off because we don't care about local user*/
10805 /* need home directory early */
10806 get_user_info(&pine_state
->ui
);
10808 pine_state
->home_dir
= cpystr((getenv("HOME") != NULL
)
10810 : pine_state
->ui
.homedir
);
10813 init_pinerc(pine_state
, &db
);
10815 fs_give((void **) &db
);
10818 * Initial allocation of array of stream pool pointers.
10819 * We do this before init_vars so that we can re-use streams used for
10820 * remote config files. These sizes may get changed later.
10822 wps_global
->s_pool
.max_remstream
= 2;
10824 wps_global
->c_client_error
[0] = '\0';
10826 pePrepareForAuthException();
10828 peInitVars(pine_state
);
10830 if((s
= peAuthException()) != NULL
)
10832 else if(wps_global
->c_client_error
[0])
10833 return(wps_global
->c_client_error
);
10835 mail_parameters(NULL
, SET_SENDCOMMAND
, (void *) pine_imap_cmd_happened
);
10836 mail_parameters(NULL
, SET_FREESTREAMSPAREP
, (void *) sp_free_callback
);
10837 mail_parameters(NULL
, SET_FREEELTSPAREP
, (void *) free_pine_elt
);
10840 * Install callback to handle certificate validation failures,
10841 * allowing the user to continue if they wish.
10843 mail_parameters(NULL
, SET_SSLCERTIFICATEQUERY
, (void *) alpine_sslcertquery
);
10844 mail_parameters(NULL
, SET_SSLFAILURE
, (void *) alpine_sslfailure
);
10847 * Set up a c-client read timeout and timeout handler. In general,
10848 * it shouldn't happen, but a server crash or dead link can cause
10849 * pine to appear wedged if we don't set this up...
10851 mail_parameters(NULL
, SET_OPENTIMEOUT
,
10852 (void *)((pine_state
->VAR_TCPOPENTIMEO
10853 && (rv
= atoi(pine_state
->VAR_TCPOPENTIMEO
)) > 4)
10854 ? (long) rv
: 30L));
10855 mail_parameters(NULL
, SET_TIMEOUT
, (void *) alpine_tcptimeout
);
10857 if(pine_state
->VAR_RSHOPENTIMEO
10858 && ((rv
= atoi(pine_state
->VAR_RSHOPENTIMEO
)) == 0 || rv
> 4))
10859 mail_parameters(NULL
, SET_RSHTIMEOUT
, (void *) (long) rv
);
10861 if(pine_state
->VAR_SSHOPENTIMEO
10862 && ((rv
= atoi(pine_state
->VAR_SSHOPENTIMEO
)) == 0 || rv
> 4))
10863 mail_parameters(NULL
, SET_SSHTIMEOUT
, (void *) (long) rv
);
10866 * Tell c-client not to be so aggressive about uid mappings
10868 mail_parameters(NULL
, SET_UIDLOOKAHEAD
, (void *) 20);
10871 * Setup referral handling
10873 mail_parameters(NULL
, SET_IMAPREFERRAL
, (void *) imap_referral
);
10874 mail_parameters(NULL
, SET_MAILPROXYCOPY
, (void *) imap_proxycopy
);
10877 * Install extra headers to fetch along with all the other stuff
10878 * mail_fetch_structure and mail_fetch_overview requests.
10882 if(get_extra_hdrs())
10883 (void) mail_parameters(NULL
, SET_IMAPEXTRAHEADERS
, (void *) get_extra_hdrs());
10885 (void) init_username(pine_state
);
10887 (void) init_hostname(wps_global
);
10890 (void) init_ldap_pname(wps_global
);
10891 #endif /* ENABLE_LDAP */
10893 if(wps_global
->prc
&& wps_global
->prc
->type
== Loc
&&
10894 can_access(wps_global
->pinerc
, ACCESS_EXISTS
) == 0 &&
10895 can_access(wps_global
->pinerc
, EDIT_ACCESS
) != 0)
10896 wps_global
->readonly_pinerc
= 1;
10899 * c-client needs USR2 and we might as well
10900 * do something sensible with HUP and TERM
10904 strncpy(pine_state
->inbox_name
, INBOX_NAME
, sizeof(pine_state
->inbox_name
));
10905 pine_state
->inbox_name
[sizeof(pine_state
->inbox_name
)-1] = '\0';
10907 init_folders(pine_state
); /* digest folder spec's */
10910 * Various options we want to make sure are set OUR way
10912 F_TURN_ON(F_QUELL_IMAP_ENV_CB
, pine_state
);
10913 F_TURN_ON(F_SLCTBL_ITEM_NOBOLD
, pine_state
);
10914 F_TURN_OFF(F_USE_SYSTEM_TRANS
, pine_state
);
10917 * Fake screen dimensions for index formatting and
10918 * message display wrap...
10920 wps_global
->ttyo
= (struct ttyo
*) fs_get(sizeof(struct ttyo
));
10921 wps_global
->ttyo
->screen_rows
= FAKE_SCREEN_LENGTH
;
10922 wps_global
->ttyo
->screen_cols
= FAKE_SCREEN_WIDTH
;
10923 if(wps_global
->VAR_WP_COLUMNS
){
10924 int w
= atoi(wps_global
->VAR_WP_COLUMNS
);
10925 if(w
>= 20 && w
<= 128)
10926 wps_global
->ttyo
->screen_cols
= w
;
10929 wps_global
->ttyo
->header_rows
= 0;
10930 wps_global
->ttyo
->footer_rows
= 0;
10934 if(wps_global
->VAR_NORM_FORE_COLOR
)
10935 pico_nfcolor(wps_global
->VAR_NORM_FORE_COLOR
);
10937 if(wps_global
->VAR_NORM_BACK_COLOR
)
10938 pico_nbcolor(wps_global
->VAR_NORM_BACK_COLOR
);
10940 if(wps_global
->VAR_REV_FORE_COLOR
)
10941 pico_rfcolor(wps_global
->VAR_REV_FORE_COLOR
);
10943 if(wps_global
->VAR_REV_BACK_COLOR
)
10944 pico_rbcolor(wps_global
->VAR_REV_BACK_COLOR
);
10946 pico_set_normal_color();
10953 peCreateStream(Tcl_Interp
*interp
, CONTEXT_S
*context
, char *mailbox
, int do_inbox
)
10955 unsigned long flgs
= 0L;
10958 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
10960 pePrepareForAuthException();
10963 flgs
|= DB_INBOXWOCNTXT
;
10965 if(do_broach_folder(mailbox
, context
, NULL
, flgs
) && wps_global
->mail_stream
){
10966 dprint((SYSDBG_INFO
, "Mailbox open: %s",
10967 wps_global
->mail_stream
->mailbox
? wps_global
->mail_stream
->mailbox
: "<UNKNOWN>"));
10971 Tcl_SetResult(interp
,
10972 (s
= peAuthException())
10974 : (*wps_global
->last_error
)
10975 ? wps_global
->last_error
10983 peDestroyStream(struct pine
*ps
)
10988 cur_is_inbox
= (sp_inbox_stream() == wps_global
->mail_stream
);
10990 /* clean up open streams */
10991 if(ps
->mail_stream
){
10992 expunge_and_close(ps
->mail_stream
, NULL
, EC_NONE
);
10993 wps_global
->mail_stream
= NULL
;
10994 wps_global
->cur_folder
[0] = '\0';
10998 mn_give(&ps
->msgmap
);
11000 if(sp_inbox_stream() && !cur_is_inbox
){
11001 ps
->mail_stream
= sp_inbox_stream();
11002 ps
->msgmap
= sp_msgmap(ps
->mail_stream
);
11003 sp_set_expunge_count(wps_global
->mail_stream
, 0L);
11004 expunge_and_close(sp_inbox_stream(), NULL
, EC_NONE
);
11005 mn_give(&ps
->msgmap
);
11012 * pePrepareForAuthException - set globals to get feedback from bowels of c-client
11015 pePrepareForAuthException(void)
11017 peNoPassword
= peCredentialError
= peCertFailure
= peCertQuery
= 0;
11021 * pePrepareForAuthException - check globals getting feedback from bowels of c-client
11026 static char buf
[CRED_REQ_SIZE
];
11029 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", CERT_QUERY_STRING
, peCredentialRequestor
);
11034 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", CERT_FAILURE_STRING
, peCredentialRequestor
);
11039 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", AUTH_EMPTY_STRING
, peCredentialRequestor
);
11043 if(peCredentialError
){
11044 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", AUTH_FAILURE_STRING
, peCredentialRequestor
);
11053 peInitVars(struct pine
*ps
)
11055 init_vars(ps
, NULL
);
11058 * fix display/keyboard-character-set to utf-8
11063 if(ps
->display_charmap
)
11064 fs_give((void **) &ps
->display_charmap
);
11066 ps
->display_charmap
= cpystr(WP_INTERNAL_CHARSET
);
11068 if(ps
->keyboard_charmap
)
11069 fs_give((void **) &ps
->keyboard_charmap
);
11071 ps
->keyboard_charmap
= cpystr(WP_INTERNAL_CHARSET
);
11073 (void) setup_for_input_output(FALSE
, &ps
->display_charmap
, &ps
->keyboard_charmap
, &ps
->input_cs
, NULL
);;
11079 peMessageBounce(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
11081 char *errstr
= NULL
, *to
, *subj
= NULL
, errbuf
[WP_MAX_POST_ERROR
+ 1];
11083 ENVELOPE
*env
, *outgoing
= NULL
;
11089 rawno
= peSequenceNumber(uid
);
11091 if(objc
> 0 && objv
[0] && (to
= Tcl_GetStringFromObj(objv
[0], NULL
))){
11092 if(objc
== 2 && objv
[1]){
11093 subj
= Tcl_GetStringFromObj(objv
[1], NULL
);
11095 else if((env
= mail_fetchstructure(wps_global
->mail_stream
, rawno
, NULL
)) != NULL
){
11096 subj
= env
->subject
;
11099 Tcl_SetResult(interp
, wps_global
->last_error
, TCL_VOLATILE
);
11103 if((errstr
= bounce_msg_body(wps_global
->mail_stream
, rawno
, NULL
,
11104 &to
, subj
, &outgoing
, &body
, NULL
))){
11105 Tcl_SetResult(interp
, errstr
, TCL_VOLATILE
);
11109 metaenv
= pine_new_env(outgoing
, NULL
, NULL
, custom
= peCustomHdrs());
11111 if(!outgoing
->from
)
11112 outgoing
->from
= generate_from();
11114 rfc822_date(wtmp_20k_buf
);
11115 outgoing
->date
= (unsigned char *) cpystr(wtmp_20k_buf
);
11117 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
11118 if(!outgoing
->message_id
)
11119 outgoing
->message_id
= generate_message_id(NULL
);
11123 if(peDoPost(metaenv
, body
, NULL
, NULL
, errbuf
) != TCL_OK
)
11126 pine_free_body(&body
);
11128 pine_free_env(&metaenv
);
11131 free_customs(custom
);
11133 mail_free_envelope(&outgoing
);
11134 pine_free_body(&body
);
11139 Tcl_SetResult(interp
, (errstr
) ? errstr
: "OK", TCL_VOLATILE
);
11140 return(errstr
? TCL_ERROR
: TCL_OK
);
11145 peMessageSpamNotice(interp
, uid
, objc
, objv
)
11146 Tcl_Interp
*interp
;
11151 char *to
, *subj
= NULL
, errbuf
[WP_MAX_POST_ERROR
+ 1], *rs
= NULL
;
11155 rawno
= peSequenceNumber(uid
);
11157 if(objv
[0] && (to
= Tcl_GetStringFromObj(objv
[0], NULL
)) && strlen(to
)){
11160 subj
= Tcl_GetStringFromObj(objv
[1], NULL
);
11162 rs
= peSendSpamReport(rawno
, to
, subj
, errbuf
);
11166 Tcl_SetResult(interp
, (rs
) ? rs
: "OK", TCL_VOLATILE
);
11167 return(rs
? TCL_ERROR
: TCL_OK
);
11172 peSendSpamReport(long rawno
, char *to
, char *subj
, char *errbuf
)
11174 char *errstr
= NULL
, *tmp_a_string
;
11175 ENVELOPE
*env
, *outgoing
;
11179 static char *fakedomain
= "@";
11183 if((env
= mail_fetchstructure(wps_global
->mail_stream
, rawno
, NULL
)) == NULL
){
11184 return(wps_global
->last_error
);
11187 /* empty subject gets "spam" subject */
11188 if(!(subj
&& *subj
))
11189 subj
= env
->subject
;
11191 /*---- New Body to start with ----*/
11192 body
= mail_newbody();
11193 body
->type
= TYPEMULTIPART
;
11195 /*---- The TEXT part/body ----*/
11196 body
->nested
.part
= mail_newbody_part();
11197 body
->nested
.part
->body
.type
= TYPETEXT
;
11199 if((msgtext
= (void *)so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
11200 pine_free_body(&body
);
11201 return("peSendSpamReport: Can't allocate text");
11204 sprintf(wtmp_20k_buf
,
11205 "The attached message is being reported to <%s> as Spam\n",
11207 so_puts((STORE_S
*) msgtext
, wtmp_20k_buf
);
11208 body
->nested
.part
->body
.contents
.text
.data
= msgtext
;
11211 /*---- Attach the raw message ----*/
11212 if(forward_mime_msg(wps_global
->mail_stream
, rawno
, NULL
, env
,
11213 &(body
->nested
.part
->next
), msgtext
)){
11214 outgoing
= mail_newenvelope();
11215 metaenv
= pine_new_env(outgoing
, NULL
, NULL
, custom
= peCustomHdrs());
11218 pine_free_body(&body
);
11219 return("peSendSpamReport: Can't generate forwarded message");
11222 /* rfc822_parse_adrlist feels free to destroy input so copy */
11223 tmp_a_string
= cpystr(to
);
11224 rfc822_parse_adrlist(&outgoing
->to
, tmp_a_string
,
11225 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, wps_global
))
11226 ? fakedomain
: wps_global
->maildomain
);
11227 fs_give((void **) &tmp_a_string
);
11229 outgoing
->from
= generate_from();
11230 outgoing
->subject
= cpystr(subj
);
11231 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
11232 outgoing
->message_id
= generate_message_id(NULL
);
11234 rfc822_date(wtmp_20k_buf
);
11235 outgoing
->date
= (unsigned char *) cpystr(wtmp_20k_buf
);
11237 /* NO FCC for Spam Reporting */
11239 if(peDoPost(metaenv
, body
, NULL
, NULL
, errbuf
) != TCL_OK
)
11242 pine_free_body(&body
);
11244 pine_free_env(&metaenv
);
11247 free_customs(custom
);
11249 mail_free_envelope(&outgoing
);
11250 pine_free_body(&body
);
11256 /* * * * * * * * * * * * * Start of Composer Routines * * * * * * * * * * * */
11260 * PEComposeCmd - export various bits of alpine state
11263 PEComposeCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
11265 char *err
= "PECompose: Unknown request";
11267 dprint((2, "PEComposeCmd"));
11270 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
11272 else if(!wps_global
){
11273 Tcl_SetResult(interp
, "peCompose: no config present", TCL_STATIC
);
11277 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
11280 if(!strcmp(s1
, "post")){
11281 long flags
= PMC_NONE
;
11282 if(F_ON(F_COMPOSE_REJECTS_UNQUAL
, wps_global
))
11283 flags
|= PMC_FORCE_QUAL
;
11285 return(peMsgCollector(interp
, objc
- 2, (Tcl_Obj
**) &objv
[2], peDoPost
, flags
));
11287 else if(objc
== 2){
11288 if(!strcmp(s1
, "userhdrs")){
11291 PINEFIELD
*custom
, *cp
;
11293 static char *standard
[] = {"To", "Cc", "Bcc", "Fcc", "Attach", "Subject", NULL
};
11295 custom
= peCustomHdrs();
11297 for(i
= 0; standard
[i
]; i
++){
11299 for(cp
= custom
; cp
; cp
= cp
->next
)
11300 if(!strucmp(cp
->name
, standard
[i
]))
11303 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", standard
[i
], p
);
11306 for(cp
= custom
; cp
!= NULL
; cp
= cp
->next
){
11307 if(!strucmp(cp
->name
, "from")){
11308 if(F_OFF(F_ALLOW_CHANGING_FROM
, wps_global
))
11311 if(cp
->textbuf
&& strlen(cp
->textbuf
)){
11317 wtmp_20k_buf
[0] = '\0';
11318 rbuf
.f
= dummy_soutr
;
11320 rbuf
.beg
= wtmp_20k_buf
;
11321 rbuf
.cur
= wtmp_20k_buf
;
11322 rbuf
.end
= wtmp_20k_buf
+SIZEOF_20KBUF
-1;
11323 rfc822_output_address_list(&rbuf
, from
= generate_from(), 0L, NULL
);
11325 mail_free_address(&from
);
11331 for(i
= 0; standard
[i
]; i
++)
11332 if(!strucmp(standard
[i
], cp
->name
))
11339 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", cp
->name
, p
);
11343 free_customs(custom
);
11347 else if(!strcmp(s1
, "syshdrs")){
11349 static char *extras
[] = {"In-Reply-To", "X-Reply-UID", NULL
};
11351 for(i
= 0; extras
[i
]; i
++)
11352 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", extras
[i
], NULL
);
11356 else if(!strcmp(s1
, "composehdrs")){
11359 if((p
= wps_global
->VAR_COMP_HDRS
) && *p
){
11361 Tcl_ListObjAppendElement(interp
,
11362 Tcl_GetObjResult(interp
),
11363 Tcl_NewStringObj(*p
, (q
= strchr(*p
, ':'))
11367 Tcl_SetResult(interp
, "", TCL_STATIC
);
11371 else if(!strcmp(s1
, "fccdefault")){
11373 CONTEXT_S
*c
= default_save_context(wps_global
->context_list
), *c2
;
11375 for(c2
= wps_global
->context_list
; c
&& c
!= c2
; c2
= c2
->next
)
11378 Tcl_ListObjAppendElement(interp
,
11379 Tcl_GetObjResult(interp
),
11380 Tcl_NewIntObj(ci
));
11381 Tcl_ListObjAppendElement(interp
,
11382 Tcl_GetObjResult(interp
),
11383 Tcl_NewStringObj(wps_global
->VAR_DEFAULT_FCC
11384 ? wps_global
->VAR_DEFAULT_FCC
11388 else if(!strcmp(s1
, "noattach")){
11389 peFreeAttach(&peCompAttach
);
11390 Tcl_SetResult(interp
, "OK", TCL_VOLATILE
);
11393 else if(!strcmp(s1
, "from")){
11395 ADDRESS
*from
= generate_from();
11396 wtmp_20k_buf
[0] = '\0';
11397 rbuf
.f
= dummy_soutr
;
11399 rbuf
.beg
= wtmp_20k_buf
;
11400 rbuf
.cur
= wtmp_20k_buf
;
11401 rbuf
.end
= wtmp_20k_buf
+SIZEOF_20KBUF
-1;
11402 rfc822_output_address_list(&rbuf
, from
, 0L, NULL
);
11404 mail_free_address(&from
);
11405 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
11408 else if(!strcmp(s1
, "attachments")){
11410 Tcl_Obj
*objAttach
;
11412 for(p
= peCompAttach
; p
; p
= p
->next
)
11414 objAttach
= Tcl_NewListObj(0, NULL
);
11417 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(p
->id
,-1));
11420 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(p
->l
.f
.remote
,-1));
11423 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewLongObj(p
->l
.f
.size
));
11426 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s", p
->l
.f
.type
, p
->l
.f
.subtype
);
11427 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(wtmp_20k_buf
,-1));
11429 /* append to list */
11430 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
11435 objAttach
= Tcl_NewListObj(0, NULL
);
11438 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(p
->id
,-1));
11441 if((name
= get_filename_parameter(NULL
, 0, p
->l
.b
.body
, NULL
)) != NULL
){
11442 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(name
, -1));
11443 fs_give((void **) &name
);
11446 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj("Unknown", -1));
11449 Tcl_ListObjAppendElement(interp
, objAttach
,
11450 Tcl_NewLongObj((p
->l
.b
.body
->encoding
== ENCBASE64
)
11451 ? ((p
->l
.b
.body
->size
.bytes
* 3)/4)
11452 : p
->l
.b
.body
->size
.bytes
));
11455 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s",
11456 body_type_names(p
->l
.b
.body
->type
),
11457 p
->l
.b
.body
->subtype
? p
->l
.b
.body
->subtype
: "Unknown");
11458 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(wtmp_20k_buf
, -1));
11460 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
11466 else if(objc
== 3){
11467 if(!strcmp(s1
, "unattach")){
11470 if((id
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
11471 if(peClearAttachID(id
)){
11472 Tcl_SetResult(interp
, "OK", TCL_STATIC
);
11476 err
= "Can't access attachment id";
11479 err
= "Can't read attachment id";
11481 else if(!strcmp(s1
, "attachinfo")){
11485 /* return: remote-filename size "type/subtype" */
11486 if((id
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
11487 if((a
= peGetAttachID(id
)) != NULL
){
11490 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(a
->l
.f
.remote
,-1));
11493 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewLongObj(a
->l
.f
.size
));
11496 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s", a
->l
.f
.type
, a
->l
.f
.subtype
);
11497 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(wtmp_20k_buf
,-1));
11500 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
11501 Tcl_NewStringObj((a
->l
.f
.description
) ? a
->l
.f
.description
: "",-1));
11508 if((name
= get_filename_parameter(NULL
, 0, a
->l
.b
.body
, NULL
)) != NULL
){
11509 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(name
, -1));
11510 fs_give((void **) &name
);
11513 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj("Unknown", -1));
11516 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
11517 Tcl_NewLongObj((a
->l
.b
.body
->encoding
== ENCBASE64
)
11518 ? ((a
->l
.b
.body
->size
.bytes
* 3)/4)
11519 : a
->l
.b
.body
->size
.bytes
));
11522 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s",
11523 body_type_names(a
->l
.b
.body
->type
),
11524 a
->l
.b
.body
->subtype
? a
->l
.b
.body
->subtype
: "Unknown");
11526 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(wtmp_20k_buf
, -1));
11529 if(a
->l
.b
.body
->description
){
11530 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%.*s", 256, a
->l
.b
.body
->description
);
11532 else if((s
= parameter_val(a
->l
.b
.body
->parameter
, "description")) != NULL
){
11533 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%.*s", 256, s
);
11534 fs_give((void **) &s
);
11537 wtmp_20k_buf
[0] = '\0';
11539 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(wtmp_20k_buf
, -1));
11544 err
= "Unknown attachment type";
11547 err
= "Can't access attachment id";
11550 err
= "Can't read attachment id";
11553 else if(objc
== 7){
11554 if(!strcmp(s1
, "attach")){
11555 char *file
, *remote
, *type
, *subtype
, *desc
;
11557 if((file
= Tcl_GetStringFromObj(objv
[2], NULL
))
11558 && (type
= Tcl_GetStringFromObj(objv
[3], NULL
))
11559 && (subtype
= Tcl_GetStringFromObj(objv
[4], NULL
))
11560 && (remote
= Tcl_GetStringFromObj(objv
[5], NULL
))){
11563 desc
= Tcl_GetStringFromObj(objv
[6], &dl
);
11566 Tcl_SetResult(interp
, peFileAttachID(file
, type
, subtype
, remote
, desc
, dl
), TCL_VOLATILE
);
11570 err
= "Can't read file description";
11573 err
= "Can't read file name";
11579 Tcl_SetResult(interp
, err
, TCL_STATIC
);
11587 COMPATT_S
*p
= (COMPATT_S
*) fs_get(sizeof(COMPATT_S
));
11588 memset(p
, 0, sizeof(COMPATT_S
));
11594 peFreeAttach(COMPATT_S
**a
)
11597 fs_give((void **) &(*a
)->id
);
11601 fs_give((void **) &(*a
)->l
.f
.type
);
11603 if((*a
)->l
.f
.subtype
)
11604 fs_give((void **) &(*a
)->l
.f
.subtype
);
11606 if((*a
)->l
.f
.remote
)
11607 fs_give((void **) &(*a
)->l
.f
.remote
);
11609 if((*a
)->l
.f
.local
){
11610 (void) unlink((*a
)->l
.f
.local
);
11611 fs_give((void **) &(*a
)->l
.f
.local
);
11614 if((*a
)->l
.f
.description
)
11615 fs_give((void **) &(*a
)->l
.f
.description
);
11617 else if((*a
)->body
){
11618 pine_free_body(&(*a
)->l
.b
.body
);
11621 peFreeAttach(&(*a
)->next
);
11622 fs_give((void **) a
);
11628 peFileAttachID(char *f
, char *t
, char *st
, char *r
, char *d
, int dl
)
11630 COMPATT_S
*ap
= peNewAttach(), *p
;
11634 ap
->l
.f
.local
= cpystr(f
);
11635 ap
->l
.f
.size
= name_file_size(f
);
11637 hval
= line_hash(f
);
11638 while(1) /* collisions? */
11639 if(peGetAttachID(ap
->id
= cpystr(long2string(hval
)))){
11640 fs_give((void **) &ap
->id
);
11646 ap
->l
.f
.remote
= cpystr(r
? r
: "");
11647 ap
->l
.f
.type
= cpystr(t
? t
: "Text");
11648 ap
->l
.f
.subtype
= cpystr(st
? st
: "Plain");
11650 ap
->l
.f
.description
= fs_get(dl
+ 1);
11651 snprintf(ap
->l
.f
.description
, dl
+ 1, "%s", d
);
11653 if((p
= peCompAttach
) != NULL
){
11659 while((p
= p
->next
) != NULL
);
11669 peBodyAttachID(BODY
*b
)
11671 COMPATT_S
*ap
= peNewAttach(), *p
;
11672 unsigned long hval
;
11675 ap
->l
.b
.body
= copy_body(NULL
, b
);
11677 hval
= b
->id
? line_hash(b
->id
) : time(0);
11678 while(1) /* collisions? */
11679 if(peGetAttachID(ap
->id
= cpystr(ulong2string(hval
)))){
11680 fs_give((void **) &ap
->id
);
11686 /* move contents pointer to copy */
11687 peBodyMoveContents(b
, ap
->l
.b
.body
);
11689 if((p
= peCompAttach
) != NULL
){
11695 while((p
= p
->next
) != NULL
);
11705 peBodyMoveContents(BODY
*bs
, BODY
*bd
)
11708 if(bs
->type
== TYPEMULTIPART
&& bd
->type
== TYPEMULTIPART
){
11709 PART
*ps
= bs
->nested
.part
,
11710 *pd
= bd
->nested
.part
;
11711 do /* for each part */
11712 peBodyMoveContents(&ps
->body
, &pd
->body
);
11713 while ((ps
= ps
->next
) && (pd
= pd
->next
)); /* until done */
11715 else if(bs
->contents
.text
.data
){
11716 bd
->contents
.text
.data
= bs
->contents
.text
.data
;
11717 bs
->contents
.text
.data
= NULL
;
11725 peGetAttachID(char *h
)
11729 for(p
= peCompAttach
; p
; p
= p
->next
)
11730 if(!strcmp(p
->id
, h
))
11738 peClearAttachID(char *h
)
11740 COMPATT_S
*pp
, *pt
= NULL
;
11742 for(pp
= peCompAttach
; pp
; pp
= pp
->next
){
11743 if(!strcmp(pp
->id
, h
)){
11745 pt
->next
= pp
->next
;
11747 peCompAttach
= pp
->next
;
11762 * peDoPost - handle preparing header and body text for posting, prepare
11763 * for any Fcc, then call the mailer to send it out
11766 peDoPost(METAENV
*metaenv
, BODY
*body
, char *fcc
, CONTEXT_S
**fcc_cntxtp
, char *errp
)
11768 int rv
= TCL_OK
, recipients
;
11771 if(commence_fcc(fcc
, fcc_cntxtp
, TRUE
)){
11773 wps_global
->c_client_error
[0] = wps_global
->last_error
[0] = '\0';
11774 pePrepareForAuthException();
11776 if((recipients
= (metaenv
->env
->to
|| metaenv
->env
->cc
|| metaenv
->env
->bcc
))
11777 && call_mailer(metaenv
, body
, NULL
, 0, NULL
, NULL
) < 0){
11778 if((s
= peAuthException()) != NULL
){
11781 else if(wps_global
->last_error
[0]){
11782 sprintf(errp
, "Send Error: %.*s", 64, wps_global
->last_error
);
11784 else if(wps_global
->c_client_error
[0]){
11785 sprintf(errp
, "Send Error: %.*s", 64, wps_global
->c_client_error
);
11788 strcpy(errp
, "Sending Failure");
11791 dprint((1, "call_mailer failed!"));
11793 else if(fcc
&& fcc_cntxtp
&& !wrapup_fcc(fcc
, *fcc_cntxtp
, recipients
? NULL
: metaenv
, body
)){
11794 strcpy(errp
, "Fcc Failed!. No message saved.");
11796 dprint((1, "explicit fcc write failed!"));
11800 REPLY_S
*reply
= NULL
;
11802 /* success, now look for x-reply-uid to flip answered flag for? */
11804 for(pf
= metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
11805 if(!strucmp(pf
->name
, "x-reply-uid")){
11807 if((reply
= (REPLY_S
*) build_reply_uid(pf
->textbuf
)) != NULL
){
11809 update_answered_flags(reply
);
11812 fs_give((void **) &reply
->mailbox
);
11815 fs_give((void **) &reply
->prefix
);
11817 if(reply
->data
.uid
.msgs
)
11818 fs_give((void **) &reply
->data
.uid
.msgs
);
11820 fs_give((void **) &reply
);
11829 dprint((1,"can't open fcc, cont"));
11831 strcpy(errp
, "Can't open Fcc");
11841 * pePostponeCmd - export various bits of alpine state
11844 PEPostponeCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
11846 char *err
= "PEPostpone: unknown request";
11850 dprint((2, "PEPostponeCmd"));
11853 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
11855 else if(!wps_global
){
11856 Tcl_SetResult(interp
, "pePostpone: no config present", TCL_STATIC
);
11860 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
11863 if(!strcmp(s1
, "extract")){
11864 if(Tcl_GetLongFromObj(interp
, objv
[2], &uidl
) == TCL_OK
){
11865 Tcl_Obj
*objHdr
= NULL
, *objBod
= NULL
, *objAttach
= NULL
, *objOpts
= NULL
;
11866 MAILSTREAM
*stream
;
11868 ENVELOPE
*env
= NULL
;
11869 PINEFIELD
*custom
= NULL
, *cp
;
11870 REPLY_S
*reply
= NULL
;
11871 ACTION_S
*role
= NULL
;
11875 char *fcc
= NULL
, *lcc
= NULL
;
11876 unsigned flags
= REDRAFT_DEL
| REDRAFT_PPND
;
11879 if(objc
> 3){ /* optional flags */
11881 Tcl_Obj
**objFlags
;
11884 Tcl_ListObjGetElements(interp
, objv
[3], &nFlags
, &objFlags
);
11885 for(i
= 0; i
< nFlags
; i
++){
11886 if((flagstr
= Tcl_GetStringFromObj(objFlags
[i
], NULL
)) == NULL
){
11890 if(!strucmp(flagstr
, "html"))
11891 flags
|= REDRAFT_HTML
;
11894 /* BUG: should probably complain if argc > 4 */
11897 && postponed_stream(&stream
, wps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0)
11899 if((so
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
11900 if((n
= mail_msgno(stream
, uid
)) > 0L){
11901 if(redraft_work(&stream
, n
, &env
, &b
, &fcc
, &lcc
, &reply
,
11902 NULL
, &custom
, &role
, /* should role be NULL? */
11904 char *charset
= NULL
;
11906 /* prepare to package up for caller */
11907 objHdr
= Tcl_NewListObj(0, NULL
);
11909 /* determine body part's charset */
11910 if((charset
= parameter_val(b
->parameter
,"charset")) != NULL
){
11911 objOpts
= Tcl_NewListObj(0, NULL
);
11912 peAppListF(interp
, objOpts
, "%s%s", "charset", charset
);
11913 fs_give((void **) &charset
);
11916 /* body part's MIME subtype */
11917 if(b
->subtype
&& strucmp(b
->subtype
,"plain")){
11919 objOpts
= Tcl_NewListObj(0, NULL
);
11921 peAppListF(interp
, objOpts
, "%s%s", "subtype", b
->subtype
);
11924 peAppListF(interp
, objHdr
, "%s%a", "from",
11925 role
&& role
->from
? role
->from
: env
->from
);
11926 peAppListF(interp
, objHdr
, "%s%a", "to", env
->to
);
11927 peAppListF(interp
, objHdr
, "%s%a", "cc", env
->cc
);
11928 peAppListF(interp
, objHdr
, "%s%a", "bcc", env
->bcc
);
11929 peAppListF(interp
, objHdr
, "%s%s", "in-reply-to", env
->in_reply_to
);
11930 peAppListF(interp
, objHdr
, "%s%s", "subject",
11931 rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
,
11932 SIZEOF_20KBUF
, env
->subject
));
11935 peFccAppend(interp
, objHdr
, fcc
, -1);
11937 for(cp
= custom
; cp
&& cp
->name
; cp
= cp
->next
)
11940 strncpy(wtmp_20k_buf
, cp
->name
, SIZEOF_20KBUF
);
11941 wtmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
11942 peAppListF(interp
, objHdr
, "%s%a",
11943 lcase((unsigned char *) wtmp_20k_buf
), *cp
->addr
);
11951 break; /* ignored */
11954 strncpy(wtmp_20k_buf
, cp
->name
, SIZEOF_20KBUF
);
11955 wtmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
11956 peAppListF(interp
, objHdr
, "%s%s",
11957 lcase((unsigned char *) wtmp_20k_buf
), cp
->textbuf
? cp
->textbuf
: cp
->val
);
11962 /* blat x-Reply-UID: for possible use? */
11964 char uidbuf
[MAILTMPLEN
], *p
;
11967 for(i
= 0L, p
= wtmp_20k_buf
; reply
->data
.uid
.msgs
[i
]; i
++){
11969 sstrncpy(&p
, ",", SIZEOF_20KBUF
-(p
-wtmp_20k_buf
));
11971 sstrncpy(&p
,ulong2string(reply
->data
.uid
.msgs
[i
]), SIZEOF_20KBUF
-(p
-wtmp_20k_buf
));
11974 wtmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
11976 snprintf(uidbuf
, sizeof(uidbuf
), "(%s%s%s)(%ld %lu %s)%s",
11977 reply
->prefix
? int2string(strlen(reply
->prefix
))
11978 : (reply
->forwarded
) ? "" : "0 ",
11979 reply
->prefix
? " " : "",
11980 reply
->prefix
? reply
->prefix
: "",
11981 i
, reply
->data
.uid
.validity
,
11982 wtmp_20k_buf
, reply
->mailbox
);
11984 peAppListF(interp
, objHdr
, "%s%s", "x-reply-uid", uidbuf
);
11987 fs_give((void **) &reply
->mailbox
);
11988 fs_give((void **) &reply
->prefix
);
11989 fs_give((void **) &reply
->data
.uid
.msgs
);
11990 fs_give((void **) &reply
);
11993 objBod
= Tcl_NewListObj(0, NULL
);
11994 peSoStrToList(interp
, objBod
, so
);
11996 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objHdr
);
11997 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objBod
);
11999 objAttach
= peMsgAttachCollector(interp
, b
);
12001 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
12004 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),objOpts
);
12009 fs_give((void **) &fcc
);
12012 fs_give((void **) &lcc
);
12014 mail_free_envelope(&env
);
12015 pine_free_body(&b
);
12016 free_action(&role
);
12018 /* if Drafts got whacked, open INBOX */
12019 if(!wps_global
->mail_stream
)
12020 do_broach_folder(wps_global
->inbox_name
,
12021 wps_global
->context_list
,
12022 NULL
, DB_INBOXWOCNTXT
);
12030 err
= "Unknown UID";
12033 err
= "No internal storage";
12035 /* redraft_work cleaned up the "stream" */
12038 err
= "No Postponed stream";
12041 err
= "Malformed extract request";
12043 else if(objc
== 2){
12044 if(!strcmp(s1
, "any")){
12045 MAILSTREAM
*stream
;
12047 if(postponed_stream(&stream
, wps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12048 Tcl_SetResult(interp
, "1", TCL_STATIC
);
12050 if(stream
!= wps_global
->mail_stream
)
12051 pine_mail_close(stream
);
12054 Tcl_SetResult(interp
, "0", TCL_STATIC
);
12058 else if(!strcmp(s1
, "count")){
12059 MAILSTREAM
*stream
;
12061 if(postponed_stream(&stream
, wps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12062 Tcl_SetResult(interp
, long2string(stream
->nmsgs
), TCL_STATIC
);
12064 if(stream
!= wps_global
->mail_stream
)
12065 pine_mail_close(stream
);
12068 Tcl_SetResult(interp
, "-1", TCL_STATIC
);
12072 else if(!strcmp(s1
, "list")){
12073 MAILSTREAM
*stream
;
12075 Tcl_Obj
*objEnv
= NULL
, *objEnvList
;
12078 if(postponed_stream(&stream
, wps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12079 if(!stream
->nmsgs
){
12080 (void) redraft_cleanup(&stream
, FALSE
, REDRAFT_PPND
);
12081 Tcl_SetResult(interp
, "", TCL_STATIC
);
12085 objEnvList
= Tcl_NewListObj(0, NULL
);
12087 for(n
= 1; n
<= stream
->nmsgs
; n
++){
12088 if((env
= pine_mail_fetchstructure(stream
, n
, NULL
)) != NULL
){
12089 objEnv
= Tcl_NewListObj(0, NULL
);
12091 peAppListF(interp
, objEnv
, "%s%s", "uid",
12092 ulong2string(mail_uid(stream
, n
)));
12094 peAppListF(interp
, objEnv
, "%s%a", "to", env
->to
);
12096 date_str((char *)env
->date
, iSDate
, 1, wtmp_20k_buf
, SIZEOF_20KBUF
, 0);
12098 peAppListF(interp
, objEnv
, "%s%s", "date", wtmp_20k_buf
);
12100 peAppListF(interp
, objEnv
, "%s%s", "subj",
12101 rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
,
12102 SIZEOF_20KBUF
, env
->subject
));
12104 Tcl_ListObjAppendElement(interp
, objEnvList
, objEnv
);
12108 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objEnvList
);
12110 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
12111 Tcl_NewStringObj("utf-8", -1));
12113 if(stream
!= wps_global
->mail_stream
)
12114 pine_mail_close(stream
);
12120 else if(objc
== 3){
12121 if(!strcmp(s1
, "append")){
12124 if((rv
= peMsgCollector(interp
, objc
- 2, (Tcl_Obj
**) &objv
[2], peDoPostpone
, PMC_NONE
)) == TCL_OK
)
12125 Tcl_SetResult(interp
, ulong2string(get_last_append_uid()), TCL_VOLATILE
);
12129 else if(!strcmp(s1
, "draft")){
12132 if((rv
= peMsgCollector(interp
, objc
- 2, (Tcl_Obj
**) &objv
[2], peDoPostpone
, PMC_PRSRV_ATT
)) == TCL_OK
)
12133 Tcl_SetResult(interp
, ulong2string(get_last_append_uid()), TCL_VOLATILE
);
12137 else if(!strcmp(s1
, "delete")){
12138 if(Tcl_GetLongFromObj(interp
, objv
[2], &uidl
) == TCL_OK
){
12139 MAILSTREAM
*stream
;
12143 if(postponed_stream(&stream
, wps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12144 if((rawno
= mail_msgno(stream
, uid
)) > 0L){
12145 mail_flag(stream
, long2string(rawno
), "\\DELETED", ST_SET
);
12146 wps_global
->expunge_in_progress
= 1;
12147 mail_expunge(stream
);
12148 wps_global
->expunge_in_progress
= 0;
12149 if(stream
!= wps_global
->mail_stream
)
12150 pine_mail_actually_close(stream
);
12155 err
= "PEPostpone delete: UID no longer exists";
12158 err
= "PEPostpone delete: No Postponed stream";
12161 err
= "PEPostpone delete: No uid provided";
12167 Tcl_SetResult(interp
, err
, TCL_STATIC
);
12173 * peDoPostpone - handle postponing after message collection
12176 peDoPostpone(METAENV
*metaenv
, BODY
*body
, char *fcc
, CONTEXT_S
**fcc_cntxtp
, char *errp
)
12183 * resolve fcc and store it in fcc custom header field data
12185 if(fcc
&& *fcc
&& fcc_cntxtp
&& *fcc_cntxtp
)
12186 for(pf
= metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
12187 if(!strucmp("fcc", pf
->name
)){
12188 char *name
, *rs
, path_in_context
[MAILTMPLEN
];
12190 if(pf
->textbuf
) /* free old value */
12191 fs_give((void **) &pf
->textbuf
);
12193 /* replace nickname with full name */
12194 if(!(name
= folder_is_nick(fcc
, FOLDERS(*fcc_cntxtp
), FN_NONE
)))
12197 if(context_isambig(name
) && !(((*fcc_cntxtp
)->use
) & CNTXT_SAVEDFLT
)){
12198 context_apply(path_in_context
, *fcc_cntxtp
, name
, sizeof(path_in_context
));
12199 rs
= IS_REMOTE(path_in_context
) ? path_in_context
: NULL
;
12205 pf
->textbuf
= cpystr(rs
);
12206 pf
->text
= &pf
->textbuf
;
12212 au
= mail_parameters(NIL
, GET_APPENDUID
, NIL
);
12213 mail_parameters(NIL
, SET_APPENDUID
, (void *) appenduid_cb
);
12215 rv
= write_postponed(metaenv
, body
);
12217 mail_parameters(NIL
, SET_APPENDUID
, (void *) au
);
12219 return((rv
< 0) ? TCL_ERROR
: TCL_OK
);
12224 * peMsgCollector - Collect message parts and call specified handler
12227 peMsgCollector(Tcl_Interp
*interp
,
12230 int (*postfunc
)(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *),
12233 Tcl_Obj
**objMsg
, **objField
, **objBody
;
12234 int i
, j
, vl
, nMsg
, nField
, nBody
;
12235 char *field
, *value
, *err
= NULL
;
12238 STRLIST_S
*tp
, *lp
;
12239 static char *fakedomain
= "@";
12241 memset(&md
, 0, sizeof(MSG_COL_S
));
12242 md
.postop_fcc_no_attach
= -1;
12243 md
.postfunc
= postfunc
;
12244 md
.qualified_addrs
= ((flags
& PMC_FORCE_QUAL
) == PMC_FORCE_QUAL
);
12247 Tcl_SetResult(interp
, "Malformed message data", TCL_STATIC
);
12250 else if(!wps_global
){
12251 Tcl_SetResult(interp
, "No open folder", TCL_STATIC
);
12255 md
.outgoing
= mail_newenvelope();
12257 md
.metaenv
= pine_new_env(md
.outgoing
, NULL
, NULL
, md
.custom
= peCustomHdrs());
12259 Tcl_ListObjGetElements(interp
, objv
[0], &nMsg
, &objMsg
);
12260 for(i
= 0; i
< nMsg
; i
++){
12261 if(Tcl_ListObjGetElements(interp
, objMsg
[i
], &nField
, &objField
) != TCL_OK
){
12262 err
= ""; /* interp's result object has error message */
12263 return(peMsgCollected(interp
, &md
, err
, flags
));
12266 if(nField
&& (field
= Tcl_GetStringFromObj(objField
[0], NULL
))){
12267 if(!strcmp(field
, "body")){
12269 err
= "Too many bodies";
12270 return(peMsgCollected(interp
, &md
, err
, flags
));
12272 else if((md
.msgtext
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
12273 /* mark storage object as user edited */
12274 (void) so_attr(md
.msgtext
, "edited", "1");
12276 Tcl_ListObjGetElements(interp
, objField
[1], &nBody
, &objBody
);
12277 for(j
= 0; j
< nBody
; j
++){
12278 value
= Tcl_GetStringFromObj(objBody
[j
], &vl
);
12280 so_nputs(md
.msgtext
, value
, vl
);
12281 so_puts(md
.msgtext
, "\n");
12284 err
= "Value read failure";
12285 return(peMsgCollected(interp
, &md
, err
, flags
));
12290 err
= "Can't acquire body storage";
12291 return(peMsgCollected(interp
, &md
, err
, flags
));
12294 else if(!strucmp(field
, "attach")){
12299 && (id
= Tcl_GetStringFromObj(objField
[1], NULL
))
12300 && (a
= peGetAttachID(id
))){
12301 tp
= new_strlist(id
);
12302 if((lp
= md
.attach
) != NULL
){
12308 while((lp
= lp
->next
) != NULL
);
12314 strcpy(err
= wtmp_20k_buf
, "Unknown attachment ID");
12315 return(peMsgCollected(interp
, &md
, err
, flags
));
12318 else if(!strucmp(field
, "fcc")){
12322 if(Tcl_ListObjGetElements(interp
, objField
[1], &nFcc
, &objFcc
) == TCL_OK
12324 && Tcl_GetIntFromObj(interp
, objFcc
[0], &md
.fcc_colid
) == TCL_OK
12325 && (value
= Tcl_GetStringFromObj(objFcc
[1], NULL
))){
12327 fs_give((void **) &md
.fcc
);
12329 md
.fcc
= cpystr(value
);
12332 strcpy(err
= wtmp_20k_buf
, "Unrecognized Fcc specification");
12333 return(peMsgCollected(interp
, &md
, err
, flags
));
12336 else if(!strucmp(field
, "postoption")){
12341 if(Tcl_ListObjGetElements(interp
, objField
[1], &nPO
, &objPO
) == TCL_OK
12343 && (value
= Tcl_GetStringFromObj(objPO
[0], NULL
))){
12344 if(!strucmp(value
,"fcc-without-attachments")){
12345 if(Tcl_GetIntFromObj(interp
, objPO
[1], &ival
) == TCL_OK
){
12346 md
.postop_fcc_no_attach
= (ival
!= 0);
12349 sprintf(err
= wtmp_20k_buf
, "Malformed Post Option: fcc-without-attachments");
12350 return(peMsgCollected(interp
, &md
, err
, flags
));
12353 else if(!strucmp(value
, "charset")){
12354 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12357 for(p
= value
; ; p
++){ /* sanity check */
12359 md
.charset
= cpystr(value
);
12363 if(isspace((unsigned char ) *p
)
12364 || !isprint((unsigned char) *p
))
12367 if(p
- value
> 255)
12372 err
= "Post option read failure";
12373 return(peMsgCollected(interp
, &md
, err
, flags
));
12376 else if(!strucmp(value
, "flowed")){
12377 if(F_OFF(F_QUELL_FLOWED_TEXT
,wps_global
)){
12378 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12379 if(!strucmp(value
, "yes"))
12383 err
= "Post option read failure";
12384 return(peMsgCollected(interp
, &md
, err
, flags
));
12388 else if(!strucmp(value
, "subtype")){
12389 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12390 if(!strucmp(value
, "html"))
12394 err
= "Post option read failure";
12395 return(peMsgCollected(interp
, &md
, err
, flags
));
12398 else if(!strucmp(value
, "priority")){
12399 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12400 char *priority
= NULL
;
12402 if(!strucmp(value
, "highest"))
12403 priority
= "Highest";
12404 else if(!strucmp(value
, "high"))
12406 else if(!strucmp(value
, "normal"))
12407 priority
= "Normal";
12408 else if(!strucmp(value
, "low"))
12410 else if(!strucmp(value
, "lowest"))
12411 priority
= "Lowest";
12414 if((pf
= set_priority_header(md
.metaenv
, priority
)) != NULL
)
12415 pf
->text
= &pf
->textbuf
;
12419 err
= "Post option read failure";
12420 return(peMsgCollected(interp
, &md
, err
, flags
));
12424 sprintf(err
= wtmp_20k_buf
, "Unknown Post Option: %s", value
);
12425 return(peMsgCollected(interp
, &md
, err
, flags
));
12429 sprintf(err
= wtmp_20k_buf
, "Malformed Post Option");
12430 return(peMsgCollected(interp
, &md
, err
, flags
));
12435 sprintf(err
= wtmp_20k_buf
, "Malformed header (%s)", field
);
12436 return(peMsgCollected(interp
, &md
, err
, flags
));
12439 if((value
= Tcl_GetStringFromObj(objField
[1], &vl
)) != NULL
){
12440 ADDRESS
**addrp
= NULL
;
12441 char **valp
= NULL
, *valcpy
;
12443 if(!strucmp(field
, "from")){
12444 addrp
= &md
.outgoing
->from
;
12446 else if(!strucmp(field
, "reply-to")){
12447 addrp
= &md
.outgoing
->reply_to
;
12449 else if(!strucmp(field
, "to")){
12450 addrp
= &md
.outgoing
->to
;
12452 else if(!strucmp(field
, "cc")){
12453 addrp
= &md
.outgoing
->cc
;
12455 else if(!strucmp(field
, "bcc")){
12456 addrp
= &md
.outgoing
->bcc
;
12458 else if(!strucmp(field
, "subject")){
12459 valp
= &md
.outgoing
->subject
;
12461 else if(!strucmp(field
, "in-reply-to")){
12462 valp
= &md
.outgoing
->in_reply_to
;
12464 else if(!strucmp(field
, "newsgroups")){
12465 valp
= &md
.outgoing
->newsgroups
;
12467 else if(!strucmp(field
, "followup-to")){
12468 valp
= &md
.outgoing
->followup_to
;
12470 else if(!strucmp(field
, "references")){
12471 valp
= &md
.outgoing
->references
;
12473 else if(!strucmp(field
, "x-reply-uid")){
12474 for(pf
= md
.metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
12475 if(!strucmp(pf
->name
, "x-reply-uid")){
12476 valp
= pf
->text
= &pf
->textbuf
;
12480 else if(!strucmp(field
, "x-auth-received")){
12481 for(pf
= md
.metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
12482 if(!strucmp(pf
->name
, "x-auth-received")){
12483 valp
= pf
->text
= &pf
->textbuf
;
12488 for(pf
= md
.metaenv
->custom
; pf
&& pf
->name
; pf
= pf
->next
)
12489 if(!strucmp(field
, pf
->name
)){
12490 if(pf
->type
== Address
)
12493 valp
= &pf
->textbuf
;
12494 else if(pf
->textbuf
)
12495 fs_give((void **) &pf
->textbuf
);
12501 dprint((2, "\nPOST: unrecognized field - %s\n", field
));
12506 fs_give((void **) valp
);
12508 sprintf(*valp
= fs_get((vl
+ 1) * sizeof(char)), "%.*s", vl
, value
);
12512 sprintf(valcpy
= fs_get((vl
+ 1) * sizeof(char)), "%.*s", vl
, value
);
12514 for(; *addrp
; addrp
= &(*addrp
)->next
)
12517 rfc822_parse_adrlist(addrp
, valcpy
,
12518 (flags
& PMC_FORCE_QUAL
)
12519 ? fakedomain
: wps_global
->maildomain
);
12520 fs_give((void **) &valcpy
);
12524 err
= "Value read failure";
12525 return(peMsgCollected(interp
, &md
, err
, flags
));
12531 return(peMsgCollected(interp
, &md
, err
, flags
));
12536 * peMsgCollected - Dispatch collected message data and cleanup
12539 peMsgCollected(Tcl_Interp
*interp
, MSG_COL_S
*md
, char *err
, long flags
)
12541 int rv
= TCL_OK
, non_ascii
= FALSE
;
12543 BODY
*body
= NULL
, *tbp
= NULL
;
12544 char errbuf
[WP_MAX_POST_ERROR
+ 1], *charset
;
12549 so_give(&md
->msgtext
);
12553 else if(md
->qualified_addrs
&& check_addresses(md
->metaenv
) == CA_BAD
){
12554 sprintf(err
= wtmp_20k_buf
, "Address must be fully qualified.");
12558 /* sniff body for possible multipart wrapping to protect encoding */
12559 so_seek(md
->msgtext
, 0L, 0);
12561 while(so_readc(&c
, md
->msgtext
))
12562 if(!c
|| c
& 0x80){
12567 if(!md
->outgoing
->from
)
12568 md
->outgoing
->from
= generate_from();
12570 rfc822_date(wtmp_20k_buf
);
12571 md
->outgoing
->date
= (unsigned char *) cpystr(wtmp_20k_buf
);
12572 md
->outgoing
->return_path
= rfc822_cpy_adr(md
->outgoing
->from
);
12573 md
->outgoing
->message_id
= generate_message_id(NULL
);
12575 body
= mail_newbody();
12577 /* wire any attachments to body */
12578 if(md
->attach
|| (non_ascii
&& F_OFF(F_COMPOSE_ALWAYS_DOWNGRADE
, wps_global
))){
12583 /* setup slot for message text */
12584 body
->type
= TYPEMULTIPART
;
12585 body
->nested
.part
= mail_newbody_part();
12586 tbp
= &body
->nested
.part
->body
;
12588 /* link in attachments */
12589 for(lp
= md
->attach
, np
= &body
->nested
.part
->next
; lp
; lp
= lp
->next
, np
= &(*np
)->next
){
12590 if(!(a
= peGetAttachID(lp
->name
))){
12591 err
= "Unknown Attachment ID";
12596 *np
= mail_newbody_part();
12599 (*np
)->body
.id
= generate_message_id(NULL
);
12600 (*np
)->body
.description
= cpystr(a
->l
.f
.description
);
12602 /* set name parameter */
12603 for(pp
= &(*np
)->body
.parameter
; *pp
; )
12604 if(!struncmp((*pp
)->attribute
, "name", 4)
12605 && (!*((*pp
)->attribute
+ 4)
12606 || *((*pp
)->attribute
+ 4) == '*')){
12607 PARAMETER
*free_me
= *pp
;
12609 free_me
->next
= NULL
;
12610 mail_free_body_parameter(&free_me
);
12616 set_parameter(pp
, "name", a
->l
.f
.remote
);
12618 /* Then set the Content-Disposition ala RFC1806 */
12619 if(!(*np
)->body
.disposition
.type
){
12620 (*np
)->body
.disposition
.type
= cpystr("attachment");
12621 for(pp
= &(*np
)->body
.disposition
.parameter
; *pp
; )
12622 if(!struncmp((*pp
)->attribute
, "filename", 4)
12623 && (!*((*pp
)->attribute
+ 4)
12624 || *((*pp
)->attribute
+ 4) == '*')){
12625 PARAMETER
*free_me
= *pp
;
12627 free_me
->next
= NULL
;
12628 mail_free_body_parameter(&free_me
);
12634 set_parameter(pp
, "filename", a
->l
.f
.remote
);
12637 if(((*np
)->body
.contents
.text
.data
= (void *) so_get(FileStar
, a
->l
.f
.local
, READ_ACCESS
)) != NULL
){
12638 (*np
)->body
.type
= mt_translate_type(a
->l
.f
.type
);
12639 (*np
)->body
.subtype
= cpystr(a
->l
.f
.subtype
);
12640 (*np
)->body
.encoding
= ENCBINARY
;
12641 (*np
)->body
.size
.bytes
= name_file_size(a
->l
.f
.local
);
12643 if((*np
)->body
.type
== TYPEOTHER
12644 && !set_mime_type_by_extension(&(*np
)->body
, a
->l
.f
.local
))
12645 set_mime_type_by_grope(&(*np
)->body
);
12647 so_release((STORE_S
*)(*np
)->body
.contents
.text
.data
);
12651 err
= "Can't open uploaded attachment";
12657 BODY
*newbody
= copy_body(NULL
, a
->l
.b
.body
);
12658 (*np
)->body
= *newbody
;
12659 fs_give((void **) &newbody
);
12660 peBodyMoveContents(a
->l
.b
.body
, &(*np
)->body
);
12663 err
= "BOTCH: Unknown attachment type";
12672 /* assign MIME parameters to text body part */
12673 tbp
->type
= TYPETEXT
;
12674 if(md
->html
) tbp
->subtype
= cpystr("HTML");
12676 tbp
->contents
.text
.data
= (void *) md
->msgtext
;
12677 tbp
->encoding
= ENCOTHER
;
12679 /* set any text flowed param */
12681 peMsgSetParm(&tbp
->parameter
, "format", "flowed");
12684 CONTEXT_S
*fcc_cntxt
= wps_global
->context_list
;
12686 while(md
->fcc_colid
--)
12687 if(fcc_cntxt
->next
)
12688 fcc_cntxt
= fcc_cntxt
->next
;
12690 if(md
->postop_fcc_no_attach
>= 0){
12691 int oldval
= F_ON(F_NO_FCC_ATTACH
, wps_global
);
12692 F_SET(F_NO_FCC_ATTACH
, wps_global
, md
->postop_fcc_no_attach
);
12693 md
->postop_fcc_no_attach
= oldval
;
12696 pine_encode_body(body
);
12698 rv
= (*md
->postfunc
)(md
->metaenv
, body
, md
->fcc
, &fcc_cntxt
, errbuf
);
12700 if(md
->postop_fcc_no_attach
>= 0){
12701 F_SET(F_NO_FCC_ATTACH
, wps_global
, md
->postop_fcc_no_attach
);
12705 if((flags
& PMC_PRSRV_ATT
) == 0)
12706 peFreeAttach(&peCompAttach
);
12709 /* maintain pointers to attachments */
12710 (void) peMsgAttachCollector(NULL
, body
);
12715 pine_free_body(&body
);
12719 fs_give((void **) &md
->charset
);
12721 free_strlist(&md
->attach
);
12723 pine_free_env(&md
->metaenv
);
12726 free_customs(md
->custom
);
12728 mail_free_envelope(&md
->outgoing
);
12731 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
12738 peMsgSetParm(PARAMETER
**pp
, char *pa
, char *pv
)
12740 for(; *pp
; pp
= &(*pp
)->next
)
12741 if(!strucmp(pa
, (*pp
)->attribute
)){
12743 fs_give((void **) &(*pp
)->value
);
12749 *pp
= mail_newbody_parameter();
12750 (*pp
)->attribute
= cpystr(pa
);
12753 (*pp
)->value
= cpystr(pv
);
12758 peMsgAttachCollector(Tcl_Interp
*interp
, BODY
*b
)
12760 char *id
, *name
= NULL
;
12762 Tcl_Obj
*aListObj
= NULL
, *aObj
= NULL
;
12764 peFreeAttach(&peCompAttach
);
12767 aListObj
= Tcl_NewListObj(0, NULL
);
12769 if(b
->type
== TYPEMULTIPART
){
12771 * Walk first level, clipping branches and adding them
12772 * to the attachment list...
12774 for(part
= b
->nested
.part
->next
; part
; part
= part
->next
) {
12775 id
= peBodyAttachID(&part
->body
);
12776 aObj
= Tcl_NewListObj(0, NULL
);
12779 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj(id
, -1));
12782 if((name
= get_filename_parameter(NULL
, 0, &part
->body
, NULL
)) != NULL
){
12783 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj(name
, -1));
12784 fs_give((void **) &name
);
12787 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj("Unknown", -1));
12790 Tcl_ListObjAppendElement(interp
, aObj
,
12791 Tcl_NewLongObj((part
->body
.encoding
== ENCBASE64
)
12792 ? ((part
->body
.size
.bytes
* 3)/4)
12793 : part
->body
.size
.bytes
));
12796 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s",
12797 body_type_names(part
->body
.type
),
12798 part
->body
.subtype
? part
->body
.subtype
: rfc822_default_subtype (part
->body
.type
));
12799 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj(wtmp_20k_buf
, -1));
12800 Tcl_ListObjAppendElement(interp
, aListObj
, aObj
);
12810 peFccAppend(Tcl_Interp
*interp
, Tcl_Obj
*obj
, char *fcc
, int colid
)
12812 Tcl_Obj
*objfcc
= NULL
;
12815 colid
= (wps_global
->context_list
&& (wps_global
->context_list
->use
& CNTXT_INCMNG
)) ? 1 : 0;
12817 return((objfcc
= Tcl_NewListObj(0, NULL
))
12818 && Tcl_ListObjAppendElement(interp
, objfcc
, Tcl_NewStringObj("fcc", -1)) == TCL_OK
12819 && peAppListF(interp
, objfcc
, "%i%s", colid
, fcc
) == TCL_OK
12820 && Tcl_ListObjAppendElement(interp
, obj
, objfcc
) == TCL_OK
);
12824 /* * * * * * * * * * * * * Start of Address Management Routines * * * * * * * * * * * */
12828 * PEAddressCmd - export various bits of address book/directory access
12831 PEAddressCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
12835 dprint((2, "PEAddressCmd"));
12838 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
12841 else if(!wps_global
){
12842 Tcl_SetResult(interp
, "PEAddress: no open folder", TCL_STATIC
);
12845 else if((op
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
12847 if(!strcmp(op
, "safecheck")){
12848 if(peInitAddrbooks(interp
, 1) != TCL_OK
)
12852 else if(!strcmp(op
, "books")){
12856 * return the list of configured address books
12859 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
12862 for(i
= 0; i
< as
.n_addrbk
; i
++){
12865 objmv
[0] = Tcl_NewIntObj(i
);
12866 if(as
.adrbks
[i
].abnick
){
12867 objmv
[1] = Tcl_NewStringObj(as
.adrbks
[i
].abnick
, -1);
12872 snprintf(buf
, sizeof(buf
), "Address book number %d", i
+ 1);
12873 objmv
[1] = Tcl_NewStringObj(buf
, -1);
12876 objmv
[2] = Tcl_NewStringObj(as
.adrbks
[i
].filename
? as
.adrbks
[i
].filename
: "", -1);
12878 objmv
[3] = Tcl_NewIntObj(as
.adrbks
[i
].access
== ReadWrite
);
12880 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
12881 Tcl_NewListObj(4, objmv
));
12887 else if(objc
== 3){
12888 if(!strcmp(op
, "parselist")){
12890 ADDRESS
*addrlist
= NULL
, *atmp
, *anextp
;
12891 static char *fakedomain
= "@";
12893 if((addrstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
)
12894 addrstr
= cpystr(addrstr
); /* can't munge tcl copy */
12896 wps_global
->c_client_error
[0] = '\0';
12897 rfc822_parse_adrlist(&addrlist
, addrstr
,
12898 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, wps_global
))
12899 ? fakedomain
: wps_global
->maildomain
);
12901 fs_give((void **) &addrstr
);
12902 if(wps_global
->c_client_error
[0]){
12903 Tcl_SetResult(interp
, wps_global
->c_client_error
, TCL_STATIC
);
12907 for(atmp
= addrlist
; atmp
; ){
12910 anextp
= atmp
->next
;
12912 wtmp_20k_buf
[0] = '\0';
12913 rbuf
.f
= dummy_soutr
;
12915 rbuf
.beg
= wtmp_20k_buf
;
12916 rbuf
.cur
= wtmp_20k_buf
;
12917 rbuf
.end
= wtmp_20k_buf
+SIZEOF_20KBUF
-1;
12918 rfc822_output_address_list(&rbuf
, atmp
, 0L, NULL
);
12920 Tcl_ListObjAppendElement(interp
,
12921 Tcl_GetObjResult(interp
),
12922 Tcl_NewStringObj(wtmp_20k_buf
, -1));
12926 mail_free_address(&addrlist
);
12929 else if(!strcmp(op
, "xlookup")){
12931 ADDRESS
*addrlist
= NULL
, *atmp
, *anextp
;
12932 static char *fakedomain
= "@";
12934 if((addrstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
)
12935 addrstr
= cpystr(addrstr
); /* can't munge tcl copy */
12937 wps_global
->c_client_error
[0] = '\0';
12938 rfc822_parse_adrlist(&addrlist
, addrstr
,
12939 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, wps_global
))
12940 ? fakedomain
: wps_global
->maildomain
);
12942 fs_give((void **) &addrstr
);
12943 if(wps_global
->c_client_error
[0]){
12944 Tcl_SetResult(interp
, wps_global
->c_client_error
, TCL_STATIC
);
12948 for(atmp
= addrlist
; atmp
; ){
12949 anextp
= atmp
->next
;
12951 wtmp_20k_buf
[0] = '\0';
12953 if(atmp
->host
[0] == '@'){
12954 /* leading ampersand means "missing-hostname" */
12959 rbuf
.f
= dummy_soutr
;
12961 rbuf
.beg
= wtmp_20k_buf
;
12962 rbuf
.cur
= wtmp_20k_buf
;
12963 rbuf
.end
= wtmp_20k_buf
+SIZEOF_20KBUF
-1;
12964 rfc822_output_address_list(&rbuf
, atmp
, 0L, NULL
);
12966 Tcl_ListObjAppendElement(interp
,
12967 Tcl_GetObjResult(interp
),
12968 Tcl_NewStringObj(wtmp_20k_buf
, -1));
12970 } /* else group syntax, move on */
12975 mail_free_address(&addrlist
);
12978 else if(!strcmp(op
, "format")){
12982 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
12988 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
)
12989 for(i
= 0; i
< as
.n_addrbk
; i
++)
12991 addrbook_new_disp_form(&as
.adrbks
[booknum
], wps_global
->VAR_ABOOK_FORMATS
, booknum
, NULL
);
12993 for(i
= 0; i
< NFIELDS
&& as
.adrbks
[booknum
].disp_form
[i
].type
!= Notused
; i
++){
12994 switch(as
.adrbks
[booknum
].disp_form
[i
].type
){
13018 objmv
[0] = Tcl_NewStringObj(s
, -1);
13019 objmv
[1] = Tcl_NewIntObj((100 * as
.adrbks
[booknum
].disp_form
[i
].width
) / wps_global
->ttyo
->screen_cols
);
13020 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13021 Tcl_NewListObj(2, objmv
));
13029 snprintf(buf
, sizeof(buf
), "PEAddress list: unknown address book number \"%d\"", booknum
);
13030 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13033 else if(!strcmp(op
, "list")){
13034 int i
, j
, k
, n
, booknum
;
13037 Tcl_Obj
*objev
[NFIELDS
+ 1], *objhv
[2];
13039 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13045 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
)
13046 for(i
= 0; i
< as
.n_addrbk
; i
++)
13048 addrbook_new_disp_form(&as
.adrbks
[booknum
], wps_global
->VAR_ABOOK_FORMATS
, booknum
, NULL
);
13051 (ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, i
));
13054 /* first member is type: Single, List or Lookup */
13062 default : /* not set!?! */
13069 objhv
[0] = Tcl_NewStringObj(ae
->nickname
, -1);
13070 objhv
[1] = Tcl_NewStringObj(s
, -1);
13071 objev
[n
= 0] = Tcl_NewListObj(2, objhv
);
13074 * set fields based on VAR_ABOOK_FORMATS
13077 for(j
= 0; j
< NFIELDS
&& as
.adrbks
[booknum
].disp_form
[j
].type
!= Notused
; j
++){
13078 switch(as
.adrbks
[booknum
].disp_form
[j
].type
){
13080 objev
[++n
] = Tcl_NewStringObj(ae
->nickname
, -1);
13083 objev
[++n
] = Tcl_NewStringObj(ae
->fullname
, -1);
13086 if(ae
->tag
== Single
){
13087 objev
[++n
] = Tcl_NewStringObj(ae
->addr
.addr
, -1);
13092 for(k
= 0; ae
->addr
.list
[k
]; k
++)
13095 objav
= (Tcl_Obj
**) fs_get(k
* sizeof(Tcl_Obj
*));
13096 for(k
= 0; ae
->addr
.list
[k
]; k
++)
13097 objav
[k
] = Tcl_NewStringObj(ae
->addr
.list
[k
], -1);
13099 objev
[++n
] = Tcl_NewListObj(k
, objav
);
13100 fs_give((void **) &objav
);
13104 objev
[++n
] = Tcl_NewStringObj(ae
->fcc
? ae
->fcc
: "", -1);
13107 objev
[++n
] = Tcl_NewStringObj(ae
->extra
? ae
->extra
: "", -1);
13115 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13116 Tcl_NewListObj(n
+ 1, objev
));
13122 snprintf(buf
, sizeof(buf
), "PEAddress list: unknown address book number \"%d\"", booknum
);
13123 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13127 else if(objc
== 4){
13128 if(!strcmp(op
, "verify")){
13130 * The object here is to check the following list of field values
13131 * to see that they are valid address list, expanding if necessary.
13132 * The first argument is the list of field values, with "to" being
13133 * first. The second arg is the current fcc value.
13135 * The return value is of the following form:
13137 * { {{errstr {{oldstr newstr {ldap-opts ...}} ...}} ...} newfcc}
13140 char *addrstr
, *newaddr
= NULL
, *error
= NULL
,
13141 *tstr1
, *tstr2
, *fcc
, *newfcc
= NULL
;
13143 int rv
, badadrs
, i
, numlistvals
,
13144 numldapqueries
= 0;
13145 Tcl_Obj
*resObj
= NULL
, *secObj
, *strObj
, *adrObj
, *res2Obj
;
13149 wpldap_global
->query_no
++;
13150 if(wpldap_global
->ldap_search_list
){
13151 wpldap_global
->ldap_search_list
=
13152 free_wpldapres(wpldap_global
->ldap_search_list
);
13155 tsl
= &(wpldap_global
->ldap_search_list
);
13156 #endif /* ENABLE_LDAP */
13158 if(Tcl_ListObjGetElements(interp
, objv
[2], &numlistvals
,
13159 &objVal
) == TCL_OK
){
13160 if((fcc
= Tcl_GetStringFromObj(objv
[3], NULL
)) == NULL
)
13162 res2Obj
= Tcl_NewListObj(0, NULL
);
13163 for(i
= 0; i
< numlistvals
; i
++){
13166 if((addrstr
= Tcl_GetStringFromObj(objVal
[i
], NULL
)) == NULL
)
13169 addrstr
= cpystr(addrstr
); /* can't munge tcl copy */
13171 toaddr
.arg
.str
= cpystr(addrstr
);
13172 l
= strlen(addrstr
);
13174 resObj
= Tcl_NewListObj(0, NULL
);
13175 secObj
= Tcl_NewListObj(0, NULL
);
13176 for(tstr1
= addrstr
; tstr1
; tstr1
= tstr2
){
13177 tstr2
= strqchr(tstr1
, ',', 0, -1);
13181 strncpy(toaddr
.arg
.str
, tstr1
, l
);
13182 toaddr
.arg
.str
[l
] = '\0';
13184 removing_leading_and_trailing_white_space(toaddr
.arg
.str
);
13185 if(*toaddr
.arg
.str
){
13186 if(i
== 0 && tstr1
== addrstr
)
13187 newfcc
= cpystr(fcc
);
13189 rv
= our_build_address(toaddr
, &newaddr
, &error
, &newfcc
, NULL
);
13192 strObj
= Tcl_NewListObj(0, NULL
);
13193 Tcl_ListObjAppendElement(interp
, strObj
,
13194 Tcl_NewStringObj(toaddr
.arg
.str
, -1));
13195 Tcl_ListObjAppendElement(interp
, strObj
,
13196 Tcl_NewStringObj(newaddr
,-1));
13197 /* append whether or not ldap stuff
13200 adrObj
= Tcl_NewListObj(0,NULL
);
13203 LDAP_CHOOSE_S
*tres
;
13204 LDAP_SERV_RES_S
*trl
;
13209 tres
= (LDAP_CHOOSE_S
*)fs_get(sizeof(LDAP_CHOOSE_S
));
13210 for(trl
= (*tsl
)->reslist
; trl
;
13212 for(e
= ldap_first_entry(trl
->ld
,
13215 e
= ldap_next_entry(trl
->ld
, e
)){
13216 tres
->ld
= trl
->ld
;
13217 tres
->selected_entry
= e
;
13218 tres
->info_used
= trl
->info_used
;
13219 tres
->serv
= trl
->serv
;
13220 if((newadr
= address_from_ldap(tres
)) != NULL
){
13221 if(newadr
->mailbox
&& newadr
->host
){
13225 len
= est_size(newadr
);
13226 ret_to
= (char *)fs_get(len
* sizeof(char));
13228 rbuf
.f
= dummy_soutr
;
13232 rbuf
.end
= ret_to
+len
-1;
13233 rfc822_output_address_list(&rbuf
, newadr
, 0L, NULL
);
13235 Tcl_ListObjAppendElement(interp
,
13236 adrObj
, Tcl_NewStringObj(ret_to
, -1));
13237 fs_give((void **)&ret_to
);
13239 mail_free_address(&newadr
);
13243 fs_give((void **)&tres
);
13245 tsl
= &((*tsl
)->next
);
13247 #endif /* ENABLE_LDAP */
13248 Tcl_ListObjAppendElement(interp
, strObj
, adrObj
);
13249 Tcl_ListObjAppendElement(interp
, secObj
, strObj
);
13261 resObj
= Tcl_NewListObj(0, NULL
);
13262 Tcl_ListObjAppendElement(interp
, resObj
,
13263 Tcl_NewStringObj(badadrs
13264 ? (error
? error
: "Unknown")
13266 Tcl_ListObjAppendElement(interp
, resObj
, secObj
);
13267 Tcl_ListObjAppendElement(interp
, res2Obj
, resObj
);
13268 fs_give((void **) &addrstr
);
13269 fs_give((void **) &toaddr
.arg
.str
);
13271 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), res2Obj
);
13272 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13273 Tcl_NewStringObj(newfcc
? newfcc
13274 : (fcc
? fcc
: ""), -1));
13275 if(newfcc
) fs_give((void **)&newfcc
);
13280 else if(!strcmp(op
, "expand")){
13282 char *addrstr
, *newaddr
= NULL
, *error
= NULL
, *fcc
, *newfcc
= NULL
;
13286 * Return value will be of the form:
13288 * ldap-query-number,
13292 * ldap-query-number will be nonzero if
13293 * there is something interesting to display as a result
13294 * of an ldap query.
13298 * Given what looks like an rfc822 address line, parse the
13299 * contents and expand any tokens that look like they ought
13303 if((addrstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
13305 toaddr
.arg
.str
= cpystr(addrstr
); /* can't munge tcl copy */
13306 fcc
= Tcl_GetStringFromObj(objv
[3], NULL
);
13308 wpldap_global
->query_no
++;
13309 if(wpldap_global
->ldap_search_list
){
13310 wpldap_global
->ldap_search_list
=
13311 free_wpldapres(wpldap_global
->ldap_search_list
);
13313 #endif /* ENABLE_LDAP */
13314 newfcc
= cpystr(fcc
);
13315 rv
= our_build_address(toaddr
, &newaddr
, &error
, &newfcc
, NULL
);
13316 fs_give((void **) &toaddr
.arg
.str
);
13320 * c-client quotes results with spaces in them, so we'll go
13321 * through and unquote them.
13323 if(wpldap_global
->ldap_search_list
){
13325 char *tstr1
, *tstr2
;
13326 char *qstr1
, *newnewaddr
;
13329 for(tres
= wpldap_global
->ldap_search_list
;
13330 tres
; tres
= tres
->next
){
13331 if(strqchr(tres
->str
, ' ', 0, -1)){
13332 qstr1len
= strlen(tres
->str
) + 3;
13333 qstr1
= (char *)fs_get(qstr1len
*sizeof(char));
13334 snprintf(qstr1
, qstr1len
, "\"%.*s\"", qstr1len
, tres
->str
);
13335 for(tstr1
= newaddr
; tstr1
; tstr1
= tstr2
){
13336 tstr2
= strqchr(tstr1
, ',', 0, -1);
13337 if(strncmp(qstr1
, tstr1
, tstr2
? tstr2
- tstr1
13338 : strlen(tstr1
)) == 0){
13340 l
= strlen(newaddr
) + strlen(tres
->str
) + 2
13341 + (tstr2
? strlen(tstr2
) : 0);
13342 newnewaddr
= (char *) fs_get(l
* sizeof(char));
13343 snprintf(newnewaddr
, l
, "%.*s%s%s", (int) (tstr1
- newaddr
),
13344 newaddr
, tres
->str
, tstr2
? tstr2
: "");
13345 fs_give((void **)&newaddr
);
13346 newaddr
= newnewaddr
;
13351 if(tstr2
&& *tstr2
== ' ')
13355 fs_give((void **) &qstr1
);
13359 #endif /* ENABLE_LDAP */
13360 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13361 Tcl_NewStringObj(newaddr
, -1)) != TCL_OK
)
13364 if(wpldap_global
->ldap_search_list
){
13365 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13366 Tcl_NewIntObj(wpldap_global
->query_no
)) != TCL_OK
)
13370 #endif /* ENABLE_LDAP */
13371 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13372 Tcl_NewIntObj(0)) != TCL_OK
)
13374 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13375 Tcl_NewStringObj(newfcc
? newfcc
13376 : (fcc
? fcc
: ""), -1)) != TCL_OK
)
13378 if(newfcc
) fs_give((void **)&newfcc
);
13383 Tcl_SetResult(interp
, error
? error
: "Indeterminate error", TCL_VOLATILE
);
13384 if(newfcc
) fs_give((void **)&newfcc
);
13389 else if(!strcmp(op
, "complete")){
13391 * CMD: complete uid
13393 * Look for possible completions for
13394 * given query_string.
13396 * ARGS: <query_string> <uid>
13398 * Returns: candidate list: {nickname {personal mailbox}}
13400 char *query
, *errstr
;
13402 COMPLETE_S
*completions
, *cp
;
13404 if(peInitAddrbooks(interp
, 0) == TCL_OK
){
13405 if((query
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
13406 if(Tcl_GetLongFromObj(interp
, objv
[3], &uid
) == TCL_OK
){
13408 completions
= adrbk_list_of_completions(query
,
13409 wps_global
->mail_stream
,
13412 ((strlen(query
) >= 5) ? ALC_INCLUDE_LDAP
: 0) |
13413 #endif /* ENABLE_LDAP */
13417 for(cp
= completions
; cp
; cp
= cp
->next
)
13418 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s %s %s",
13419 cp
->nickname
? cp
->nickname
: "",
13420 cp
->full_address
? cp
->full_address
: "",
13421 cp
->fcc
? cp
->fcc
: "");
13423 free_complete_s(&completions
);
13426 Tcl_SetResult(interp
, "", TCL_STATIC
);
13431 errstr
= "PEAddress: Cannot read UID";
13434 errstr
= "PEAddress: Cannot get completion query";
13437 errstr
= "PEAddress: Address Book initialization failed";
13439 Tcl_SetResult(interp
, errstr
, TCL_STATIC
);
13443 else if(objc
== 5){
13444 if(!strcmp(op
, "entry")){
13445 int booknum
, i
, aindex
;
13446 char *nick
, *astr
= NULL
, *errstr
= NULL
, *fccstr
= NULL
, buf
[128];
13450 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13454 * Given an address book handle and nickname, return address
13456 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
)
13457 for(i
= 0; i
< as
.n_addrbk
; i
++)
13459 if((nick
= Tcl_GetStringFromObj(objv
[3], NULL
)) == NULL
){
13460 Tcl_SetResult(interp
, "PEAddress list: Can't get nickname", TCL_STATIC
);
13463 if(Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
13464 || (*nick
== '\0' && aindex
< 0)){
13465 Tcl_SetResult(interp
, "PEAddress list: Can't get aindex", TCL_STATIC
);
13469 ? (ae
= adrbk_lookup_by_nick(as
.adrbks
[booknum
].address_book
, nick
, NULL
))
13470 : (ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, aindex
))){
13472 bldto
.arg
.abe
= ae
;
13474 (void) our_build_address(bldto
, &astr
, &errstr
, &fccstr
, NULL
);
13478 fs_give((void **) &astr
);
13480 Tcl_SetResult(interp
, errstr
, TCL_VOLATILE
);
13488 l
= (4*strlen(astr
) + 1) * sizeof(char);
13489 p
= (char *) fs_get(l
);
13490 if(rfc1522_decode_to_utf8((unsigned char *) p
, l
, astr
) == (unsigned char *) p
){
13491 fs_give((void **) &astr
);
13495 fs_give((void **)&p
);
13500 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13501 Tcl_NewStringObj(astr
, -1));
13502 fs_give((void **) &astr
);
13505 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13506 Tcl_NewStringObj(*fccstr
? fccstr
: "\"\"", -1));
13507 fs_give((void **) &fccstr
);
13510 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13511 Tcl_NewStringObj("", -1));
13514 Tcl_SetResult(interp
, "", TCL_STATIC
);
13519 snprintf(buf
, sizeof(buf
), "PEAddress list: unknown address book ID %d", booknum
);
13520 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13523 else if(!strcmp(op
, "fullentry")){
13524 int booknum
, j
, aindex
;
13529 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13533 * Given an address book handle and nickname, return
13534 * nickname, fullname, address(es), fcc, and comments
13536 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
){
13537 if(booknum
>= 0 && booknum
< as
.n_addrbk
){
13538 if((nick
= Tcl_GetStringFromObj(objv
[3], NULL
)) == NULL
)
13540 if(Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
13541 || (*nick
== '\0' && aindex
< 0))
13544 ? (ae
= adrbk_lookup_by_nick(as
.adrbks
[booknum
].address_book
, nick
, NULL
))
13545 : (ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, aindex
))){
13546 Tcl_ListObjAppendElement(interp
,
13547 Tcl_GetObjResult(interp
),
13548 Tcl_NewStringObj(ae
->nickname
? ae
->nickname
: "", -1));
13549 Tcl_ListObjAppendElement(interp
,
13550 Tcl_GetObjResult(interp
),
13551 Tcl_NewStringObj(ae
->fullname
? ae
->fullname
: "", -1));
13552 resObj
= Tcl_NewListObj(0,NULL
);
13553 if(ae
->tag
== Single
)
13554 Tcl_ListObjAppendElement(interp
,
13556 Tcl_NewStringObj(ae
->addr
.addr
? ae
->addr
.addr
: "", -1));
13558 for(j
= 0; ae
->addr
.list
[j
]; j
++)
13559 Tcl_ListObjAppendElement(interp
, resObj
,
13560 Tcl_NewStringObj(ae
->addr
.list
[j
] ? ae
->addr
.list
[j
] : "", -1));
13562 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), resObj
);
13563 Tcl_ListObjAppendElement(interp
,
13564 Tcl_GetObjResult(interp
),
13565 Tcl_NewStringObj(ae
->fcc
? ae
->fcc
: "", -1));
13566 Tcl_ListObjAppendElement(interp
,
13567 Tcl_GetObjResult(interp
),
13568 Tcl_NewStringObj(ae
->extra
? ae
->extra
: "", -1));
13575 else if(!strcmp(op
, "delete")){
13576 char *nick
, buf
[256];
13577 int booknum
, aindex
;
13578 adrbk_cntr_t old_entry
;
13580 if(peInitAddrbooks(interp
, 0) != TCL_OK
){
13581 snprintf(buf
, sizeof(buf
), "PEAddress delete: couldn't init addressbooks");
13582 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13585 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
){
13586 nick
= Tcl_GetStringFromObj(objv
[3], NULL
);
13587 removing_leading_and_trailing_white_space(nick
);
13591 if(booknum
>= 0 && booknum
< as
.n_addrbk
) {
13592 if(as
.adrbks
[booknum
].access
!= ReadWrite
) return TCL_ERROR
;
13593 ab
= as
.adrbks
[booknum
].address_book
;
13596 snprintf(buf
, sizeof(buf
), "PEAddress delete: Book number out of range");
13597 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13600 if((Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
)
13601 || (*nick
== '\0' && aindex
< 0))
13603 adrbk_check_validity(ab
, 1L);
13604 if(ab
->flags
& FILE_OUTOFDATE
||
13605 (ab
->rd
&& ab
->rd
->flags
& REM_OUTOFDATE
)){
13606 Tcl_SetResult(interp
,
13607 "Address book out of sync. Cannot update at this moment",
13612 snprintf(buf
, sizeof(buf
), "PEAddress delete: No nickname");
13613 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13617 ? (!adrbk_lookup_by_nick(ab
, nick
, &old_entry
))
13618 : ((old_entry
= (adrbk_cntr_t
)aindex
) == -1)){
13619 snprintf(buf
, sizeof(buf
), "PEAddress delete: Nickname \"%.128s\" not found", nick
);
13620 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13623 if(adrbk_delete(ab
, old_entry
, 0, 0, 1, 1)){
13624 snprintf(buf
, sizeof(buf
), "PEAddress delete: Couldn't delete addressbook entry");
13625 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13631 else if((objc
== 10 || objc
== 11) && !strcmp(op
, "edit")){
13632 if(!strcmp(op
, "edit")){
13633 int booknum
, adri
, add
, rv
, aindex
;
13634 char *nick
, *fn
, *fcc
, *comment
, *addrfield
,
13635 buf
[256], **addrs
, *orignick
= NULL
;
13636 AdrBk_Entry
*ae
= NULL
;
13638 adrbk_cntr_t old_entry
= NO_NEXT
, new_entry
;
13640 ADDRESS
*adr
= NULL
;
13643 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13645 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
){
13646 if(as
.adrbks
[booknum
].access
!= ReadWrite
) return TCL_ERROR
;
13647 nick
= Tcl_GetStringFromObj(objv
[3], NULL
);
13648 removing_leading_and_trailing_white_space(nick
);
13649 if(Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
){
13650 Tcl_SetResult(interp
, "No Address Handle", TCL_VOLATILE
);
13653 fn
= Tcl_GetStringFromObj(objv
[5], NULL
);
13654 removing_leading_and_trailing_white_space(fn
);
13655 if(!*fn
) fn
= NULL
;
13656 addrfield
= Tcl_GetStringFromObj(objv
[6], NULL
);
13657 removing_leading_and_trailing_white_space(addrfield
);
13658 if(!*addrfield
) addrfield
= NULL
;
13660 if(Tcl_ListObjGetElements(interp, objv[7], &numlistvals, &objVal) != TCL_OK)
13663 fcc
= Tcl_GetStringFromObj(objv
[7], NULL
);
13664 removing_leading_and_trailing_white_space(fcc
);
13665 if(!*fcc
) fcc
= NULL
;
13666 comment
= Tcl_GetStringFromObj(objv
[8], NULL
);
13667 removing_leading_and_trailing_white_space(comment
);
13668 if(!*comment
) comment
= NULL
;
13669 if(Tcl_GetIntFromObj(interp
, objv
[9], &add
) != TCL_OK
)
13673 * if objc == 11 then that means that they changed the
13674 * value of nick to something else, and this one is the
13677 orignick
= Tcl_GetStringFromObj(objv
[10], NULL
);
13678 removing_leading_and_trailing_white_space(orignick
);
13680 if((addrs
= parse_addrlist(addrfield
)) != NULL
){
13681 int tbuflen
= strlen(addrfield
);
13683 if(!(tbuf
= (char *) fs_get(sizeof(char) * (tbuflen
+128)))){
13684 Tcl_SetResult(interp
, "malloc error", TCL_VOLATILE
);
13685 fs_give((void **) &addrs
);
13688 for(adri
= 0; addrs
[adri
]; adri
++){
13689 if(*(addrs
[adri
])){
13690 wps_global
->c_client_error
[0] = '\0';
13691 strncpy(tbuf
, addrs
[adri
], tbuflen
+128);
13692 tbuf
[tbuflen
+128-1] = '\0';
13693 rfc822_parse_adrlist(&adr
, tbuf
, "@");
13694 if(adr
) mail_free_address(&adr
);
13696 if(wps_global
->c_client_error
[0]){
13697 snprintf(buf
, sizeof(buf
),"Problem with address %.10s%s: %s",
13698 addrs
[adri
], strlen(addrs
[adri
]) > 10 ?
13699 "..." : "", wps_global
->c_client_error
);
13700 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13702 fs_give((void **) &tbuf
);
13703 fs_give((void **) &addrs
);
13708 if(tbuf
) fs_give((void **)&tbuf
);
13712 /* addrs[adri] = NULL; */
13714 if(adri
> 1) tag
= List
;
13717 if(booknum
>= 0 && booknum
< as
.n_addrbk
) {
13718 ab
= as
.adrbks
[booknum
].address_book
;
13722 fs_give((void **) &addrs
);
13725 adrbk_check_validity(ab
, 1L);
13726 if(ab
->flags
& FILE_OUTOFDATE
||
13727 (ab
->rd
&& ab
->rd
->flags
& REM_OUTOFDATE
)){
13728 Tcl_SetResult(interp
,
13729 "Address book out of sync. Cannot update at this moment",
13734 ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, aindex
);
13736 old_entry
= (adrbk_cntr_t
) aindex
;
13739 Tcl_SetResult(interp
, "No Address Handle!", TCL_VOLATILE
);
13743 else if(nick
&& *nick
&& adrbk_lookup_by_nick(ab
, nick
, NULL
)){
13744 snprintf(buf
, sizeof(buf
), "Entry with nickname %.128s already exists.",
13746 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13748 fs_give((void **) &addrs
);
13752 ((tag
== List
&& ae
->tag
== Single
) ||
13753 (tag
== Single
&& ae
->tag
== List
))){
13754 if(adrbk_delete(ab
, old_entry
, 0,0,1,0)){
13755 snprintf(buf
, sizeof(buf
), "Problem updating from %s to %s.",
13756 ae
->tag
== Single
? "Single" : "List",
13757 tag
== List
? "List" : "Single");
13758 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13760 fs_give((void **) &addrs
);
13763 old_entry
= NO_NEXT
;
13765 if((rv
= adrbk_add(ab
, old_entry
,
13768 tag
== List
? (char *)addrs
:
13769 (addrs
&& *addrs
) ? *addrs
: "",
13771 comment
? comment
: "",
13772 tag
, &new_entry
, NULL
, 0, 1,
13773 tag
== List
? 0 : 1)) != 0){
13774 snprintf(buf
, sizeof(buf
), "Couldn't add entry! rv=%d.", rv
);
13775 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13777 fs_give((void **) &addrs
);
13781 adrbk_listdel_all(ab
, new_entry
);
13782 adrbk_nlistadd(ab
, new_entry
, NULL
, NULL
, addrs
, 0, 1, 1);
13786 snprintf(buf
, sizeof(buf
), "Unknown address book ID %d", booknum
);
13787 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13793 Tcl_SetResult(interp
, "PEAddress: unrecognized command", TCL_STATIC
);
13799 peInitAddrbooks(Tcl_Interp
*interp
, int safe
)
13801 if(wps_global
->remote_abook_validity
> 0)
13802 (void)adrbk_check_and_fix_all(safe
, 0, 0);
13804 if(!init_addrbooks(NoDisplay
, 1, 1, 0)){
13805 Tcl_SetResult(interp
, "No Address Book Configured", TCL_STATIC
);
13815 peRuleStatVal(char *str
, int *n
)
13820 if(!strcmp(str
, "either"))
13821 *n
= PAT_STAT_EITHER
;
13822 else if(!strcmp(str
, "yes"))
13824 else if(!strcmp(str
, "no"))
13833 #define RS_RULE_EDIT 0x0001
13834 #define RS_RULE_ADD 0x0002
13835 #define RS_RULE_DELETE 0x0004
13836 #define RS_RULE_SHUFFUP 0x0008
13837 #define RS_RULE_SHUFFDOWN 0x0010
13838 #define RS_RULE_GETPAT 0x0100
13839 #define RS_RULE_FINDPAT 0x0200
13842 peRuleSet(Tcl_Interp
*interp
, Tcl_Obj
**objv
)
13844 char *rule
, *patvar
, *patval
, *actvar
, *actval
, *tstr
, *ruleaction
;
13845 int rno
, nPat
, nPatEmnt
, nAct
, nActEmnt
, i
, rv
= 0;
13846 Tcl_Obj
**objPat
, **objPatEmnt
, **objAct
, **objActEmnt
;
13847 long rflags
= PAT_USE_CHANGED
, aflags
= 0;
13849 PAT_S
*pat
, *new_pat
;
13851 if(!(rule
= Tcl_GetStringFromObj(objv
[0], NULL
)))
13854 if(!(ruleaction
= Tcl_GetStringFromObj(objv
[1], NULL
)))
13857 if(Tcl_GetIntFromObj(interp
, objv
[2], &rno
) == TCL_ERROR
)
13860 if(!(strcmp(rule
, "filter")))
13861 rflags
|= ROLE_DO_FILTER
;
13862 else if(!(strcmp(rule
, "score")))
13863 rflags
|= ROLE_DO_SCORES
;
13864 else if(!(strcmp(rule
, "indexcolor")))
13865 rflags
|= ROLE_DO_INCOLS
;
13869 if(!(strcmp(ruleaction
, "edit"))){
13870 aflags
|= RS_RULE_EDIT
;
13871 aflags
|= RS_RULE_GETPAT
;
13872 aflags
|= RS_RULE_FINDPAT
;
13874 else if(!(strcmp(ruleaction
, "add"))){
13875 aflags
|= RS_RULE_ADD
;
13876 aflags
|= RS_RULE_GETPAT
;
13878 else if(!(strcmp(ruleaction
, "delete"))){
13879 aflags
|= RS_RULE_DELETE
;
13880 aflags
|= RS_RULE_FINDPAT
;
13882 else if(!(strcmp(ruleaction
, "shuffup"))){
13883 aflags
|= RS_RULE_SHUFFUP
;
13884 aflags
|= RS_RULE_FINDPAT
;
13886 else if(!(strcmp(ruleaction
, "shuffdown"))){
13887 aflags
|= RS_RULE_SHUFFDOWN
;
13888 aflags
|= RS_RULE_FINDPAT
;
13890 else return(TCL_ERROR
);
13892 if(aflags
& RS_RULE_FINDPAT
){
13893 if(any_patterns(rflags
, &pstate
)){
13894 for(pat
= first_pattern(&pstate
), i
= 0;
13896 pat
= next_pattern(&pstate
), i
++);
13897 if(i
!= rno
) return(TCL_ERROR
);
13900 if(aflags
& RS_RULE_GETPAT
){
13903 Tcl_ListObjGetElements(interp
, objv
[3], &nPat
, &objPat
);
13904 Tcl_ListObjGetElements(interp
, objv
[4], &nAct
, &objAct
);
13906 new_pat
= (PAT_S
*)fs_get(sizeof(PAT_S
));
13907 memset(new_pat
, 0, sizeof(PAT_S
));
13908 new_pat
->patgrp
= (PATGRP_S
*)fs_get(sizeof(PATGRP_S
));
13909 memset(new_pat
->patgrp
, 0, sizeof(PATGRP_S
));
13910 new_pat
->action
= (ACTION_S
*)fs_get(sizeof(ACTION_S
));
13911 memset(new_pat
->action
, 0, sizeof(ACTION_S
));
13913 /* Set up the pattern group */
13914 for(i
= 0; i
< nPat
; i
++){
13915 Tcl_ListObjGetElements(interp
, objPat
[i
], &nPatEmnt
, &objPatEmnt
);
13916 if(nPatEmnt
!= 2) return(TCL_ERROR
);
13917 patvar
= Tcl_GetStringFromObj(objPatEmnt
[0], NULL
);
13918 patval
= Tcl_GetStringFromObj(objPatEmnt
[1], NULL
);
13919 if(!patvar
|| !patval
) return(TCL_ERROR
);
13923 tstr
= cpystr(patval
);
13924 removing_leading_and_trailing_white_space(tstr
);
13926 fs_give((void **) &tstr
);
13929 if(!(strcmp(patvar
, "nickname"))){
13930 new_pat
->patgrp
->nick
= tstr
;
13933 else if(!(strcmp(patvar
, "comment"))){
13934 new_pat
->patgrp
->comment
= tstr
;
13937 else if(!(strcmp(patvar
, "to"))){
13938 new_pat
->patgrp
->to
= string_to_pattern(tstr
);
13940 else if(!(strcmp(patvar
, "from"))){
13941 new_pat
->patgrp
->from
= string_to_pattern(tstr
);
13943 else if(!(strcmp(patvar
, "sender"))){
13944 new_pat
->patgrp
->sender
= string_to_pattern(tstr
);
13946 else if(!(strcmp(patvar
, "cc"))){
13947 new_pat
->patgrp
->cc
= string_to_pattern(tstr
);
13949 else if(!(strcmp(patvar
, "recip"))){
13950 new_pat
->patgrp
->recip
= string_to_pattern(tstr
);
13952 else if(!(strcmp(patvar
, "partic"))){
13953 new_pat
->patgrp
->partic
= string_to_pattern(tstr
);
13955 else if(!(strcmp(patvar
, "news"))){
13956 new_pat
->patgrp
->news
= string_to_pattern(tstr
);
13958 else if(!(strcmp(patvar
, "subj"))){
13959 new_pat
->patgrp
->subj
= string_to_pattern(tstr
);
13961 else if(!(strcmp(patvar
, "bodytext"))){
13962 new_pat
->patgrp
->bodytext
= string_to_pattern(tstr
);
13964 else if(!(strcmp(patvar
, "alltext"))){
13965 new_pat
->patgrp
->alltext
= string_to_pattern(tstr
);
13967 else if(!(strcmp(patvar
, "keyword"))){
13968 new_pat
->patgrp
->keyword
= string_to_pattern(tstr
);
13970 else if(!(strcmp(patvar
, "charset"))){
13971 new_pat
->patgrp
->charsets
= string_to_pattern(tstr
);
13973 else if(!(strcmp(patvar
, "ftype"))){
13974 if(!tstr
) return(TCL_ERROR
);
13976 if(!(strcmp(tstr
, "any")))
13977 new_pat
->patgrp
->fldr_type
= FLDR_ANY
;
13978 else if(!(strcmp(tstr
, "news")))
13979 new_pat
->patgrp
->fldr_type
= FLDR_NEWS
;
13980 else if(!(strcmp(tstr
, "email")))
13981 new_pat
->patgrp
->fldr_type
= FLDR_EMAIL
;
13982 else if(!(strcmp(tstr
, "specific")))
13983 new_pat
->patgrp
->fldr_type
= FLDR_SPECIFIC
;
13985 free_pat(&new_pat
);
13989 else if(!(strcmp(patvar
, "folder"))){
13990 new_pat
->patgrp
->folder
= string_to_pattern(tstr
);
13992 else if(!(strcmp(patvar
, "stat_new"))){
13993 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_new
)){
13994 free_pat(&new_pat
);
13998 else if(!(strcmp(patvar
, "stat_rec"))){
13999 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_rec
)){
14000 free_pat(&new_pat
);
14004 else if(!(strcmp(patvar
, "stat_del"))){
14005 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_del
)){
14006 free_pat(&new_pat
);
14010 else if(!(strcmp(patvar
, "stat_imp"))){
14011 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_imp
)){
14012 free_pat(&new_pat
);
14016 else if(!(strcmp(patvar
, "stat_ans"))){
14017 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_ans
)){
14018 free_pat(&new_pat
);
14022 else if(!(strcmp(patvar
, "stat_8bitsubj"))){
14023 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_8bitsubj
)){
14024 free_pat(&new_pat
);
14028 else if(!(strcmp(patvar
, "stat_bom"))){
14029 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_bom
)){
14030 free_pat(&new_pat
);
14034 else if(!(strcmp(patvar
, "stat_boy"))){
14035 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_boy
)){
14036 free_pat(&new_pat
);
14040 else if(!(strcmp(patvar
, "age"))){
14041 new_pat
->patgrp
->age
= parse_intvl(tstr
);
14043 else if(!(strcmp(patvar
, "size"))){
14044 new_pat
->patgrp
->size
= parse_intvl(tstr
);
14046 else if(!(strcmp(patvar
, "score"))){
14047 new_pat
->patgrp
->score
= parse_intvl(tstr
);
14049 else if(!(strcmp(patvar
, "addrbook"))){
14051 if(!strcmp(tstr
, "either"))
14052 new_pat
->patgrp
->inabook
= IAB_EITHER
;
14053 else if(!strcmp(tstr
, "yes"))
14054 new_pat
->patgrp
->inabook
= IAB_YES
;
14055 else if(!strcmp(tstr
, "no"))
14056 new_pat
->patgrp
->inabook
= IAB_NO
;
14057 else if(!strcmp(tstr
, "yesspecific"))
14058 new_pat
->patgrp
->inabook
= IAB_SPEC_YES
;
14059 else if(!strcmp(tstr
, "nospecific"))
14060 new_pat
->patgrp
->inabook
= IAB_SPEC_NO
;
14068 free_pat(&new_pat
);
14070 else if(!(strcmp(patvar
, "specificabook"))){
14071 new_pat
->patgrp
->abooks
= string_to_pattern(tstr
);
14073 else if(!(strcmp(patvar
, "headers"))){
14075 int nHdrList
, nHdrPair
, n
;
14076 Tcl_Obj
**objHdrList
, **objHdrPair
;
14078 Tcl_ListObjGetElements(interp
, objPatEmnt
[1], &nHdrList
, &objHdrList
);
14080 for(ahp
= &new_pat
->patgrp
->arbhdr
; *ahp
; ahp
= &(*ahp
)->next
)
14083 for (n
= 0; n
< nHdrList
; n
++){
14087 Tcl_ListObjGetElements(interp
, objHdrList
[n
], &nHdrPair
, &objHdrPair
);
14091 hdrfld
= Tcl_GetStringFromObj(objHdrPair
[0], NULL
);
14092 hdrval
= Tcl_GetStringFromObj(objHdrPair
[1], NULL
);
14095 *ahp
= (ARBHDR_S
*) fs_get(sizeof(ARBHDR_S
));
14096 memset(*ahp
, 0, sizeof(ARBHDR_S
));
14098 (*ahp
)->field
= cpystr(hdrfld
);
14100 (*ahp
)->p
= string_to_pattern(hdrval
);
14103 (*ahp
)->isemptyval
= 1;
14105 ahp
= &(*ahp
)->next
;
14110 free_pat(&new_pat
);
14115 fs_give((void **) &tstr
);
14121 if((new_pat
->patgrp
->inabook
& (IAB_SPEC_YES
| IAB_SPEC_NO
)) == 0
14122 && new_pat
->patgrp
->abooks
)
14123 free_pattern(&new_pat
->patgrp
->abooks
);
14125 if(new_pat
->patgrp
->fldr_type
!= FLDR_SPECIFIC
&& new_pat
->patgrp
->folder
)
14126 free_pattern(&new_pat
->patgrp
->folder
);
14128 /* set up the action */
14129 if(!(strcmp(rule
, "filter")))
14130 new_pat
->action
->is_a_filter
= 1;
14131 else if(!(strcmp(rule
, "role")))
14132 new_pat
->action
->is_a_role
= 1;
14133 else if(!(strcmp(rule
, "score")))
14134 new_pat
->action
->is_a_score
= 1;
14135 else if(!(strcmp(rule
, "indexcolor")))
14136 new_pat
->action
->is_a_incol
= 1;
14138 free_pat(&new_pat
);
14142 for(i
= 0; i
< nAct
; i
++){
14143 Tcl_ListObjGetElements(interp
, objAct
[i
], &nActEmnt
, &objActEmnt
);
14145 free_pat(&new_pat
);
14149 actvar
= Tcl_GetStringFromObj(objActEmnt
[0], NULL
);
14150 actval
= Tcl_GetStringFromObj(objActEmnt
[1], NULL
);
14151 if(!actvar
|| !actval
){
14152 free_pat(&new_pat
);
14156 if(new_pat
->action
->is_a_filter
&& !(strcmp(actvar
, "action"))){
14157 if(!strcmp(actval
, "delete"))
14158 new_pat
->action
->kill
= 1;
14159 else if(!strcmp(actval
, "move"))
14160 new_pat
->action
->kill
= 0;
14162 free_pat(&new_pat
);
14166 else if(new_pat
->action
->is_a_filter
&& !(strcmp(actvar
, "folder"))){
14167 tstr
= cpystr(actval
);
14168 removing_leading_and_trailing_white_space(tstr
);
14169 if(!(*tstr
)) fs_give((void **)&tstr
);
14170 new_pat
->action
->folder
= string_to_pattern(tstr
);
14171 if(tstr
) fs_give((void **)&tstr
);
14173 else if(new_pat
->action
->is_a_filter
&& !(strcmp(actvar
, "moind"))){
14174 if(!strcmp(actval
, "1"))
14175 new_pat
->action
->move_only_if_not_deleted
= 1;
14176 else if(!strcmp(actval
, "0"))
14177 new_pat
->action
->move_only_if_not_deleted
= 0;
14179 free_pat(&new_pat
);
14183 else if(new_pat
->action
->is_a_incol
&& !(strcmp(actvar
, "fg"))){
14184 char asciicolor
[256];
14186 if(ascii_colorstr(asciicolor
, actval
) == 0) {
14187 if(!new_pat
->action
->incol
){
14188 new_pat
->action
->incol
= new_color_pair(asciicolor
,NULL
);
14191 snprintf(new_pat
->action
->incol
->fg
,
14192 sizeof(new_pat
->action
->incol
->fg
), "%s", asciicolor
);
14195 else if(new_pat
->action
->is_a_incol
&& !(strcmp(actvar
, "bg"))){
14196 char asciicolor
[256];
14198 if(ascii_colorstr(asciicolor
, actval
) == 0) {
14199 if(!new_pat
->action
->incol
){
14200 new_pat
->action
->incol
= new_color_pair(NULL
, asciicolor
);
14203 snprintf(new_pat
->action
->incol
->bg
,
14204 sizeof(new_pat
->action
->incol
->bg
), "%s", asciicolor
);
14207 else if(new_pat
->action
->is_a_score
&& !(strcmp(actvar
, "scoreval"))){
14208 long scoreval
= (long) atoi(actval
);
14210 if(scoreval
>= SCORE_MIN
&& scoreval
<= SCORE_MAX
)
14211 new_pat
->action
->scoreval
= scoreval
;
14213 else if(new_pat
->action
->is_a_score
&& !(strcmp(actvar
, "scorehdr"))){
14214 HEADER_TOK_S
*hdrtok
;
14216 if((hdrtok
= stringform_to_hdrtok(actval
)) != NULL
)
14217 new_pat
->action
->scorevalhdrtok
= hdrtok
;
14220 free_pat(&new_pat
);
14225 if(new_pat
->action
->is_a_filter
&& new_pat
->action
->kill
&& new_pat
->action
->folder
)
14226 fs_give((void **)&new_pat
->action
->folder
);
14227 else if(new_pat
->action
->is_a_filter
&& new_pat
->action
->kill
== 0 && new_pat
->action
->folder
== 0){
14228 free_pat(&new_pat
);
14229 Tcl_SetResult(interp
, "No folder set for Move", TCL_VOLATILE
);
14234 if(aflags
& RS_RULE_EDIT
)
14235 rv
= edit_pattern(new_pat
, rno
, rflags
);
14236 else if(aflags
& RS_RULE_ADD
)
14237 rv
= add_pattern(new_pat
, rflags
);
14238 else if(aflags
& RS_RULE_DELETE
)
14239 rv
= delete_pattern(rno
, rflags
);
14240 else if(aflags
& RS_RULE_SHUFFUP
)
14241 rv
= shuffle_pattern(rno
, 1, rflags
);
14242 else if(aflags
& RS_RULE_SHUFFDOWN
)
14243 rv
= shuffle_pattern(rno
, -1, rflags
);
14247 return(rv
? TCL_ERROR
: TCL_OK
);
14253 peAEToAddress(AdrBk_Entry
*ae
)
14255 char *list
, *l1
, *l2
;
14258 ADDRESS
*addr
= NULL
;
14260 if(ae
->tag
== List
){
14262 for(l2
= ae
->addr
.list
; *l2
; l2
++)
14263 length
+= (strlen(*l2
) + 1);
14265 list
= (char *) fs_get(length
+ 1);
14268 for(l2
= ae
->addr
.list
; *l2
; l2
++){
14269 if(l1
!= list
&& l1
-list
< length
+1)
14272 strncpy(l1
, *l2
, length
+1-(l1
-list
));
14276 list
[length
] = '\0';
14279 bldto
.arg
.str
= list
;
14280 adr2
= expand_address(bldto
, userdomain
, localdomain
,
14281 loop_detected
, fcc
, did_set
,
14282 lcc
, error
, 1, simple_verify
,
14285 fs_give((void **) &list
);
14287 else if(ae
->tag
== Single
){
14288 if(strucmp(ae
->addr
.addr
, a
->mailbox
)){
14290 bldto
.arg
.str
= ae
->addr
.addr
;
14291 adr2
= expand_address(bldto
, userdomain
,
14292 localdomain
, loop_detected
,
14294 error
, 1, simple_verify
,
14299 * A loop within plain single entry is ignored.
14300 * Set up so later code thinks we expanded.
14302 adr2
= mail_newaddr();
14303 adr2
->mailbox
= cpystr(ae
->addr
.addr
);
14304 adr2
->host
= cpystr(userdomain
);
14305 adr2
->adl
= cpystr(a
->adl
);
14310 * Personal names: If the expanded address has a personal
14311 * name and the address book entry is a list with a fullname,
14312 * tack the full name from the address book on in front.
14313 * This mainly occurs with a distribution list where the
14314 * list has a full name, and the first person in the list also
14317 * This algorithm doesn't work very well if lists are
14318 * included within lists, but it's not clear what would
14321 if(ae
->fullname
&& ae
->fullname
[0]){
14322 if(adr2
->personal
&& adr2
->personal
[0]){
14323 if(ae
->tag
== List
){
14324 /* combine list name and existing name */
14327 if(!simple_verify
){
14329 l
= strlen(adr2
->personal
) + strlen(ae
->fullname
) + 4;
14330 name
= (char *)fs_get((l
+1) * sizeof(char));
14331 snprintf(name
, l
+1, "%s -- %s", ae
->fullname
,
14333 fs_give((void **)&adr2
->personal
);
14334 adr2
->personal
= name
;
14338 /* replace with nickname fullname */
14339 fs_give((void **)&adr2
->personal
);
14340 adr2
->personal
= adrbk_formatname(ae
->fullname
,
14345 if(abe
-p
>tag
!= List
|| !simple_verify
){
14347 fs_give((void **)&adr2
->personal
);
14349 adr2
->personal
= adrbk_formatname(abe
->fullname
,
14361 peAEFcc(AdrBk_Entry
*ae
)
14365 if(ae
->fcc
&& ae
->fcc
[0]){
14367 if(!strcmp(ae
->fcc
, "\"\""))
14370 fcc
= cpystr(ae
->fcc
);
14373 else if(ae
->nickname
&& ae
->nickname
[0] &&
14374 (wps_global
->fcc_rule
== FCC_RULE_NICK
||
14375 wps_global
->fcc_rule
== FCC_RULE_NICK_RECIP
)){
14377 * else if fcc-rule=fcc-by-nickname, use that
14380 fcc
= cpystr(ae
->nickname
);
14391 extern PINEFIELD
*parse_custom_hdrs(char **, CustomType
);
14393 return(parse_custom_hdrs(wps_global
->VAR_CUSTOM_HDRS
, UseAsDef
));
14399 * PEClistCmd - Collection list editing tools
14402 PEClistCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
14404 char *err
= "Unknown PEClist request";
14406 dprint((2, "PEClistCmd"));
14409 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
14412 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
14415 if(objc
== 3){ /* delete */
14416 if(!strcmp(s1
, "delete")){
14417 int cl
, i
, n
, deln
;
14419 CONTEXT_S
*del_ctxt
, *tmp_ctxt
, *new_ctxt
;
14421 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14422 Tcl_SetResult(interp
,
14423 "cledit malformed: first arg must be int",
14427 for(i
= 0, del_ctxt
= wps_global
->context_list
;
14428 del_ctxt
&& i
< cl
; i
++, del_ctxt
= del_ctxt
->next
);
14429 if(!del_ctxt
) return(TCL_ERROR
);
14430 for(n
= 0; del_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14432 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14434 deln
= del_ctxt
->var
.i
;
14435 for(i
= 0; del_ctxt
->var
.v
->current_val
.l
[i
]; i
++){
14437 newl
[i
] = cpystr(del_ctxt
->var
.v
->current_val
.l
[i
]);
14439 newl
[i
-1] = cpystr(del_ctxt
->var
.v
->current_val
.l
[i
]);
14441 n
= set_variable_list(del_ctxt
->var
.v
- wps_global
->vars
,
14442 *newl
? newl
: NULL
, TRUE
, Main
);
14443 free_list_array(&newl
);
14444 set_current_val(del_ctxt
->var
.v
, TRUE
, FALSE
);
14446 Tcl_SetResult(interp
,
14447 "Error saving changes",
14451 for(tmp_ctxt
= del_ctxt
->next
; tmp_ctxt
&& tmp_ctxt
->var
.v
==
14452 del_ctxt
->var
.v
; tmp_ctxt
= tmp_ctxt
->next
)
14454 if((tmp_ctxt
= del_ctxt
->next
) != NULL
)
14455 tmp_ctxt
->prev
= del_ctxt
->prev
;
14456 if((tmp_ctxt
= del_ctxt
->prev
) != NULL
)
14457 tmp_ctxt
->next
= del_ctxt
->next
;
14458 if(!del_ctxt
->prev
&& !del_ctxt
->next
){
14459 new_ctxt
= new_context(del_ctxt
->var
.v
->current_val
.l
[0], NULL
);
14460 wps_global
->context_list
= new_ctxt
;
14461 if(!new_ctxt
->var
.v
)
14462 new_ctxt
->var
= del_ctxt
->var
;
14464 else if(wps_global
->context_list
== del_ctxt
){
14465 wps_global
->context_list
= del_ctxt
->next
;
14466 if(!wps_global
->context_list
)
14467 return TCL_ERROR
; /* this shouldn't happen */
14469 if(wps_global
->context_last
== del_ctxt
)
14470 wps_global
->context_last
= NULL
;
14471 if(wps_global
->context_current
== del_ctxt
){
14472 strncpy(wps_global
->cur_folder
,
14473 wps_global
->mail_stream
->mailbox
,
14474 sizeof(wps_global
->cur_folder
));
14475 wps_global
->cur_folder
[sizeof(wps_global
->cur_folder
)-1] = '\0';
14476 wps_global
->context_current
= wps_global
->context_list
;
14478 del_ctxt
->prev
= NULL
;
14479 del_ctxt
->next
= NULL
;
14480 free_context(&del_ctxt
);
14481 init_inbox_mapping(wps_global
->VAR_INBOX_PATH
,
14482 wps_global
->context_list
);
14485 else if(!strcmp(s1
, "shuffdown")){
14487 CONTEXT_S
*sh_ctxt
, *nsh_ctxt
, *tctxt
;
14488 char **newl
, *tmpch
;
14490 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14491 Tcl_SetResult(interp
,
14492 "cledit malformed: first arg must be int",
14496 for(sh_ctxt
= wps_global
->context_list
, i
= 0;
14497 sh_ctxt
&& i
< cl
; i
++, sh_ctxt
= sh_ctxt
->next
);
14498 if(!sh_ctxt
|| !sh_ctxt
->next
){
14499 Tcl_SetResult(interp
,
14500 "invalid context list number",
14504 if(sh_ctxt
->var
.v
== sh_ctxt
->next
->var
.v
){
14505 shn
= sh_ctxt
->var
.i
;
14506 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14507 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14509 for(i
= 0; sh_ctxt
->var
.v
->current_val
.l
[i
]; i
++){
14511 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
+1]);
14512 else if(i
== shn
+ 1)
14513 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14515 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14517 n
= set_variable_list(sh_ctxt
->var
.v
- wps_global
->vars
,
14519 free_list_array(&newl
);
14520 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14522 Tcl_SetResult(interp
,
14523 "Error saving changes",
14527 nsh_ctxt
= sh_ctxt
->next
;
14532 nsh_ctxt
= sh_ctxt
->next
;
14533 shn
= sh_ctxt
->var
.i
;
14534 tmpch
= cpystr(sh_ctxt
->var
.v
->current_val
.l
[shn
]);
14535 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14537 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14539 for(i
= 0; sh_ctxt
->var
.v
->current_val
.l
[i
+1]; i
++)
14540 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14541 n
= set_variable_list(sh_ctxt
->var
.v
- wps_global
->vars
,
14542 newl
, FALSE
, Main
);
14543 free_list_array(&newl
);
14544 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14545 for(n
= 0; nsh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14547 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14549 newl
[0] = cpystr(nsh_ctxt
->var
.v
->current_val
.l
[0]);
14551 for(i
= 2; nsh_ctxt
->var
.v
->current_val
.l
[i
-1]; i
++)
14552 newl
[i
] = cpystr(nsh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14553 n
= set_variable_list(nsh_ctxt
->var
.v
- wps_global
->vars
,
14555 free_list_array(&newl
);
14556 set_current_val(nsh_ctxt
->var
.v
, TRUE
, FALSE
);
14557 sh_ctxt
->var
.v
= nsh_ctxt
->var
.v
;
14558 sh_ctxt
->var
.i
= 1;
14559 /* this for loop assumes that there are only two variable lists,
14560 * folder-collections and news-collections, a little more will
14561 * have to be done if we want to accommodate for the INHERIT
14562 * option introduced in 4.30.
14564 for(tctxt
= nsh_ctxt
->next
; tctxt
; tctxt
= tctxt
->next
)
14567 if(sh_ctxt
->prev
) sh_ctxt
->prev
->next
= nsh_ctxt
;
14568 nsh_ctxt
->prev
= sh_ctxt
->prev
;
14569 sh_ctxt
->next
= nsh_ctxt
->next
;
14570 nsh_ctxt
->next
= sh_ctxt
;
14571 sh_ctxt
->prev
= nsh_ctxt
;
14572 if(sh_ctxt
->next
) sh_ctxt
->next
->prev
= sh_ctxt
;
14573 if(wps_global
->context_list
== sh_ctxt
)
14574 wps_global
->context_list
= nsh_ctxt
;
14575 init_inbox_mapping(wps_global
->VAR_INBOX_PATH
,
14576 wps_global
->context_list
);
14579 else if(!strcmp(s1
, "shuffup")){
14581 CONTEXT_S
*sh_ctxt
, *psh_ctxt
, *tctxt
;
14582 char **newl
, *tmpch
;
14584 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14585 Tcl_SetResult(interp
,
14586 "cledit malformed: first arg must be int",
14590 for(sh_ctxt
= wps_global
->context_list
, i
= 0;
14591 sh_ctxt
&& i
< cl
; i
++, sh_ctxt
= sh_ctxt
->next
);
14592 if(!sh_ctxt
|| !sh_ctxt
->prev
){
14593 Tcl_SetResult(interp
,
14594 "invalid context list number",
14598 if(sh_ctxt
->var
.v
== sh_ctxt
->prev
->var
.v
){
14599 shn
= sh_ctxt
->var
.i
;
14600 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14601 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14603 for(i
= 0; sh_ctxt
->var
.v
->current_val
.l
[i
]; i
++){
14605 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14606 else if(i
== shn
- 1)
14607 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
+1]);
14609 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14611 i
= set_variable_list(sh_ctxt
->var
.v
- wps_global
->vars
,
14613 free_list_array(&newl
);
14614 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14616 Tcl_SetResult(interp
,
14617 "Error saving changes",
14621 psh_ctxt
= sh_ctxt
->prev
;
14626 psh_ctxt
= sh_ctxt
->prev
;
14627 shn
= sh_ctxt
->var
.i
;
14628 tmpch
= cpystr(sh_ctxt
->var
.v
->current_val
.l
[shn
]);
14629 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14631 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14633 for(i
= 1; sh_ctxt
->var
.v
->current_val
.l
[i
]; i
++)
14634 newl
[i
-1] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14635 i
= set_variable_list(sh_ctxt
->var
.v
- wps_global
->vars
,
14636 newl
, FALSE
, Main
);
14637 free_list_array(&newl
);
14639 Tcl_SetResult(interp
,
14640 "Error saving changes",
14644 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14645 for(n
= 0; psh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14647 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14649 for(i
= 0; psh_ctxt
->var
.v
->current_val
.l
[i
+1]; i
++)
14650 newl
[i
] = cpystr(psh_ctxt
->var
.v
->current_val
.l
[i
]);
14652 newl
[i
] = cpystr(psh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14653 i
= set_variable_list(psh_ctxt
->var
.v
- wps_global
->vars
,
14655 free_list_array(&newl
);
14657 Tcl_SetResult(interp
,
14658 "Error saving changes",
14662 set_current_val(psh_ctxt
->var
.v
, TRUE
, FALSE
);
14663 for(tctxt
= sh_ctxt
->next
; tctxt
; tctxt
= tctxt
->next
)
14665 sh_ctxt
->var
.v
= psh_ctxt
->var
.v
;
14666 sh_ctxt
->var
.i
= n
- 2;
14667 /* There MUST be at least 2 collections in the list */
14670 if(sh_ctxt
->next
) sh_ctxt
->next
->prev
= psh_ctxt
;
14671 psh_ctxt
->next
= sh_ctxt
->next
;
14672 sh_ctxt
->prev
= psh_ctxt
->prev
;
14673 psh_ctxt
->prev
= sh_ctxt
;
14674 sh_ctxt
->next
= psh_ctxt
;
14675 if(sh_ctxt
->prev
) sh_ctxt
->prev
->next
= sh_ctxt
;
14676 if(wps_global
->context_list
== psh_ctxt
)
14677 wps_global
->context_list
= sh_ctxt
;
14678 init_inbox_mapping(wps_global
->VAR_INBOX_PATH
,
14679 wps_global
->context_list
);
14683 else if(objc
== 7){
14684 if(!strcmp(s1
, "edit") || !strcmp(s1
, "add")){
14685 int cl
, quotes_needed
= 0, i
, add
= 0, n
= 0;
14686 char *nick
, *server
, *path
, *view
,
14687 context_buf
[MAILTMPLEN
*4], **newl
;
14688 CONTEXT_S
*new_ctxt
, *tmp_ctxt
;
14690 if(!strcmp(s1
, "add")) add
= 1;
14692 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14693 Tcl_SetResult(interp
,
14694 "cledit malformed: first arg must be int",
14698 if(!(nick
= Tcl_GetStringFromObj(objv
[3], NULL
))){
14699 Tcl_SetResult(interp
,
14704 if(!(server
= Tcl_GetStringFromObj(objv
[4], NULL
))){
14705 Tcl_SetResult(interp
,
14710 if(!(path
= Tcl_GetStringFromObj(objv
[5], NULL
))){
14711 Tcl_SetResult(interp
,
14716 if(!(view
= Tcl_GetStringFromObj(objv
[6], NULL
))){
14717 Tcl_SetResult(interp
,
14722 removing_leading_and_trailing_white_space(nick
);
14723 removing_leading_and_trailing_white_space(server
);
14724 removing_leading_and_trailing_white_space(path
);
14725 removing_leading_and_trailing_white_space(view
);
14726 if(strchr(nick
, ' '))
14728 if(strlen(nick
)+strlen(server
)+strlen(path
)+strlen(view
) >
14729 MAILTMPLEN
* 4 - 20) { /* for good measure */
14730 Tcl_SetResult(interp
,
14736 if(3 + strlen(nick
) + strlen(server
) + strlen(path
) +
14737 strlen(view
) > MAILTMPLEN
+ 4){
14738 Tcl_SetResult(interp
,
14739 "collection fields too long",
14743 snprintf(context_buf
, sizeof(context_buf
), "%s%s%s%s%s%s[%s]", quotes_needed
?
14744 "\"" : "", nick
, quotes_needed
? "\"" : "",
14745 strlen(nick
) ? " " : "",
14746 server
, path
, view
);
14747 new_ctxt
= new_context(context_buf
, NULL
);
14749 for(tmp_ctxt
= wps_global
->context_list
, i
= 0;
14750 tmp_ctxt
&& i
< cl
; i
++, tmp_ctxt
= tmp_ctxt
->next
);
14752 Tcl_SetResult(interp
,
14753 "invalid context list number",
14757 new_ctxt
->next
= tmp_ctxt
->next
;
14758 new_ctxt
->prev
= tmp_ctxt
->prev
;
14759 if(tmp_ctxt
->prev
&& tmp_ctxt
->prev
->next
== tmp_ctxt
)
14760 tmp_ctxt
->prev
->next
= new_ctxt
;
14761 if(tmp_ctxt
->next
&& tmp_ctxt
->next
->prev
== tmp_ctxt
)
14762 tmp_ctxt
->next
->prev
= new_ctxt
;
14763 if(wps_global
->context_list
== tmp_ctxt
)
14764 wps_global
->context_list
= new_ctxt
;
14765 if(wps_global
->context_current
== tmp_ctxt
){
14766 strncpy(wps_global
->cur_folder
,
14767 wps_global
->mail_stream
->mailbox
,
14768 sizeof(wps_global
->cur_folder
));
14769 wps_global
->cur_folder
[sizeof(wps_global
->cur_folder
)-1] = '\0';
14770 wps_global
->context_current
= new_ctxt
;
14772 if(wps_global
->context_last
== tmp_ctxt
)
14773 wps_global
->context_last
= new_ctxt
;
14774 new_ctxt
->var
= tmp_ctxt
->var
;
14775 tmp_ctxt
->next
= tmp_ctxt
->prev
= NULL
;
14776 free_context(&tmp_ctxt
);
14779 for(tmp_ctxt
= wps_global
->context_list
;
14780 tmp_ctxt
->next
; tmp_ctxt
= tmp_ctxt
->next
);
14781 new_ctxt
->prev
= tmp_ctxt
;
14782 tmp_ctxt
->next
= new_ctxt
;
14783 new_ctxt
->var
.v
= tmp_ctxt
->var
.v
;
14784 new_ctxt
->var
.i
= tmp_ctxt
->var
.i
+ 1;
14786 if(!new_ctxt
->var
.v
){
14787 Tcl_SetResult(interp
,
14792 for(n
= 0; new_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14794 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14796 for(n
= 0; new_ctxt
->var
.v
->current_val
.l
[n
]; n
++)
14797 newl
[n
] = (n
== new_ctxt
->var
.i
)
14798 ? cpystr(context_buf
)
14799 : cpystr(new_ctxt
->var
.v
->current_val
.l
[n
]);
14800 if(add
) newl
[n
++] = cpystr(context_buf
);
14801 n
= set_variable_list(new_ctxt
->var
.v
- wps_global
->vars
,
14803 free_list_array(&newl
);
14804 set_current_val(new_ctxt
->var
.v
, TRUE
, FALSE
);
14805 init_inbox_mapping(wps_global
->VAR_INBOX_PATH
,
14806 wps_global
->context_list
);
14808 Tcl_SetResult(interp
,
14809 "Error saving changes",
14819 Tcl_SetResult(interp
, err
, TCL_STATIC
);
14825 * peTakeaddr - Take Address
14828 peTakeaddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
14830 TA_S
*talist
= NULL
, *current
, *head
;
14831 Tcl_Obj
*itemObj
, *secObj
= NULL
, *resObj
= NULL
;
14834 mn_set_cur(sp_msgmap(wps_global
->mail_stream
), peMessageNumber(uid
));
14836 if(set_up_takeaddr('a', wps_global
, sp_msgmap(wps_global
->mail_stream
),
14837 &talist
, &anum
, TA_NOPROMPT
, NULL
) < 0
14838 || (talist
== NULL
)){
14839 Tcl_SetResult(interp
,
14840 "Take address failed to set up",
14845 for(head
= talist
; head
->prev
; head
= head
->prev
);
14847 * Return value will be of the form:
14849 * { "line to print",
14850 * {"personal", "mailbox", "host"} # addr
14851 * {"nick", "fullname", "fcc", "comment"} # suggested
14856 * The two list items will be empty if that line is
14857 * just informational.
14859 itemObj
= Tcl_NewListObj(0, NULL
);
14860 for(current
= head
; current
; current
= current
->next
){
14861 if(current
->skip_it
&& !current
->print
) continue;
14862 secObj
= Tcl_NewListObj(0, NULL
);
14863 if(Tcl_ListObjAppendElement(interp
, secObj
,
14864 Tcl_NewStringObj(current
->strvalue
,-1)) != TCL_OK
)
14866 resObj
= Tcl_NewListObj(0, NULL
);
14867 /* append the address information */
14868 if(current
->addr
&& !current
->print
){
14869 if(Tcl_ListObjAppendElement(interp
, resObj
,
14870 Tcl_NewStringObj(current
->addr
->personal
14871 ? current
->addr
->personal
14872 : "", -1)) != TCL_OK
)
14874 if(Tcl_ListObjAppendElement(interp
, resObj
,
14875 Tcl_NewStringObj(current
->addr
->mailbox
14876 ? current
->addr
->mailbox
14877 : "", -1)) != TCL_OK
)
14879 if(Tcl_ListObjAppendElement(interp
, resObj
,
14880 Tcl_NewStringObj(current
->addr
->host
14881 ? current
->addr
->host
14882 : "", -1)) != TCL_OK
)
14885 if(Tcl_ListObjAppendElement(interp
, secObj
,
14888 resObj
= Tcl_NewListObj(0, NULL
);
14889 /* append the suggested possible entries */
14891 && (current
->nickname
|| current
->fullname
14892 || current
->fcc
|| current
->comment
)){
14893 if(Tcl_ListObjAppendElement(interp
, resObj
,
14894 Tcl_NewStringObj(current
->nickname
14895 ? current
->nickname
14896 : "", -1)) != TCL_OK
)
14898 if(Tcl_ListObjAppendElement(interp
, resObj
,
14899 Tcl_NewStringObj(current
->fullname
14900 ? current
->fullname
14901 : "", -1)) != TCL_OK
)
14903 if(Tcl_ListObjAppendElement(interp
, resObj
,
14904 Tcl_NewStringObj(current
->fcc
14906 : "", -1)) != TCL_OK
)
14908 if(Tcl_ListObjAppendElement(interp
, resObj
,
14909 Tcl_NewStringObj(current
->comment
14911 : "", -1)) != TCL_OK
)
14914 if(Tcl_ListObjAppendElement(interp
, secObj
, resObj
) != TCL_OK
)
14916 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
14921 free_talines(&talist
);
14927 * peTakeFrom - Take only From Address
14930 peTakeFrom(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
14939 * Return value will be of the form:
14941 * { "line to print",
14942 * {"personal", "mailbox", "host"} # addr
14943 * {"nick", "fullname", "fcc", "comment"} # suggested
14948 * The two list items will be empty if that line is
14949 * just informational.
14953 if((env
= pine_mail_fetchstructure(wps_global
->mail_stream
,
14954 rawno
= peSequenceNumber(uid
),
14956 /* append the address information */
14957 for(ap
= env
->from
; ap
; ap
= ap
->next
){
14958 objItem
= Tcl_NewListObj(0, NULL
);
14959 /* append EMPTY "line to print" */
14960 if(Tcl_ListObjAppendElement(interp
, objItem
, Tcl_NewStringObj("",-1)) != TCL_OK
)
14963 /* append address info */
14964 peAppListF(interp
, objItem
, "%s%s%s",
14965 ap
->personal
? (char *) rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf
, SIZEOF_20KBUF
, ap
->personal
) : "",
14966 ap
->mailbox
? ap
->mailbox
: "",
14967 ap
->host
? ap
->host
: "");
14969 /* append suggested info */
14970 peAddSuggestedContactInfo(interp
, objItem
, ap
);
14972 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objItem
) != TCL_OK
)
14979 err
= wps_global
->last_error
;
14982 err
= "Invalid UID";
14989 peAddSuggestedContactInfo(Tcl_Interp
*interp
, Tcl_Obj
*lobjp
, ADDRESS
*addr
)
14991 char *nick
= NULL
, *full
= NULL
, *fcc
= NULL
, *comment
= NULL
;
14993 get_contactinfo_from_addr(addr
, &nick
, &full
, &fcc
, &comment
);
14995 peAppListF(interp
, lobjp
, "%s%s%s%s",
14999 comment
? comment
: "");
15002 fs_give((void **) &nick
);
15005 fs_give((void **) &full
);
15008 fs_give((void **) &fcc
);
15011 fs_give((void **) &comment
);
15017 /* * * * * * * * * Status message ring management * * * * * * * * * * * * */
15020 sml_newmsg(int priority
, char *text
)
15022 static long id
= 1;
15025 smp
= (STATMSG_S
*) fs_get(sizeof(STATMSG_S
));
15026 memset(smp
, 0, sizeof(STATMSG_S
));
15028 smp
->posted
= time(0);
15029 smp
->type
= priority
;
15030 smp
->text
= cpystr(text
);
15036 sml_addmsg(int priority
, char *text
)
15038 STATMSG_S
*smp
= sml_newmsg(priority
, text
);
15041 smp
->next
= peStatList
;
15054 char **retstrs
= NULL
, **tmpstrs
;
15056 for(n
= 0, smp
= peStatList
; smp
&& !smp
->seen
; n
++, smp
= smp
->next
)
15059 if(n
== 0) return NULL
;
15060 retstrs
= (char **)fs_get((n
+1)*sizeof(char *));
15061 for(tmpstrs
= retstrs
, smp
= peStatList
; smp
&& !smp
->seen
; smp
= smp
->next
){
15062 *tmpstrs
= smp
->text
;
15074 return(peStatList
? peStatList
->text
: "");
15082 for(smp
= peStatList
; smp
; smp
= smp
->next
)
15088 /* * * * * * * * * LDAP Support Routines * * * * * * * * * * * */
15092 * PELdapCmd - LDAP TCL interface
15095 PELdapCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
15097 #ifndef ENABLE_LDAP
15098 char *err
= "Call to PELdap when LDAP not enabled";
15100 char *err
= "Unknown PELdap request";
15103 dprint((2, "PELdapCmd"));
15106 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15107 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15110 s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
15114 if(!strcmp(s1
, "directories")){
15120 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15121 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15124 if(wps_global
->VAR_LDAP_SERVERS
){
15125 for(i
= 0; wps_global
->VAR_LDAP_SERVERS
[i
] &&
15126 wps_global
->VAR_LDAP_SERVERS
[i
][0]; i
++){
15127 info
= break_up_ldap_server(wps_global
->VAR_LDAP_SERVERS
[i
]);
15128 secObj
= Tcl_NewListObj(0, NULL
);
15129 if(Tcl_ListObjAppendElement(interp
, secObj
,
15130 Tcl_NewStringObj(info
->nick
? info
->nick
15131 : "", -1)) != TCL_OK
)
15133 if(Tcl_ListObjAppendElement(interp
, secObj
,
15134 Tcl_NewStringObj(info
->serv
? info
->serv
15135 : "", -1)) != TCL_OK
)
15139 free_ldap_server_info(&info
);
15140 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15146 Tcl_SetResult(interp
, "", TCL_STATIC
);
15150 else if(!strcmp(s1
, "query")){
15152 char *srchstr
, *filtstr
;
15153 LDAP_CHOOSE_S
*winning_e
= NULL
;
15154 LDAP_SERV_RES_S
*results
= NULL
;
15156 CUSTOM_FILT_S
*filter
= NULL
;
15159 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15160 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15163 if(Tcl_GetIntFromObj(interp
, objv
[2], &dir
) == TCL_ERROR
){
15164 Tcl_SetResult(interp
,
15165 "PELdap results malformed: first arg must be int",
15169 wpldap_global
->query_no
++;
15170 if(wpldap_global
->ldap_search_list
){
15171 wpldap_global
->ldap_search_list
=
15172 free_wpldapres(wpldap_global
->ldap_search_list
);
15174 srchstr
= Tcl_GetStringFromObj(objv
[3], NULL
);
15175 filtstr
= Tcl_GetStringFromObj(objv
[4], NULL
);
15176 if(!srchstr
) return(TCL_ERROR
);
15177 if(!filtstr
) return(TCL_ERROR
);
15179 filter
= (CUSTOM_FILT_S
*)fs_get(sizeof(CUSTOM_FILT_S
));
15180 filter
->filt
= cpystr(filtstr
);
15181 filter
->combine
= 0;
15183 memset(&wp_err
, 0, sizeof(wp_err
));
15184 ldap_lookup_all(srchstr
, dir
, 0, AlwaysDisplay
, filter
, &winning_e
,
15185 &wp_err
, &results
);
15187 fs_give((void **)&filter
->filt
);
15188 fs_give((void **)&filter
);
15190 Tcl_SetResult(interp
, int2string(wpldap_global
->ldap_search_list
15191 ? wpldap_global
->query_no
: 0),
15196 * First argument has always got to be the query number for now.
15197 * Might need to rething that when setting up queries.
15200 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15201 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15204 if(Tcl_GetIntFromObj(interp
, objv
[2], &qn
) == TCL_ERROR
){
15205 Tcl_SetResult(interp
,
15206 "PELdap results malformed: first arg must be int",
15210 if(qn
!= wpldap_global
->query_no
){
15211 Tcl_SetResult(interp
,
15212 "Query is no longer valid", TCL_VOLATILE
);
15216 if(!strcmp(s1
, "results")){
15217 return(peLdapQueryResults(interp
));
15220 else if(objc
== 4){
15221 if(!strcmp(s1
, "ldapext")){
15223 * Returns a list of the form:
15224 * {"dn" {{attrib {val, ...}}, ...}}
15226 char *whichrec
= Tcl_GetStringFromObj(objv
[3], NULL
);
15227 char *tmpstr
, *tmp
, *tmp2
, *a
;
15228 struct berval
**vals
;
15229 WPLDAPRES_S
*curres
;
15230 LDAP_CHOOSE_S
*winning_e
= NULL
;
15231 LDAP_SERV_RES_S
*trl
;
15232 Tcl_Obj
*secObj
= NULL
, *resObj
= NULL
, *itemObj
;
15235 int i
, j
, whichi
, whichj
;
15237 if(whichrec
== NULL
){
15238 Tcl_SetResult(interp
, "Ldap ldapext error 1", TCL_VOLATILE
);
15241 tmpstr
= cpystr(whichrec
);
15243 for(tmp2
= tmp
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15245 Tcl_SetResult(interp
, "Ldap ldapext error 2", TCL_VOLATILE
);
15249 whichi
= atoi(tmp
);
15252 for(tmp
= tmp2
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15254 Tcl_SetResult(interp
, "Ldap ldapext error 3", TCL_VOLATILE
);
15257 whichj
= atoi(tmp
);
15258 fs_give((void **)&tmpstr
);
15259 for(curres
= wpldap_global
->ldap_search_list
, i
= 0;
15260 i
< whichi
&& curres
; i
++, curres
= curres
->next
);
15262 Tcl_SetResult(interp
, "Ldap ldapext error 4", TCL_VOLATILE
);
15265 for(trl
= curres
->reslist
, j
= 0; trl
; trl
= trl
->next
){
15266 for(e
= ldap_first_entry(trl
->ld
, trl
->res
);
15267 e
!= NULL
&& j
< whichj
;
15268 e
= ldap_next_entry(trl
->ld
, e
), j
++);
15269 if(e
!= NULL
&& j
== whichj
)
15272 if(e
== NULL
|| trl
== NULL
){
15273 Tcl_SetResult(interp
, "Ldap ldapext error 5", TCL_VOLATILE
);
15276 winning_e
= (LDAP_CHOOSE_S
*)fs_get(sizeof(LDAP_CHOOSE_S
));
15277 winning_e
->ld
= trl
->ld
;
15278 winning_e
->selected_entry
= e
;
15279 winning_e
->info_used
= trl
->info_used
;
15280 winning_e
->serv
= trl
->serv
;
15281 a
= ldap_get_dn(winning_e
->ld
, winning_e
->selected_entry
);
15282 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15283 Tcl_NewStringObj(a
? a
: "", -1)) != TCL_OK
)
15286 our_ldap_dn_memfree(a
);
15288 itemObj
= Tcl_NewListObj(0, NULL
);
15289 for(a
= ldap_first_attribute(winning_e
->ld
, winning_e
->selected_entry
, &ber
);
15291 a
= ldap_next_attribute(winning_e
->ld
, winning_e
->selected_entry
, ber
)){
15293 secObj
= Tcl_NewListObj(0, NULL
);
15294 if(Tcl_ListObjAppendElement(interp
, secObj
,
15295 Tcl_NewStringObj(ldap_translate(a
,
15296 winning_e
->info_used
), -1)) != TCL_OK
)
15298 resObj
= Tcl_NewListObj(0, NULL
);
15299 vals
= ldap_get_values_len(winning_e
->ld
, winning_e
->selected_entry
, a
);
15301 for(i
= 0; vals
[i
]; i
++){
15302 if(Tcl_ListObjAppendElement(interp
, resObj
,
15303 Tcl_NewStringObj(vals
[i
]->bv_val
, -1)) != TCL_OK
)
15306 ldap_value_free_len(vals
);
15307 if(Tcl_ListObjAppendElement(interp
, secObj
, resObj
) != TCL_OK
)
15310 if(!strcmp(a
,"objectclass")){
15311 if(Tcl_ListObjAppendElement(interp
, secObj
,
15312 Tcl_NewStringObj("objectclass", -1)) != TCL_OK
)
15315 if(Tcl_ListObjAppendElement(interp
, itemObj
, secObj
) != TCL_OK
)
15318 our_ldap_memfree(a
);
15321 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15322 itemObj
) != TCL_OK
)
15325 fs_give((void **)&winning_e
);
15329 else if(objc
== 6){
15330 if(!strcmp(s1
, "setaddrs")){
15331 char *listset
= Tcl_GetStringFromObj(objv
[3], NULL
);
15332 char *addrstr
= Tcl_GetStringFromObj(objv
[4], NULL
);
15333 char *tmp
, *tmp2
, *tmplistset
, was_char
, *ret_to
,
15335 int **lset
, noreplace
= 0;
15336 ADDRESS
*adr
= NULL
, *curadr
, *prevadr
, *newadr
,
15337 *curnewadr
, *newadrs
;
15338 int curi
, i
, j
, numsrchs
, numset
, setit
;
15339 LDAP_CHOOSE_S
*tres
;
15340 LDAP_SERV_RES_S
*trl
;
15341 WPLDAPRES_S
*curres
;
15346 if(Tcl_GetIntFromObj(interp
, objv
[5], &noreplace
) == TCL_ERROR
){
15347 Tcl_SetResult(interp
,
15348 "PELdap results malformed: first arg must be int",
15352 if(listset
== NULL
|| addrstr
== NULL
) return TCL_ERROR
;
15353 tmpaddrstr
= cpystr(addrstr
);
15356 mail_parameters(NIL
, SET_PARSEPHRASE
, (void *)massage_phrase_addr
);
15357 rfc822_parse_adrlist(&adr
, tmpaddrstr
, "@");
15358 mail_parameters(NIL
, SET_PARSEPHRASE
, NULL
);
15361 tmplistset
= cpystr(listset
);
15362 for(curres
= wpldap_global
->ldap_search_list
, numsrchs
= 0;
15363 curres
; curres
= curres
->next
, numsrchs
++);
15364 lset
= (int **)fs_get((numsrchs
+1)*sizeof(int *));
15365 for(i
= 0; i
< numsrchs
; i
++){
15366 for(tmp
= tmplistset
, numset
= 0; *tmp
;){
15367 for(tmp2
= tmp
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15369 Tcl_SetResult(interp
, "Ldap error 1", TCL_VOLATILE
);
15372 if(atoi(tmp
) == i
) numset
++;
15374 for(tmp
= tmp2
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15375 if(*tmp2
!= ',' && *tmp2
!= '\0'){
15376 Tcl_SetResult(interp
, "Ldap error 2", TCL_VOLATILE
);
15382 lset
[i
] = (int *)fs_get((numset
+1)*sizeof(int));
15383 for(tmp
= tmplistset
, j
= 0; *tmp
&& j
< numset
;){
15385 for(tmp2
= tmp
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15387 Tcl_SetResult(interp
, "Ldap error 3", TCL_VOLATILE
);
15391 if(atoi(tmp
) == i
) setit
++;
15394 for(tmp
= tmp2
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15395 if(*tmp2
!= ',' && *tmp2
!= '\0'){
15396 Tcl_SetResult(interp
, "Ldap error 4", TCL_VOLATILE
);
15402 lset
[i
][j
++] = atoi(tmp
);
15411 for(i
= 0, curres
= wpldap_global
->ldap_search_list
;
15412 i
< numsrchs
&& curres
; i
++, curres
= curres
->next
){
15414 for(curadr
= adr
; curadr
; curadr
= curadr
->next
){
15415 if(strcmp(curadr
->mailbox
, curres
->str
) == 0
15416 && curadr
->host
&& *curadr
->host
== '@')
15420 if(!curadr
&& !noreplace
){
15421 Tcl_SetResult(interp
, "Ldap error 5", TCL_VOLATILE
);
15424 newadrs
= newadr
= curnewadr
= NULL
;
15425 for(trl
= curres
->reslist
, j
= 0, curi
= 0; trl
; trl
= trl
->next
){
15426 for(e
= ldap_first_entry(trl
->ld
, trl
->res
);
15427 e
!= NULL
&& lset
[i
][curi
] != -1;
15428 e
= ldap_next_entry(trl
->ld
, e
), j
++){
15429 if(j
== lset
[i
][curi
]){
15430 tres
= (LDAP_CHOOSE_S
*)fs_get(sizeof(LDAP_CHOOSE_S
));
15431 tres
->ld
= trl
->ld
;
15432 tres
->selected_entry
= e
;
15433 tres
->info_used
= trl
->info_used
;
15434 tres
->serv
= trl
->serv
;
15435 newadr
= address_from_ldap(tres
);
15436 fs_give((void **)&tres
);
15438 if(newadrs
== NULL
){
15439 newadrs
= curnewadr
= newadr
;
15442 curnewadr
->next
= newadr
;
15443 curnewadr
= newadr
;
15449 if(newadrs
== NULL
|| curnewadr
== NULL
){
15450 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "No Result Selected for \"%s\"", curadr
->mailbox
? curadr
->mailbox
: "noname");
15451 q_status_message(SM_ORDER
, 0, 3, wtmp_20k_buf
);
15452 newadr
= copyaddr(curadr
);
15453 if(newadrs
== NULL
){
15454 newadrs
= curnewadr
= newadr
;
15457 curnewadr
->next
= newadr
;
15458 curnewadr
= newadr
;
15461 curnewadr
->next
= curadr
? curadr
->next
: NULL
;
15462 if(curadr
) curadr
->next
= NULL
;
15466 prevadr
->next
= newadrs
;
15468 mail_free_address(&curadr
);
15472 len
= est_size(adr
);
15473 ret_to
= (char *)fs_get(len
* sizeof(char));
15475 strip_personal_quotes(adr
);
15476 rbuf
.f
= dummy_soutr
;
15480 rbuf
.end
= ret_to
+len
-1;
15481 rfc822_output_address_list(&rbuf
, adr
, 0L, NULL
);
15483 Tcl_SetResult(interp
, ret_to
, TCL_VOLATILE
);
15484 fs_give((void **)&ret_to
);
15485 fs_give((void **)&tmpaddrstr
);
15486 fs_give((void **)&tmplistset
);
15487 for(i
= 0; lset
[i
]; i
++)
15488 fs_give((void **)&lset
[i
]);
15489 fs_give((void **)&lset
);
15491 mail_free_address(&adr
);
15497 #endif /* ENABLE_LDAP */
15498 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15505 peLdapQueryResults(Tcl_Interp
*interp
)
15508 Tcl_Obj
*secObj
= NULL
, *resObj
= NULL
, *itemObj
;
15510 LDAP_SERV_RES_S
*trl
;
15511 /* returned list will be of the form:
15515 * {name, {title, ...}, {unit, ...},
15516 * {org, ...}, {email, ...}},
15523 for(tsl
= wpldap_global
->ldap_search_list
;
15524 tsl
; tsl
= tsl
->next
){
15525 secObj
= Tcl_NewListObj(0, NULL
);
15526 if(Tcl_ListObjAppendElement(interp
, secObj
,
15527 Tcl_NewStringObj(tsl
->str
? tsl
->str
15528 : "", -1)) != TCL_OK
)
15530 resObj
= Tcl_NewListObj(0, NULL
);
15531 for(trl
= tsl
->reslist
; trl
; trl
= trl
->next
){
15532 for(e
= ldap_first_entry(trl
->ld
, trl
->res
);
15534 e
= ldap_next_entry(trl
->ld
, e
)){
15536 struct berval
**cn
, **org
, **unit
, **title
, **mail
, **sn
;
15539 cn
= org
= title
= unit
= mail
= sn
= NULL
;
15541 itemObj
= Tcl_NewListObj(0, NULL
);
15542 peLdapEntryParse(trl
, e
, &cn
, &org
, &unit
, &title
,
15545 if(Tcl_ListObjAppendElement(interp
, itemObj
,
15546 Tcl_NewStringObj(cn
[0]->bv_val
, -1)) != TCL_OK
)
15548 ldap_value_free_len(cn
);
15551 if(Tcl_ListObjAppendElement(interp
, itemObj
,
15552 Tcl_NewStringObj(sn
[0]->bv_val
, -1)) != TCL_OK
)
15554 ldap_value_free_len(sn
);
15557 dn
= ldap_get_dn(trl
->ld
, e
);
15560 our_ldap_dn_memfree(dn
);
15564 if(Tcl_ListObjAppendElement(interp
, itemObj
,
15565 Tcl_NewStringObj(dn
? dn
: "", -1)) != TCL_OK
)
15569 our_ldap_dn_memfree(dn
);
15571 if(peLdapStrlist(interp
, itemObj
, title
) == TCL_ERROR
)
15573 if(peLdapStrlist(interp
, itemObj
, unit
) == TCL_ERROR
)
15575 if(peLdapStrlist(interp
, itemObj
, org
) == TCL_ERROR
)
15577 if(peLdapStrlist(interp
, itemObj
, mail
) == TCL_ERROR
)
15579 if(Tcl_ListObjAppendElement(interp
, resObj
, itemObj
) != TCL_OK
)
15582 ldap_value_free_len(title
);
15584 ldap_value_free_len(unit
);
15586 ldap_value_free_len(org
);
15588 ldap_value_free_len(mail
);
15591 if(Tcl_ListObjAppendElement(interp
, secObj
, resObj
) != TCL_OK
)
15593 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15601 peLdapStrlist(Tcl_Interp
*interp
, Tcl_Obj
*itemObj
, struct berval
**strl
)
15606 strlObj
= Tcl_NewListObj(0, NULL
);
15608 for(i
= 0; ALPINE_LDAP_usable(strl
, i
); i
++){
15609 if(Tcl_ListObjAppendElement(interp
, strlObj
,
15610 Tcl_NewStringObj(strl
[i
]->bv_val
, -1)) != TCL_OK
)
15614 if(Tcl_ListObjAppendElement(interp
, itemObj
, strlObj
) != TCL_OK
)
15621 init_ldap_pname(struct pine
*ps
)
15623 if(!wps_global
->VAR_PERSONAL_NAME
15624 || wps_global
->VAR_PERSONAL_NAME
[0] == '\0'){
15626 struct variable
*vtmp
;
15628 if(ps
->maildomain
&& *ps
->maildomain
15629 && ps
->VAR_USER_ID
&& *ps
->VAR_USER_ID
){
15630 pname
= peLdapPname(ps
->VAR_USER_ID
, ps
->maildomain
);
15632 vtmp
= &ps
->vars
[V_PERSONAL_NAME
];
15633 if((vtmp
->fixed_val
.p
&& vtmp
->fixed_val
.p
[0] == '\0')
15634 || (vtmp
->is_fixed
&& !vtmp
->fixed_val
.p
)){
15635 if(vtmp
->fixed_val
.p
)
15636 fs_give((void **)&vtmp
->fixed_val
.p
);
15637 vtmp
->fixed_val
.p
= cpystr(pname
);
15640 if(vtmp
->global_val
.p
)
15641 fs_give((void **)&vtmp
->global_val
.p
);
15642 vtmp
->global_val
.p
= cpystr(pname
);
15644 fs_give((void **)&pname
);
15645 set_current_val(vtmp
, FALSE
, FALSE
);
15651 #endif /* ENABLE_LDAP */
15654 * Note: this is taken straight out of pico/composer.c
15656 * strqchr - returns pointer to first non-quote-enclosed occurance of ch in
15657 * the given string. otherwise NULL.
15659 * ch -- the character we're looking for
15660 * q -- q tells us if we start out inside quotes on entry and is set
15661 * correctly on exit.
15662 * m -- max characters we'll check for ch (set to -1 for no check)
15665 strqchr(char *s
, int ch
, int *q
, int m
)
15667 int quoted
= (q
) ? *q
: 0;
15669 for(; s
&& *s
&& m
!= 0; s
++, m
--){
15676 if(!quoted
&& *s
== ch
)
15685 wp_prune_folders(CONTEXT_S
*ctxt
,
15692 Tcl_Interp
*interp
)
15694 Tcl_Obj
*resObj
= NULL
, *secObj
= NULL
;
15695 char path2
[MAXPATH
+1], tmp
[21];
15696 int exists
, month_to_use
;
15697 struct sm_folder
*mail_list
, *sm
;
15699 mail_list
= get_mail_list(ctxt
, fcc
);
15701 for(sm
= mail_list
; sm
!= NULL
&& sm
->name
!= NULL
; sm
++)
15702 if(sm
->month_num
== cur_month
- 1)
15703 break; /* matched a month */
15705 month_to_use
= (sm
== NULL
|| sm
->name
== NULL
) ? cur_month
- 1 : 0;
15707 if(!(month_to_use
== 0 || pr
== PRUNE_NO_AND_ASK
|| pr
== PRUNE_NO_AND_NO
)){
15708 strncpy(path2
, fcc
, sizeof(path2
)-1);
15709 path2
[sizeof(path2
)-1] = '\0';
15710 strncpy(tmp
, month_abbrev((month_to_use
% 12)+1), sizeof(tmp
)-1);
15711 tmp
[sizeof(tmp
)-1] = '\0';
15712 lcase((unsigned char *) tmp
);
15713 snprintf(path2
+ strlen(path2
), sizeof(path2
)-strlen(path2
), "-%.20s-%d", tmp
, month_to_use
/12);
15715 if((exists
= folder_exists(ctxt
, fcc
)) == FEX_ERROR
){
15719 else if(exists
& FEX_ISFILE
){
15720 if(pr
== PRUNE_YES_AND_ASK
|| (pr
== PRUNE_YES_AND_NO
&& !moved_fldrs
)){
15721 prune_move_folder(fcc
, path2
, ctxt
);
15723 resObj
= Tcl_NewListObj(0, NULL
);
15724 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewStringObj(type
, -1));
15725 secObj
= Tcl_NewListObj(0, NULL
);
15726 Tcl_ListObjAppendElement(interp
, secObj
, Tcl_NewStringObj(fcc
, -1));
15727 Tcl_ListObjAppendElement(interp
, secObj
, Tcl_NewStringObj(path2
, -1));
15728 Tcl_ListObjAppendElement(interp
, resObj
, secObj
);
15732 if(pr
== PRUNE_ASK_AND_ASK
|| pr
== PRUNE_YES_AND_ASK
15733 || pr
== PRUNE_NO_AND_ASK
){
15735 if(!resObj
&& sm
&& sm
->name
&& sm
->name
[0] != '\0'){
15736 resObj
= Tcl_NewListObj(0, NULL
);
15737 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewStringObj(type
, -1));
15738 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewListObj(0, NULL
));
15741 secObj
= Tcl_NewListObj(0, NULL
);
15742 for(sm
= mail_list
; sm
!= NULL
&& sm
->name
!= NULL
; sm
++){
15743 if(sm
->name
[0] == '\0') /* can't happen */
15745 Tcl_ListObjAppendElement(interp
, secObj
, Tcl_NewStringObj(sm
->name
, -1));
15748 Tcl_ListObjAppendElement(interp
, resObj
, secObj
);
15750 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewListObj(0, NULL
));
15752 free_folder_list(ctxt
);
15754 if((sm
= mail_list
) != NULL
){
15756 fs_give((void **)&(sm
->name
));
15760 fs_give((void **)&mail_list
);
15768 hex_colorstr(char *hexcolor
, char *str
)
15770 char *tstr
, *p
, *p2
, tbuf
[256];
15773 strcpy(hexcolor
, "000000");
15774 tstr
= color_to_asciirgb(str
);
15776 p2
= strindex(p
, ',');
15777 if(p2
== NULL
) return 0;
15778 strncpy(tbuf
, p
, min(50, p2
-p
));
15780 sprintf(hexcolor
, "%2.2x", i
);
15782 p2
= strindex(p
, ',');
15783 if(p2
== NULL
) return 0;
15784 strncpy(tbuf
, p
, min(50, p2
-p
));
15786 sprintf(hexcolor
+2, "%2.2x", i
);
15788 strncpy(tbuf
, p
, 50);
15790 sprintf(hexcolor
+4, "%2.2x", i
);
15798 if(ch
>= '0' && ch
<= '9')
15800 else if (ch
>= 'A' && ch
<= 'F')
15801 return (10 + (ch
- 'A'));
15802 else if (ch
>= 'a' && ch
<= 'f')
15803 return (10 + (ch
- 'a'));
15808 ascii_colorstr(char *acolor
, char *hexcolor
)
15812 if(strlen(hexcolor
) > 6) return 1;
15814 if((hv
= hexval(hexcolor
[0])) == -1) return 1;
15816 if((hv
= hexval(hexcolor
[1])) == -1) return 1;
15818 sprintf(acolor
, "%3.3d,", i
);
15820 if((hv
= hexval(hexcolor
[2])) == -1) return 1;
15822 if((hv
= hexval(hexcolor
[3])) == -1) return 1;
15824 sprintf(acolor
+4, "%3.3d,", i
);
15826 if((hv
= hexval(hexcolor
[4])) == -1) return 1;
15828 if((hv
= hexval(hexcolor
[5])) == -1) return 1;
15830 sprintf(acolor
+8, "%3.3d", i
);
15837 peRandomString(char *b
, int l
, int f
)
15839 static char *kb
= "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
15846 for(j
= 0; j
< ((sizeof(long) * 8) / 5); j
++){
15853 case PRS_LOWER_CASE
:
15854 *s
++ = (char) tolower((unsigned char) kb
[(n
& 0x1F)]);
15857 case PRS_MIXED_CASE
:
15859 *s
++ = (char) tolower((unsigned char) kb
[(n
& 0x1F)]);
15864 *s
++ = kb
[(n
& 0x1F)];
15875 peAppendMsg(MAILSTREAM
*stream
, void *data
, char **flags
, char **date
, STRING
**message
)
15877 char *t
,*t1
,tmp
[MAILTMPLEN
];
15880 APPEND_PKG
*ap
= (APPEND_PKG
*) data
;
15881 *flags
= *date
= NIL
; /* assume no flags or date */
15882 if (ap
->flags
) fs_give ((void **) &ap
->flags
);
15883 if (ap
->date
) fs_give ((void **) &ap
->date
);
15884 mail_gc (ap
->stream
,GC_TEXTS
);
15885 if (++ap
->msgno
<= ap
->msgmax
) {
15886 /* initialize flag string */
15887 memset (t
= tmp
,0,MAILTMPLEN
);
15888 /* output system flags */
15889 if ((elt
= mail_elt (ap
->stream
,ap
->msgno
))->seen
) {strncat (t
," \\Seen", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15890 if (elt
->deleted
) {strncat (t
," \\Deleted", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15891 if (elt
->flagged
) {strncat (t
," \\Flagged", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15892 if (elt
->answered
) {strncat (t
," \\Answered", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15893 if (elt
->draft
) {strncat (t
," \\Draft", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15894 if ((u
= elt
->user_flags
) != 0L) do /* any user flags? */
15895 if ((MAILTMPLEN
- ((t
+= strlen (t
)) - tmp
)) > (long)
15897 (t1
= ap
->stream
->user_flags
[find_rightmost_bit (&u
)]))) {
15898 if(t
-tmp
< sizeof(tmp
))
15899 *t
++ = ' '; /* space delimiter */
15900 strncpy (t
,t1
,sizeof(tmp
)-(t
-tmp
)); /* copy the user flag */
15902 while (u
); /* until no more user flags */
15903 tmp
[sizeof(tmp
)-1] = '\0';
15904 *flags
= ap
->flags
= cpystr (tmp
+ 1);
15905 *date
= ap
->date
= cpystr (mail_date (tmp
,elt
));
15906 *message
= ap
->message
; /* message stringstruct */
15907 INIT (ap
->message
,mstring
,(void *) ap
,elt
->rfc822_size
);
15909 else *message
= NIL
; /* all done */
15914 /* Initialize file string structure for file stringstruct
15915 * Accepts: string structure
15916 * pointer to message data structure
15921 ms_init(STRING
*s
, void *data
, unsigned long size
)
15923 APPEND_PKG
*md
= (APPEND_PKG
*) data
;
15924 s
->data
= data
; /* note stream/msgno and header length */
15925 mail_fetchheader_full (md
->stream
,md
->msgno
,NIL
,&s
->data1
,FT_PREFETCHTEXT
);
15926 mail_fetchtext_full (md
->stream
,md
->msgno
,&s
->size
,NIL
);
15927 s
->size
+= s
->data1
; /* header + body size */
15932 /* Get next character from file stringstruct
15933 * Accepts: string structure
15934 * Returns: character, string structure chunk refreshed
15939 char c
= *s
->curpos
++; /* get next byte */
15940 SETPOS (s
,GETPOS (s
)); /* move to next chunk */
15941 return c
; /* return the byte */
15945 /* Set string pointer position for file stringstruct
15946 * Accepts: string structure
15950 ms_setpos(STRING
*s
, unsigned long i
)
15952 APPEND_PKG
*md
= (APPEND_PKG
*) s
->data
;
15953 if (i
< s
->data1
) { /* want header? */
15954 s
->chunk
= mail_fetchheader (md
->stream
,md
->msgno
);
15955 s
->chunksize
= s
->data1
; /* header length */
15956 s
->offset
= 0; /* offset is start of message */
15958 else if (i
< s
->size
) { /* want body */
15959 s
->chunk
= mail_fetchtext (md
->stream
,md
->msgno
);
15960 s
->chunksize
= s
->size
- s
->data1
;
15961 s
->offset
= s
->data1
; /* offset is end of header */
15963 else { /* off end of message */
15964 s
->chunk
= NIL
; /* make sure that we crack on this then */
15965 s
->chunksize
= 1; /* make sure SNX cracks the right way... */
15968 /* initial position and size */
15969 s
->curpos
= s
->chunk
+ (i
-= s
->offset
);
15970 s
->cursize
= s
->chunksize
- i
;
15975 remote_pinerc_failure(void)
15977 snprintf(wps_global
->last_error
, sizeof(wps_global
->last_error
), "%s",
15978 wps_global
->c_client_error
[0]
15979 ? wps_global
->c_client_error
15980 : _("Unable to read remote configuration"));
15986 peWebAlpinePrefix(void)
15992 void peNewMailAnnounce(MAILSTREAM
*stream
, long n
, long t_nm_count
){
15993 char subject
[MAILTMPLEN
+1], subjtext
[MAILTMPLEN
+1], from
[MAILTMPLEN
+1],
15994 *folder
= NULL
, intro
[MAILTMPLEN
+1];
15996 ENVELOPE
*e
= NULL
;
15999 if(n
&& (resObj
= Tcl_NewListObj(0, NULL
)) != NULL
){
16001 Tcl_ListObjAppendElement(peED
.interp
, resObj
, Tcl_NewLongObj(number
= sp_mail_since_cmd(stream
)));
16002 Tcl_ListObjAppendElement(peED
.interp
, resObj
, Tcl_NewLongObj(mail_uid(stream
, n
)));
16005 e
= pine_mail_fetchstructure(stream
, n
, NULL
);
16007 if(sp_flagged(stream
, SP_INBOX
))
16010 folder
= STREAMNAME(stream
);
16011 if(folder
[0] == '?' && folder
[1] == '\0')
16016 format_new_mail_msg(folder
, number
, e
, intro
, from
, subject
, subjtext
, sizeof(intro
));
16018 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
,
16019 "%s%s%s%.80s%.80s", intro
,
16020 from
? ((number
> 1L) ? " Most recent f" : " F") : "",
16021 from
? "rom " : "",
16025 Tcl_ListObjAppendElement(peED
.interp
, resObj
, Tcl_NewStringObj(wtmp_20k_buf
,-1));
16027 Tcl_ListObjAppendElement(peED
.interp
, Tcl_GetObjResult(peED
.interp
), resObj
);
16032 /* * * * * * * * * RSS 2.0 Support Routines * * * * * * * * * * * */
16035 * PERssCmd - RSS TCL interface
16038 PERssCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
16042 dprint((2, "PERssCmd"));
16045 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
16048 s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
16051 if(!strcmp(s1
, "news")){
16052 return(peRssReturnFeed(interp
, "news", wps_global
->VAR_RSS_NEWS
));
16054 else if(!strcmp(s1
, "weather")){
16055 return(peRssReturnFeed(interp
, "weather", wps_global
->VAR_RSS_WEATHER
));
16059 Tcl_SetResult(interp
, "Unknown PERss command", TCL_STATIC
);
16064 * peRssReturnFeed - fetch feed contents and package Tcl response
16067 peRssReturnFeed(Tcl_Interp
*interp
, char *type
, char *link
)
16070 char *errstr
= "UNKNOWN";
16073 wps_global
->c_client_error
[0] = '\0';
16075 if((feed
= peRssFeed(interp
, type
, link
)) != NULL
)
16076 return(peRssPackageFeed(interp
, feed
));
16078 if(wps_global
->mm_log_error
)
16079 errstr
= wps_global
->c_client_error
;
16082 errstr
= "missing setting";
16084 snprintf(wtmp_20k_buf
, SIZEOF_20KBUF
, "%s feed fail: %s", type
, errstr
);
16085 Tcl_SetResult(interp
, wtmp_20k_buf
, TCL_VOLATILE
);
16090 * peRssPackageFeed - build a list of feed item elements
16092 * LIST ORDER: {title} {link} {description} {image}
16095 peRssPackageFeed(Tcl_Interp
*interp
, RSS_FEED_S
*feed
)
16099 for(item
= feed
->items
; item
; item
= item
->next
)
16100 if(peAppListF(interp
, Tcl_GetObjResult(interp
), "%s %s %s %s",
16101 (item
->title
&& *item
->title
)? item
->title
: "Feed Provided No Title",
16102 item
->link
? item
->link
: "",
16103 item
->description
? item
->description
: "",
16104 feed
->image
? feed
->image
: "") != TCL_OK
)
16112 * peRssFeed - return cached feed struct or fetch a new one
16115 peRssFeed(Tcl_Interp
*interp
, char *type
, char *link
)
16117 int i
, cache_l
, cp_ref
;
16118 time_t now
= time(0);
16119 RSS_FEED_S
*feed
= NULL
;
16120 RSS_CACHE_S
*cache
, *cp
;
16121 static RSS_CACHE_S news_cache
[RSS_NEWS_CACHE_SIZE
], weather_cache
[RSS_WEATHER_CACHE_SIZE
];
16123 if(!strucmp(type
,"news")){
16124 cache
= &news_cache
[0];
16125 cache_l
= RSS_NEWS_CACHE_SIZE
;
16128 cache
= &weather_cache
[0];
16129 cache_l
= RSS_WEATHER_CACHE_SIZE
;
16132 /* search/purge cache */
16133 for(i
= 0; i
< cache_l
; i
++)
16135 if(now
> cache
[i
].stale
){
16136 peRssClearCacheEntry(&cache
[i
]);
16138 else if(!strcmp(link
, cache
[i
].link
)){
16139 cache
[i
].referenced
++;
16140 return(cache
[i
].feed
); /* HIT! */
16144 if((feed
= peRssFetch(interp
, link
)) != NULL
){
16145 /* find cache slot, and insert feed into cache */
16146 for(i
= 0, cp_ref
= 0; i
< cache_l
; i
++)
16147 if(!cache
[i
].feed
){
16151 else if(cache
[i
].referenced
>= cp_ref
)
16155 cp
= &cache
[0]; /* failsafe */
16157 peRssClearCacheEntry(cp
); /* make sure */
16159 cp
->link
= cpystr(link
);
16161 cp
->referenced
= 0;
16162 cp
->stale
= now
+ (((feed
->ttl
> 0) ? feed
->ttl
: 60) * 60);
16169 * peRssFetch - follow the provided link an return the resulting struct
16172 peRssFetch(Tcl_Interp
*interp
, char *link
)
16174 char *scheme
= NULL
, *loc
= NULL
, *path
= NULL
, *parms
= NULL
, *query
= NULL
, *frag
= NULL
;
16175 char *buffer
= NULL
, *bp
, *p
, *q
;
16177 unsigned long port
= 0L, buffer_len
= 0L;
16178 time_t theirdate
= 0;
16179 STORE_S
*feed_so
= NULL
;
16180 TCPSTREAM
*tcp_stream
;
16184 rfc1808_tokens(link
, &scheme
, &loc
, &path
, &parms
, &query
, &frag
);
16185 if(scheme
&& loc
&& path
){
16186 if((p
= strchr(loc
,':')) != NULL
){
16188 while(*p
&& isdigit((unsigned char) *p
))
16189 port
= ((port
* 10) + (*p
++ - '0'));
16192 Tcl_SetResult(interp
, "Bad RSS port number", TCL_STATIC
);
16193 peRssComponentFree(&scheme
,&loc
,&path
,&parms
,&query
,&frag
);
16198 if(scheme
&& !strucmp(scheme
, "feed")){
16199 fs_give((void **) &scheme
);
16200 scheme
= cpystr("http");
16203 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long) 5);
16204 tcp_stream
= tcp_open (loc
, scheme
, port
| NET_NOOPENTIMEOUT
);
16205 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long) 30);
16207 if(tcp_stream
!= NULL
){
16210 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",
16211 path
, parms
? ":" : "", parms
? parms
: "",
16212 query
? "?" : "", query
? query
: "", loc
,
16213 ALPINE_VERSION
, SYSTYPE
, get_alpine_revision_string(rev
, sizeof(rev
)));
16215 mail_parameters(NULL
, SET_WRITETIMEOUT
, (void *)(long) 5);
16216 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long) 5);
16218 if(tcp_sout(tcp_stream
, wtmp_20k_buf
, strlen(wtmp_20k_buf
))){
16219 int ok
= 0, chunked
= FALSE
;
16221 while((p
= tcp_getline(tcp_stream
)) != NULL
){
16224 if(strucmp(p
,"HTTP/1.1 200 OK")){
16225 fs_give((void **) &p
);
16229 else if(*p
== '\0'){ /* first blank line, start of body */
16230 if(buffer
|| feed_so
){
16231 fs_give((void **) &p
);
16236 buffer
= fs_get(buffer_len
+ 16);
16237 if(!tcp_getbuffer(tcp_stream
, buffer_len
, buffer
))
16238 fs_give((void **) &buffer
);
16240 fs_give((void **) &p
);
16243 else if((feed_so
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
16244 fs_give((void **) &p
);
16248 else if(feed_so
){ /* collect body */
16250 int chunk_len
= 0, gotbuf
;
16252 /* first line is chunk size in hex */
16253 for(q
= p
; *q
&& isxdigit((unsigned char) *q
); q
++)
16254 chunk_len
= (chunk_len
* 16) + XDIGIT2C(*q
);
16256 if(chunk_len
> 0){ /* collect chunk */
16257 char *tbuf
= fs_get(chunk_len
+ 16);
16258 gotbuf
= tcp_getbuffer(tcp_stream
, chunk_len
, tbuf
);
16260 so_nputs(feed_so
, tbuf
, chunk_len
);
16262 fs_give((void **) &tbuf
);
16265 fs_give((void **) &p
);
16270 /* collect trailing CRLF */
16271 gotbuf
= ((q
= tcp_getline(tcp_stream
)) != NULL
&& *q
== '\0');
16273 fs_give((void **) &q
);
16275 if(chunk_len
== 0 || !gotbuf
){
16276 fs_give((void **) &p
);
16281 so_puts(feed_so
, p
);
16283 else{ /* in header, grok fields */
16284 if((q
= strchr(p
,':')) != NULL
){
16288 while(isspace((unsigned char ) *q
))
16291 /* content-length */
16292 if(l
== 4 && !strucmp(p
, "date")){
16293 theirdate
= date_to_local_time_t(q
);
16295 else if(l
== 7 && !strucmp(p
, "expires")){
16296 time_t expires
= date_to_local_time_t(q
) - ((theirdate
> 0) ? theirdate
: time(0));
16298 if(expires
> 0 && expires
< (8 * 60 * 60))
16301 else if(l
== 12 && !strucmp(p
, "content-type")
16302 && struncmp(q
,"text/xml", 8)
16303 && struncmp(q
,"application/xhtml+xml", 21)
16304 && struncmp(q
,"application/rss+xml", 19)
16305 && struncmp(q
,"application/xml", 15)){
16306 fs_give((void **) &p
);
16309 else if(l
== 13 && !strucmp(p
, "cache-control")){
16310 if(!struncmp(q
,"max-age=",8)){
16313 for(q
+= 8; *q
&& isdigit((unsigned char) *q
); q
++)
16314 secs
= ((secs
* 10) + (*q
- '0'));
16320 else if(l
== 14 && !strucmp(p
,"content-length")){
16321 while(*q
&& isdigit((unsigned char) *q
))
16322 buffer_len
= ((buffer_len
* 10) + (*q
++ - '0'));
16325 fs_give((void **) &p
);
16329 else if(l
== 17 && !strucmp(p
, "transfer-encoding")){
16330 if(!struncmp(q
,"chunked", 7)){
16333 else{ /* unknown encoding */
16334 fs_give((void **) &p
);
16341 fs_give((void **) &p
);
16345 Tcl_SetResult(interp
, "RSS send failure", TCL_STATIC
);
16346 peRssComponentFree(&scheme
,&loc
,&path
,&parms
,&query
,&frag
);
16349 tcp_close(tcp_stream
);
16350 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long) 60);
16351 mail_parameters(NULL
, SET_WRITETIMEOUT
, (void *)(long) 60);
16352 peRssComponentFree(&scheme
,&loc
,&path
,&parms
,&query
,&frag
);
16355 buffer
= (char *) so_text(feed_so
);
16356 buffer_len
= (int) so_tell(feed_so
);
16359 if(buffer
&& buffer_len
){
16365 /* grok response */
16366 bucket
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
16367 gf_set_readc(&gc
, buffer
, buffer_len
, CharStar
, 0);
16368 gf_set_so_writec(&pc
, bucket
);
16370 gf_link_filter(gf_html2plain
, gf_html2plain_rss_opt(&feed
,0));
16371 if((err
= gf_pipe(gc
, pc
)) != NULL
){
16372 gf_html2plain_rss_free(&feed
);
16373 Tcl_SetResult(interp
, "RSS connection failure", TCL_STATIC
);
16381 fs_give((void **) &buffer
);
16386 Tcl_SetResult(interp
, "RSS response error", TCL_STATIC
);
16389 Tcl_SetResult(interp
, "RSS connection failure", TCL_STATIC
);
16392 Tcl_SetResult(interp
, "RSS feed missing scheme", TCL_STATIC
);
16395 Tcl_SetResult(interp
, "No RSS Feed Defined", TCL_STATIC
);
16402 peRssComponentFree(char **scheme
,char **loc
,char **path
,char **parms
,char **query
,char **frag
)
16404 if(scheme
) fs_give((void **) scheme
);
16405 if(loc
) fs_give((void **) loc
);
16406 if(path
) fs_give((void **) path
);
16407 if(parms
) fs_give((void **) parms
);
16408 if(query
) fs_give((void **) query
);
16409 if(frag
) fs_give((void **) frag
);
16413 peRssClearCacheEntry(RSS_CACHE_S
*entry
)
16417 fs_give((void **) &entry
->link
);
16419 gf_html2plain_rss_free(&entry
->feed
);
16420 memset(entry
, 0, sizeof(RSS_CACHE_S
));