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 * Aribtrary 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 lenght 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
*ps_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 tmp_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(ps_global
);
910 /* destroy user context */
911 peDestroyUserContext(&ps_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(ps_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(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid foreground color value %.100s", fghex
);
1104 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
1108 if(ascii_colorstr(asciicolor
, bghex
) == 0) {
1110 fs_give((void **)&thc
->bg
);
1112 thc
->bg
= cpystr(asciicolor
);
1115 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
1116 Tcl_SetResult(interp
, tmp_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
= &ps_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
= &ps_global
->vars
[V_NORM_FORE_COLOR
];
1160 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
1164 if(!vtmp
->name
|| vtmp
->is_list
){
1165 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
1166 Tcl_SetResult(interp
, tmp_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(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid color value %.100s", fghex
);
1181 Tcl_SetResult(interp
, tmp_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
= &ps_global
->vars
[V_NORM_FORE_COLOR
];
1189 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
1193 if(!vtmp
->name
|| vtmp
->is_list
){
1194 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
1195 Tcl_SetResult(interp
, tmp_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(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
1210 Tcl_SetResult(interp
, tmp_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
, ps_global
->VAR_WP_INDEXHEIGHT
?
1275 ps_global
->VAR_WP_INDEXHEIGHT
: "", TCL_VOLATILE
);
1278 else if(!strcmp(s1
, "indexlines")){
1279 Tcl_SetResult(interp
, ps_global
->VAR_WP_INDEXLINES
?
1280 ps_global
->VAR_WP_INDEXLINES
: "0", TCL_VOLATILE
);
1283 else if(!strcmp(s1
, "aggtabstate")){
1284 Tcl_SetResult(interp
, ps_global
->VAR_WP_AGGSTATE
?
1285 ps_global
->VAR_WP_AGGSTATE
: "0", TCL_VOLATILE
);
1288 else if(!strcmp(s1
, "alpinestate")){
1291 if((wps
= ps_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
,tmp_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
,tmp_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
, ps_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((ps_global
->VAR_LITERAL_SIG
1432 || (ps_global
->VAR_SIGNATURE_FILE
1433 && IS_REMOTE(ps_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(ps_global
->VAR_LITERAL_SIG
){
1459 if(ps_global
->restricted
){
1460 err
= "Alpine demo can't change config file";
1463 /* BUG: no "exceptions file" support */
1464 if((apval
= APVAL(&ps_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(ps_global
->VAR_SIGNATURE_FILE
))
1474 snprintf(err
= tmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote signature file: %s",
1475 ps_global
->VAR_SIGNATURE_FILE
? ps_global
->VAR_SIGNATURE_FILE
: "<null>");
1476 else if(!(sig
= simple_read_remote_file(ps_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(ps_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 ps_global
->last_expire_year
= tm_now
->tm_year
;
1554 ps_global
->last_expire_month
= tm_now
->tm_mon
;
1555 snprintf(tmp
, sizeof(tmp
), "%d.%d", ps_global
->last_expire_year
,
1556 ps_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(ps_global
->context_list
)))
1577 prune_cntxt
= ps_global
->context_list
;
1580 if(ps_global
->VAR_DEFAULT_FCC
&& *ps_global
->VAR_DEFAULT_FCC
1581 && context_isambig(ps_global
->VAR_DEFAULT_FCC
))
1582 if((retObj
= wp_prune_folders(prune_cntxt
,
1583 ps_global
->VAR_DEFAULT_FCC
,
1585 ps_global
->pruning_rule
, &ok
,
1586 moved_fldrs
, interp
)) != NULL
)
1587 Tcl_ListObjAppendElement(interp
,
1588 Tcl_GetObjResult(interp
),
1591 if(ok
&& ps_global
->VAR_READ_MESSAGE_FOLDER
1592 && *ps_global
->VAR_READ_MESSAGE_FOLDER
1593 && context_isambig(ps_global
->VAR_READ_MESSAGE_FOLDER
))
1594 if((retObj
= wp_prune_folders(prune_cntxt
,
1595 ps_global
->VAR_READ_MESSAGE_FOLDER
,
1597 ps_global
->pruning_rule
, &ok
,
1598 moved_fldrs
, interp
)) != NULL
)
1599 Tcl_ListObjAppendElement(interp
,
1600 Tcl_GetObjResult(interp
),
1602 if(ok
&& (p
= ps_global
->VAR_PRUNED_FOLDERS
)){
1603 for(; ok
&& *p
; p
++)
1604 if(**p
&& context_isambig(*p
))
1605 if((retObj
= wp_prune_folders(prune_cntxt
,
1607 ps_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(ps_global
->mail_stream
)
1624 pine_mail_ping(ps_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
, ps_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(ps_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
= &ps_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
= &ps_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
= ps_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
- ps_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(ps_global
->VAR_LITERAL_SIG
){
1852 char *cstring_version
, *sig
, *line
;
1856 tmp_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(tmp_20k_buf
+ strlen(tmp_20k_buf
), SIZEOF_20KBUF
- strlen(tmp_20k_buf
), "%.*s\n", SIG_MAX_COLS
, line
);
1862 sig
= cpystr(tmp_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
, ps_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
= ps_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
, ps_global
)){
1997 toggle_feature(ps_global
,
1998 &ps_global
->vars
[V_FEATURE_LIST
],
1999 feature
, TRUE
, Main
);
2002 ps_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
= ps_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
- ps_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
= ps_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
= ps_global
->full_header
;
2151 ps_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(ps_global
->vars
[V_VIEW_HDR_COLORS
].is_changed_val
)
2224 hcolors
= spec_colors_from_varlist(ps_global
->vars
[V_VIEW_HDR_COLORS
].changed_val
.l
, 0);
2226 hcolors
= spec_colors_from_varlist(ps_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(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid foreground color value %.100s", fghex
);
2360 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
2364 if(ascii_colorstr(asciicolor
, bghex
) == 0) {
2366 fs_give((void **)&thc
->bg
);
2368 thc
->bg
= cpystr(asciicolor
);
2371 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
2372 Tcl_SetResult(interp
, tmp_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
= &ps_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
= &ps_global
->vars
[V_NORM_FORE_COLOR
];
2416 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
2420 if(!vtmp
->name
|| vtmp
->is_list
){
2421 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
2422 Tcl_SetResult(interp
, tmp_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(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid color value %.100s", fghex
);
2440 Tcl_SetResult(interp
, tmp_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
= &ps_global
->vars
[V_NORM_FORE_COLOR
];
2448 vtmp
->name
&& strucmp(vtmp
->name
, tvname
);
2452 if(!vtmp
->name
|| vtmp
->is_list
){
2453 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background var %.100s", varname
);
2454 Tcl_SetResult(interp
, tmp_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(tmp_20k_buf
, SIZEOF_20KBUF
, "colorset: invalid background color value %.100s", bghex
);
2471 Tcl_SetResult(interp
, tmp_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
= &ps_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
, ps_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
= &ps_global
->vars
[V_LITERAL_SIG
];
2506 if(vtmp
->is_changed_val
? vtmp
->changed_val
.p
2507 : ps_global
->VAR_LITERAL_SIG
){
2511 if(ps_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(&ps_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
= &ps_global
->vars
[V_SIGNATURE_FILE
])
2528 && !IS_REMOTE(vtmp
->is_changed_val
? vtmp
->changed_val
.p
2529 : ps_global
->VAR_SIGNATURE_FILE
))
2530 snprintf(err
= tmp_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 : (ps_global
->VAR_SIGNATURE_FILE
2534 ? ps_global
->VAR_SIGNATURE_FILE
: "<null>"));
2535 else if(!(peTSig
|| (sig
= simple_read_remote_file(vtmp
->is_changed_val
2536 ? vtmp
->changed_val
.p
2537 : ps_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
= &ps_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
= &ps_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
= ps_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
, ps_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(ps_global
->vars
[V_FEATURE_LIST
].is_changed_val
){
2681 ps_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
, ps_global
)){
2686 toggle_feature(ps_global
,
2687 &ps_global
->vars
[V_FEATURE_LIST
],
2688 feature
, TRUE
, Main
);
2693 for(vtmp
= ps_global
->vars
; vtmp
->name
; vtmp
++){
2694 if(vtmp
->is_changed_val
2695 && (vtmp
- ps_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
- ps_global
->vars
) {
2716 init_hostname(ps_global
);
2719 free_contexts(&ps_global
->context_list
);
2720 init_folders(ps_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(ps_global
->VAR_INDEX_FORMAT
,
2737 &ps_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(ps_global
->VAR_SORT_KEY
, &ps_global
->def_sort
, &def_sort_rev
);
2760 case V_VIEW_HDR_COLORS
:
2761 set_custom_spec_colors(ps_global
);
2763 case V_POST_CHAR_SET
:
2764 update_posting_charset(ps_global
, 1);
2772 peWriteSig(interp
, ps_global
->VAR_SIGNATURE_FILE
, NULL
);
2775 if(write_pinerc(ps_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(ps_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
= ps_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
- ps_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
,tmp_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
,tmp_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
= &ps_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
= &ps_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
= &ps_global
->vars
[V_LITERAL_SIG
];
3154 if(vtmp
->is_changed_val
? vtmp
->changed_val
.p
3155 : ps_global
->VAR_LITERAL_SIG
){
3157 tmp_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(tmp_20k_buf
+ strlen(tmp_20k_buf
), SIZEOF_20KBUF
- strlen(tmp_20k_buf
), "%.*s\n", SIG_MAX_COLS
, line
);
3163 sig
= cpystr(tmp_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(ps_global
->vars
[V_VIEW_HDR_COLORS
].is_changed_val
)
3204 hcolors
= spec_colors_from_varlist(ps_global
->vars
[V_VIEW_HDR_COLORS
].changed_val
.l
, 0);
3206 hcolors
= spec_colors_from_varlist(ps_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
= &ps_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
= &ps_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
= &ps_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
= &ps_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 && ps_global
->ttyo
->screen_cols
!= n
){
3336 clear_index_cache(sp_inbox_stream(), 0);
3337 ps_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(ps_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(ps_global
->prc
->name
);
3356 prc
->type
= ps_global
->prc
->type
;
3357 prc
->rd
= ps_global
->prc
->rd
;
3358 prc
->outstanding_pinerc_changes
= 1;
3360 /* tie off original pinerc struct and free it */
3361 ps_global
->prc
->rd
= NULL
;
3362 ps_global
->prc
->outstanding_pinerc_changes
= 0;
3363 free_pinerc_s(&ps_global
->prc
);
3365 /* set global->prc to new struct with no pinerc_lines
3366 * and fool write_pinerc into not writing changed vars
3368 ps_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
= ps_global
->vars
; var
->name
!= NULL
; var
++){
3376 var
->been_written
= ((var
- ps_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(ps_global
, Main
, WRP_NOUSER
| WRP_PRESERV_WRITTEN
);
3389 peInitVars(ps_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
= ps_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 ps_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
= &ps_global
->vars
[V_FOLDER_SPEC
];
3505 nvar
= &ps_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
= &ps_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
= &ps_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
= &ps_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
= &ps_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(tmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote signature file: %s",
3717 file
? file
: "<null>");
3718 Tcl_SetResult(interp
, tmp_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(tmp_20k_buf
, SIZEOF_20KBUF
, "Can't create stream for sig file: %s", file
);
3730 Tcl_SetResult(interp
, tmp_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(tmp_20k_buf
, SIZEOF_20KBUF
, "Readonly sig file: %s", file
);
3765 Tcl_SetResult(interp
, tmp_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(tmp_20k_buf
, SIZEOF_20KBUF
, "Unavailable sig file: %s", file
);
3793 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
3800 tmp_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(tmp_20k_buf
+ strlen(tmp_20k_buf
), SIZEOF_20KBUF
- strlen(tmp_20k_buf
), "%.*s\n",
3806 SIG_MAX_COLS
, line
);
3810 for(i
= 0; peTSig
[i
] && i
< SIG_MAX_LINES
; i
++) {
3811 snprintf(tmp_20k_buf
+ strlen(tmp_20k_buf
), SIZEOF_20KBUF
- strlen(tmp_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(tmp_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(tmp_20k_buf
, SIZEOF_20KBUF
, "Sig copy failure1: %s: %s",
3831 rd
->lf
, error_description(errno
));
3832 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
3833 rd_close_remdata(&rd
);
3841 rd_close_remdata(&rd
);
3842 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "Sig copy open failure2: %s: %s",
3843 rd
->lf
, error_description(errno
));
3844 Tcl_SetResult(interp
, tmp_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(tmp_20k_buf
, SIZEOF_20KBUF
, "Sig update failure: %s: %s",
3858 rd
->lf
, error_description(errno
));
3859 Tcl_SetResult(interp
, tmp_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 ps_global
->debug_imap
= 0;
3972 if(ps_global
->mail_stream
)
3973 mail_nodebug(ps_global
->mail_stream
);
3976 else if(level
> 0 && level
< 5){
3978 ps_global
->debug_imap
= level
;
3979 if(ps_global
->mail_stream
)
3980 mail_debug(ps_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(tmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote Config: %s", pinerc
);
4069 Tcl_SetResult(interp
, tmp_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(ps_global
);
4093 /* destroy old user context */
4094 peDestroyUserContext(&ps_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(ps_global
);
4113 /* destroy user context */
4114 peDestroyUserContext(&ps_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
= ps_global
? ps_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 || (ps_global
? F_ON(F_PREFER_ALT_AUTH
, ps_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
= ps_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(tmp_20k_buf
, SIZEOF_20KBUF
, "Authentication driver %.30s disabled", driver
);
4309 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
4313 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "PESession: Can't disable %.30s", driver
);
4314 Tcl_SetResult(interp
, tmp_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 ps_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(ps_global
&& ps_global
->smime
){
4386 strncpy((char *) ps_global
->smime
->passphrase
, passphrase
,
4387 sizeof(ps_global
->smime
->passphrase
));
4388 ps_global
->smime
->passphrase
[sizeof(ps_global
->smime
->passphrase
)-1] = '\0';
4389 ps_global
->smime
->entered_passphrase
= 1;
4390 ps_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(ps_global
->mail_stream
!= sp_inbox_stream()
4418 || strcmp(type
, "current") == 0){
4419 delete_count
= count_flagged(ps_global
->mail_stream
, F_DEL
);
4420 resObj
= Tcl_NewListObj(0, NULL
);
4421 Tcl_ListObjAppendElement(interp
, resObj
,
4422 Tcl_NewStringObj(pretty_fn(ps_global
->cur_folder
), -1));
4423 Tcl_ListObjAppendElement(interp
, resObj
,
4424 Tcl_NewIntObj(delete_count
));
4425 Tcl_ListObjAppendElement(interp
, resObj
,
4426 Tcl_NewIntObj((ps_global
->mail_stream
4427 == sp_inbox_stream())
4429 Tcl_ListObjAppendElement(interp
, resObj
,
4430 Tcl_NewIntObj((ps_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
= ps_global
->context_list
; cp
&& cp
!= ps_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(ps_global
->cur_folder
,-1)) == TCL_OK
)
4610 else if(!strcmp(op
, "collections")){
4617 * Returns: List of currently configured collections
4619 for(i
= 0, cp
= ps_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
= ps_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
= ps_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
= ps_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
= ps_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
= ps_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
, ps_global
->mail_stream
)))){
4775 ps_global
->noshow_error
= 1;
4777 mstream
= context_open(cp
, NULL
, folder
,
4778 SP_USEPOOL
| SP_TEMPUSE
| OP_READONLY
| OP_SHORTCACHE
,
4780 ps_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
= ps_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
, ps_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
= ps_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
, ps_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 ps_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 ps_global
->c_client_error
);
4999 ps_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 ps_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
= ps_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 ps_global
->mail_stream
)){
5091 snprintf(err
= errbuf
, sizeof(errbuf
), "PEFolder: import: %.200s",
5092 ps_global
->c_client_error
);
5097 pine_mail_close(dst
);
5100 snprintf(err
= errbuf
, sizeof(errbuf
), "PEFolder: import: %.200s",
5101 ps_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 ps_global
->c_client_error
);
5119 ps_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
= ps_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(ps_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 ps_global
->c_client_error
[0] = ps_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 ps_global
->c_client_error
[0] = '\0';
5227 pePrepareForAuthException();
5229 rv
= folder_name_exists(cp
, folder
, NULL
);
5232 if((errstr
= peAuthException()) == NULL
){
5233 if(ps_global
->c_client_error
[0])
5234 errstr
= ps_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 ps_global
->c_client_error
[0] = ps_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 (ps_global
->last_error
[0])
5295 ? ps_global
->last_error
5296 : (ps_global
->c_client_error
[0])
5297 ? ps_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 ps_global
->c_client_error
[0] = ps_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(ps_global
->restricted
)
5356 prc
= ps_global
->prc
;
5359 prc
= ps_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
== ps_global
->context_list
5375 && !(cp
->dir
&& cp
->dir
->ref
)
5376 && strucmp(folder
, ps_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
== ps_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(ps_global
->inbox_name
,
5441 ps_global
->context_list
,
5442 NULL
, DB_INBOXWOCNTXT
);
5447 * Use fp->name since "folder" may be a nickname...
5449 if(ps_global
->mail_stream
5450 && context_same_stream(cp
, fp
->name
, ps_global
->mail_stream
))
5451 del_stream
= ps_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 (ps_global
->last_error
[0])
5462 ? ps_global
->last_error
5463 : (ps_global
->c_client_error
[0])
5464 ? ps_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 ps_global
->c_client_error
[0] = ps_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 (ps_global
->last_error
[0])
5513 ? ps_global
->last_error
5514 : (ps_global
->c_client_error
[0])
5515 ? ps_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(ps_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
= ps_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 emtpy string.
5600 * * the second element which is either
5601 * the percentage width or empty string
5604 return(peIndexFormat(interp
));
5606 else if(ps_global
&& ps_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
= ps_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 ps_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(ps_global
->mail_stream
, msgmap
, FALSE
);
5654 (void) cmd_expunge_work(stream
, msgmap
, NULL
);
5656 Tcl_SetResult(interp
, ps_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
= ps_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 ps_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(ps_global
->mail_stream
, msgmap
, FALSE
);
5700 if(!(cp
= default_save_context(ps_global
->context_list
)))
5701 cp
= ps_global
->context_list
;
5703 /* copy to trash if we're not in trash */
5704 if(ps_global
->VAR_TRASH_FOLDER
5705 && ps_global
->VAR_TRASH_FOLDER
[0]
5706 && context_allowed(context_apply(tmp
, cp
, ps_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 delted to Trash */
5725 n
= save(ps_global
, stream
,
5726 cp
, ps_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
, ps_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(ps_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(ps_global
->mail_stream
)))){
5776 mn_set_cur(sp_msgmap(ps_global
->mail_stream
), msgno
);
5778 for(countdown
= count
; countdown
> 0; countdown
--){
5779 imapuid_t uid
= mail_uid(ps_global
->mail_stream
, mn_m2raw(sp_msgmap(ps_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(ps_global
, ps_global
->mail_stream
,
5792 sp_msgmap(ps_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
, ps_global
, ps_global
->mail_stream
,
5798 sp_msgmap(ps_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(ps_global
->mail_stream
, raw
)) && mc
->valid
)){
5810 mail_fetch_flags(ps_global
->mail_stream
,
5811 ulong2string(uid
), FT_UID
);
5812 mc
= mail_elt(ps_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(ps_global
->mail_stream
)) && msgline_hidden(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), msgno
, MN_NONE
); msgno
++)
5860 if(msgno
> mn_get_total(sp_msgmap(ps_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 messsages in open mailbox
5898 Tcl_SetResult(interp
,
5899 long2string(mn_get_total(sp_msgmap(ps_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(ps_global
->mail_stream
))),
5918 else if(!strcmp(op
, "selected")){
5922 * Returns: count of selected messsages in open mailbox
5925 Tcl_SetResult(interp
,
5926 long2string(any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_SLCT
)),
5930 else if(!strcmp(op
, "searched")){
5934 * Returns: count of searched messsages in open mailbox
5937 Tcl_SetResult(interp
,
5938 long2string(any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_SRCH
)),
5942 else if(!strcmp(op
, "mailboxname")){
5946 * Returns: string representing the name of the
5949 Tcl_SetResult(interp
, ps_global
->cur_folder
, TCL_VOLATILE
);
5952 else if(!strcmp(op
, "close")){
5956 * Returns: with global mail_stream closed
5958 peDestroyStream(ps_global
);
5961 else if(!strcmp(op
, "newmailreset")){
5963 zero_new_mail_count();
5964 sp_set_mail_box_changed(ps_global
->mail_stream
, 0);
5965 sp_set_expunge_count(ps_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(ps_global
->mail_stream
)
5983 && (count
= sp_mail_since_cmd(ps_global
->mail_stream
))){
5985 for(newest
= ps_global
->mail_stream
->nmsgs
; newest
> 1L; newest
--)
5986 if(!get_lflag(ps_global
->mail_stream
, NULL
, newest
, MN_EXLD
))
5990 format_new_mail_msg(NULL
, count
,
5991 pine_mail_fetchstructure(ps_global
->mail_stream
,
5993 intro
, from
, subject
, subjtxt
, sizeof(subject
));
5995 snprintf(s
= tmp_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(ps_global
->mail_stream
), MN_HIDE
) > 0L)
6011 ? any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_SLCT
) : 0L),
6015 else if(!strcmp(op
, "focus")){
6016 Tcl_SetResult(interp
,
6017 long2string((any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_HIDE
) > 0L)
6018 ? any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_SRCH
) : 0L),
6022 else if(!strcmp(op
, "first")){
6023 if(any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_HIDE
)){
6026 for(n
= 1L; n
<= mn_get_total(sp_msgmap(ps_global
->mail_stream
)); n
++)
6027 if(!get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), n
, MN_HIDE
)){
6028 Tcl_SetResult(interp
, long2string(n
), TCL_VOLATILE
);
6032 unzoom_index(ps_global
, ps_global
->mail_stream
, sp_msgmap(ps_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(ps_global
->mail_stream
)) <= 0
6052 || ((n
= mn_get_cur(sp_msgmap(ps_global
->mail_stream
))) > 0
6053 && (u
= mail_uid(ps_global
->mail_stream
, mn_m2raw(sp_msgmap(ps_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(ps_global
->mail_stream
), MN_HIDE
)){
6065 for(n
= mn_get_total(sp_msgmap(ps_global
->mail_stream
)); n
> 0L; n
--)
6066 if(!get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), n
, MN_HIDE
)){
6067 Tcl_SetResult(interp
, long2string(n
), TCL_VOLATILE
);
6072 Tcl_SetResult(interp
, long2string(mn_get_total(sp_msgmap(ps_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; ps_global
->sort_types
[i
] != EndofList
; i
++)
6088 if(Tcl_ListObjAppendElement(interp
,
6089 Tcl_GetObjResult(interp
),
6090 Tcl_NewStringObj(sort_name(ps_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(!ps_global
->mail_stream
|| sp_dead_stream(ps_global
->mail_stream
))
6100 Tcl_SetResult(interp
, "closed", TCL_STATIC
);
6101 else if(ps_global
->mail_stream
->rdonly
&& !IS_NEWS(ps_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(ps_global
->mail_stream
, sp_msgmap(ps_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(ps_global
->mail_stream
), msgno
)) > 0L){
6127 raw
= mail_uid(ps_global
->mail_stream
, raw
);
6128 Tcl_SetResult(interp
, long2string(raw
), TCL_VOLATILE
);
6132 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "Invalid UID for message %ld", msgno
);
6133 Tcl_SetResult(interp
, tmp_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(ps_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 senstive 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(ps_global
->mail_stream
), MN_HIDE
) != (mn_get_total(sp_msgmap(ps_global
->mail_stream
)) - (n
= any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_SLCT
)))){
6245 zoom_index(ps_global
, ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), MN_SLCT
);
6250 if(any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_HIDE
))
6251 unzoom_index(ps_global
, ps_global
->mail_stream
, sp_msgmap(ps_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 senstive 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(ps_global
->mail_stream
), MN_HIDE
) != (mn_get_total(sp_msgmap(ps_global
->mail_stream
)) - (n
= any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_SRCH
))))
6276 zoom_index(ps_global
, ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), MN_SRCH
);
6281 if(any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_HIDE
))
6282 unzoom_index(ps_global
, ps_global
->mail_stream
, sp_msgmap(ps_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(ps_global
->mail_stream
), msgno
);
6302 mn_inc_cur(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), MH_NONE
);
6303 Tcl_SetResult(interp
, long2string(mn_get_cur(sp_msgmap(ps_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; ps_global
->sort_types
[i
] != EndofList
; i
++)
6328 if(strucmp(sort_name(ps_global
->sort_types
[i
]), sort
) == 0){
6329 if(sp_unsorted_newmail(ps_global
->mail_stream
)
6330 || !(ps_global
->sort_types
[i
] == mn_get_sort(sp_msgmap(ps_global
->mail_stream
))
6331 && mn_get_revsort(sp_msgmap(ps_global
->mail_stream
)) == reversed
))
6332 sort_folder(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
),
6333 ps_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(ps_global
->mail_stream
), msgno
);
6365 mn_inc_cur(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), MH_NONE
);
6369 mn_dec_cur(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), MH_NONE
);
6373 Tcl_SetResult(interp
, long2string(mn_get_cur(sp_msgmap(ps_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(ps_global
->mail_stream
)))){
6395 mn_set_cur(sp_msgmap(ps_global
->mail_stream
), msgno
);
6398 long n
= mn_get_cur(sp_msgmap(ps_global
->mail_stream
));
6400 if(peAppListF(interp
, Tcl_GetObjResult(interp
),
6401 "%l%l", n
, mail_uid(ps_global
->mail_stream
,
6402 mn_m2raw(sp_msgmap(ps_global
->mail_stream
), n
))) != TCL_OK
)
6405 mn_inc_cur(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), MH_NONE
);
6407 if(n
== mn_get_cur(sp_msgmap(ps_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 messsages 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(ps_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(ps_global
->mail_stream
, sp_msgmap(ps_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(ps_global
->mail_stream
)); n
++)
6448 if(!get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_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(ps_global
->mail_stream
), msgno
);
6476 msgno
= mn_get_cur(sp_msgmap(ps_global
->mail_stream
));
6478 if(get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), msgno
, MN_SLCT
))
6479 if(Tcl_ListObjAppendElement(interp
,
6480 Tcl_GetObjResult(interp
),
6481 Tcl_NewLongObj((long) mail_uid(ps_global
->mail_stream
, msgno
))) != TCL_OK
)
6484 mn_inc_cur(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), MH_NONE
);
6486 if(msgno
== mn_get_cur(sp_msgmap(ps_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(ps_global
->mail_stream
, mn_m2raw(sp_msgmap(ps_global
->mail_stream
), n
));
6520 mn_set_cur(sp_msgmap(ps_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(ps_global
->mail_stream
))), -1)) == TCL_OK
6558 && Tcl_ListObjAppendElement(interp
,
6559 Tcl_GetObjResult(interp
),
6560 Tcl_NewStringObj(mn_get_revsort(sp_msgmap(ps_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(ps_global
->def_sort
), -1)) == TCL_OK
6571 && Tcl_ListObjAppendElement(interp
,
6572 Tcl_GetObjResult(interp
),
6573 Tcl_NewStringObj(ps_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(ps_global
->mail_stream
), MN_HIDE
) > 0L;
6589 mm_search_stream
= ps_global
->mail_stream
;
6590 mm_search_count
= 0L;
6592 for(n
= 1L; n
<= ps_global
->mail_stream
->nmsgs
; n
++)
6593 if((mc
= mail_elt(ps_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(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), NULL
, 1);
6617 else if(matchflag
& MN_SRCH
){
6618 for(n
= 1L; n
<= ps_global
->mail_stream
->nmsgs
; n
++)
6619 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_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(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), &n
, 0);
6636 else if(matchflag
& MN_SRCH
){
6637 for(n
= 1L; n
<= ps_global
->mail_stream
->nmsgs
; n
++)
6638 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_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
<= ps_global
->mail_stream
->nmsgs
; n
++)
6648 if(get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), n
, MN_SRCH
)){
6650 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_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
<= ps_global
->mail_stream
->nmsgs
; n
++)
6660 if(get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), n
, MN_SRCH
)){
6662 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_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
<= ps_global
->mail_stream
->nmsgs
; n
++)
6723 if((mc
= mail_elt(ps_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(ps_global
->mail_stream
)); i
++)
6750 if(mail_elt(ps_global
->mail_stream
,
6751 mn_m2raw(sp_msgmap(ps_global
->mail_stream
), i
))->searched
){
6752 if(get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_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(ps_global
->mail_stream
)); i
++)
6766 /* turning OFF selectedness if the "searched" bit isn't lit. */
6767 if(get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), i
, matchflag
)){
6768 if(!mail_elt(ps_global
->mail_stream
,
6769 mn_m2raw(sp_msgmap(ps_global
->mail_stream
), i
))->searched
){
6771 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), i
, matchflag
, 0);
6773 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), i
, MN_HIDE
, 1);
6775 else if(msgno
< mn_get_cur(sp_msgmap(ps_global
->mail_stream
)))
6779 else if(mail_elt(ps_global
->mail_stream
,mn_m2raw(sp_msgmap(ps_global
->mail_stream
),i
))->searched
){
6780 /* turn ON selectedness if "searched" bit is lit. */
6781 if(!get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), i
, matchflag
)){
6783 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), i
, matchflag
, 1);
6785 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), i
, MN_HIDE
, 0);
6789 /* if we're zoomed and the current message was unselected */
6791 && get_lflag(ps_global
->mail_stream
,sp_msgmap(ps_global
->mail_stream
),mn_get_cur(sp_msgmap(ps_global
->mail_stream
)),MN_HIDE
))
6792 mn_reset_cur(sp_msgmap(ps_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(ps_global
->mail_stream
))){
6825 if(last
>= 1L && last
<= mn_get_total(sp_msgmap(ps_global
->mail_stream
))){
6826 for(n
= first
; n
<= last
; n
++)
6827 mm_searched(ps_global
->mail_stream
,
6828 mn_m2raw(sp_msgmap(ps_global
->mail_stream
), n
));
6831 return(peSelectError(interp
, "last out of range"));
6834 mm_searched(ps_global
->mail_stream
,
6835 mn_m2raw(sp_msgmap(ps_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(ps_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(ps_global
->mail_stream
,
6910 sp_msgmap(ps_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(ps_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(ps_global
->mail_stream
)); i
++)
7105 if(get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_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(ps_global
->mail_stream
)); i
++)
7115 if(get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_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(ps_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(ps_global
, sp_msgmap(ps_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(ps_global
, sp_msgmap(ps_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(ps_global
->mail_stream
)); n
++){
7175 rawno
= mn_m2raw(sp_msgmap(ps_global
->mail_stream
), n
);
7176 if(get_lflag(ps_global
->mail_stream
, NULL
, rawno
, MN_SLCT
)
7177 && peIsFlagged(ps_global
->mail_stream
,
7178 mail_uid(ps_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(ps_global
->mail_stream
, sp_msgmap(ps_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
= ps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
7229 if((folder
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7230 if(pseudo_selected(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
))){
7232 if(!READONLY_FOLDER(ps_global
->mail_stream
)
7233 && F_OFF(F_SAVE_WONT_DELETE
, ps_global
))
7236 if(colid
== 0 && !strucmp(folder
, "inbox"))
7237 flgs
|= SV_INBOXWOCNTXT
;
7239 i
= save(ps_global
, ps_global
->mail_stream
,
7240 cp
, folder
, sp_msgmap(ps_global
->mail_stream
), flgs
);
7242 err
= (i
== mn_total_cur(sp_msgmap(ps_global
->mail_stream
))) ? NULL
: "problem saving";
7244 restore_selected(sp_msgmap(ps_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
= ps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
7277 if((folder
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7278 if(pseudo_selected(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
))){
7280 if(colid
== 0 && !strucmp(folder
, "inbox"))
7281 flgs
|= SV_INBOXWOCNTXT
;
7283 i
= save(ps_global
, ps_global
->mail_stream
,
7284 cp
, folder
, sp_msgmap(ps_global
->mail_stream
), flgs
);
7286 err
= (i
== mn_total_cur(sp_msgmap(ps_global
->mail_stream
))) ? NULL
: "problem copying";
7288 restore_selected(sp_msgmap(ps_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
= ps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
7321 if((folder
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7322 if(pseudo_selected(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
))){
7326 if(colid
== 0 && !strucmp(folder
, "inbox"))
7327 flgs
|= SV_INBOXWOCNTXT
;
7329 i
= save(ps_global
, ps_global
->mail_stream
,
7330 cp
, folder
, sp_msgmap(ps_global
->mail_stream
), flgs
);
7332 err
= (i
== mn_total_cur(sp_msgmap(ps_global
->mail_stream
))) ? NULL
: "problem moving";
7334 restore_selected(sp_msgmap(ps_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(ps_global
->mail_stream
)); n
++){
7364 rawno
= mn_m2raw(sp_msgmap(ps_global
->mail_stream
), n
);
7365 if(get_lflag(ps_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
= ps_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";
7577 case iSubjKeyInitText
:
7586 case iNewsAndRecips
:
7587 name
= "News/Recip";
7590 case iRecipsAndNews
:
7591 name
= "Recip/News";
7599 if(cdesc
->width
> 0){
7600 int p
= ((cdesc
->width
* 100) / FAKE_SCREEN_WIDTH
);
7602 snprintf(wbuf
, sizeof(wbuf
), "%d%%", p
);
7607 if(peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s%s", name
, wbuf
, dname
) != TCL_OK
)
7616 peNewMailResult(Tcl_Interp
*interp
)
7618 unsigned long n
, uid
;
7620 if(sp_mail_box_changed(ps_global
->mail_stream
)){
7621 if((n
= sp_mail_since_cmd(ps_global
->mail_stream
)) != 0L){
7622 /* first element is count of new messages */
7623 if(Tcl_ListObjAppendElement(interp
,
7624 Tcl_GetObjResult(interp
),
7625 Tcl_NewLongObj(n
)) != TCL_OK
)
7628 /* second element is UID of most recent message */
7629 for(uid
= ps_global
->mail_stream
->nmsgs
; uid
> 1L; uid
--)
7630 if(!get_lflag(ps_global
->mail_stream
, NULL
, uid
, MN_EXLD
))
7634 Tcl_ResetResult(interp
);
7635 Tcl_SetResult(interp
, "0 0 0", TCL_STATIC
);
7639 uid
= mail_uid(ps_global
->mail_stream
, uid
);
7641 if(Tcl_ListObjAppendElement(interp
,
7642 Tcl_GetObjResult(interp
),
7643 Tcl_NewLongObj(uid
)) != TCL_OK
)
7647 if(Tcl_ListObjAppendElement(interp
,
7648 Tcl_GetObjResult(interp
),
7649 Tcl_NewIntObj(0)) != TCL_OK
)
7652 /* zero is UID of new message */
7653 if(Tcl_ListObjAppendElement(interp
,
7654 Tcl_GetObjResult(interp
),
7655 Tcl_NewIntObj(0)) != TCL_OK
)
7659 /* third element is expunge count */
7660 if(Tcl_ListObjAppendElement(interp
,
7661 Tcl_GetObjResult(interp
),
7662 Tcl_NewLongObj(sp_expunge_count(ps_global
->mail_stream
)
7663 ? sp_expunge_count(ps_global
->mail_stream
)
7669 Tcl_SetResult(interp
, "0 0 0", TCL_STATIC
);
7675 /* * * * * * * * Start of Per-Thread/SubThread access functions * * * * * * * */
7679 * PEThreadCmd - access/manipulate various pieces of thread state
7682 PEThreadCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
7684 char *err
, errbuf
[256], *cmd
, *op
;
7688 dprint((2, "PEThreadCmd"));
7690 snprintf(err
= errbuf
, sizeof(errbuf
), "Unknown %s request",
7691 Tcl_GetStringFromObj(objv
[0], NULL
));
7693 if(!(ps_global
&& ps_global
->mail_stream
)){
7694 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: No open mailbox",
7695 Tcl_GetStringFromObj(objv
[0], NULL
));
7698 Tcl_WrongNumArgs(interp
, 1, objv
, "uid cmd ?args?");
7700 else if(Tcl_GetLongFromObj(interp
, objv
[1], &uidl
) != TCL_OK
){
7701 return(TCL_ERROR
); /* conversion problem? */
7703 else if(!peSequenceNumber(uidl
)){
7704 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: UID %ld doesn't exist",
7705 Tcl_GetStringFromObj(objv
[0], NULL
), uidl
);
7707 else if((cmd
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7710 if(!strucmp(cmd
,"info")){
7711 #define WP_MAX_THRD_PREFIX 256
7714 char tstr
[WP_MAX_THRD_PREFIX
];
7716 if((raw
= peSequenceNumber(uid
)) != 0L){
7718 * translate PINETHRD_S data into
7720 if((pthrd
= msgno_thread_info(ps_global
->mail_stream
, raw
, NULL
, THD_TOP
)) != NULL
){
7723 /* BUG: build tstr form pthrd */
7726 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
7727 Tcl_NewStringObj(tstr
, -1));
7731 Tcl_SetResult(interp
, "0", TCL_STATIC
);
7738 if(!strucmp(cmd
,"flag")){
7739 if((op
= Tcl_GetStringFromObj(objv
[3], NULL
)) != NULL
){
7740 if(!strucmp(op
,"deleted")){
7743 if(Tcl_GetIntFromObj(interp
, objv
[4], &value
) != TCL_ERROR
){
7749 if(!(n
= peSequenceNumber(uid
))){
7750 Tcl_SetResult(interp
, "Unrecognized UID", TCL_STATIC
);
7754 flag
= cpystr("\\DELETED");
7755 mail_flag(ps_global
->mail_stream
, long2string(n
), flag
, (value
? ST_SET
: 0L));
7756 fs_give((void **) &flag
);
7758 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
7759 Tcl_NewStringObj(ulong2string(uid
), -1));
7761 if(++n
<= ps_global
->mail_stream
->nmsgs
){
7762 uid
= mail_uid(ps_global
->mail_stream
, n
);
7767 if((pthrd
= msgno_thread_info(ps_global
->mail_stream
, n
, NULL
,THD_TOP
)) != NULL
){
7779 Tcl_SetResult(interp
, err
, TCL_STATIC
);
7785 /* * * * * * * * Start of Per-Message access functions * * * * * * * */
7789 static struct _message_cmds
{
7794 int (*f
)(Tcl_Interp
*, imapuid_t
, int, Tcl_Obj
**);
7796 } message_cmds
[] = {
7797 {"size", 1, {{3, peMessageSize
}}},
7798 {"date", 2, {{3, peMessageDate
}, {4, peMessageDate
}}},
7799 {"subject", 1, {{3, peMessageSubject
}}},
7800 {"fromaddr", 1, {{3, peMessageFromAddr
}}},
7801 {"toaddr", 1, {{3, peMessageToAddr
}}},
7802 {"ccaddr", 1, {{3, peMessageCcAddr
}}},
7803 {"status", 1, {{3, peMessageStatus
}}},
7804 {"statusbits", 1, {{3, peMessageStatusBits
}}},
7805 {"charset", 1, {{3, peMessageCharset
}}},
7806 {"number", 1, {{3, peMsgnoFromUID
}}},
7809 {"text", 1, {{3, peMessageText
}}},
7810 {"header", 1, {{3, peMessageHeader
}}},
7811 {"attachments", 1, {{3, peMessageAttachments
}}},
7812 {"body", 3, {{3, peMessageBody
}, {4, peMessageBody
}}},
7813 {"cid", 1, {{4, peMessagePartFromCID
}}},
7814 {"flag", 2, {{4, peGetFlag
}, {5, peSetFlag
}}},
7815 {"replyheaders", 2, {{3, peReplyHeaders
},{4, peReplyHeaders
}}},
7816 {"replytext", 2, {{4, peReplyText
}, {5, peReplyText
}}},
7817 {"forwardheaders", 2, {{3, peForwardHeaders
}, {4, peForwardHeaders
}}},
7818 {"forwardtext", 2, {{3, peForwardText
}, {4, peForwardText
}}},
7820 {"select", 2, {{3, peMsgSelect
}, {4, peMsgSelect
}}},
7821 {"detach", 1, {{5, peDetach
}}},
7822 {"attachinfo", 1, {{4, peAttachInfo
}}},
7823 {"savedefault", 1, {{3, peSaveDefault
}}},
7824 {"save", 1, {{5, peSave
}}},
7825 {"copy", 1, {{5, peCopy
}}},
7826 {"move", 1, {{5, peMove
}}},
7827 {"takeaddr", 1, {{3, peTakeaddr
}}},
7828 {"takefrom", 1, {{3, peTakeFrom
}}},
7829 {"replyquote", 1, {{3, peReplyQuote
}}},
7830 {"bounce", 2, {{4, peMessageBounce
},{5, peMessageBounce
}}},
7831 {"spam", 1, {{5, peMessageSpamNotice
}}},
7832 {"needpasswd", 1, {{3, peMessageNeedPassphrase
}}},
7840 * PEMessageCmd - export various bits of message information
7842 * NOTE: all exported commands are of the form:
7844 * PEMessage <uid> <cmd> <args>
7847 PEMessageCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
7849 char *err
, errbuf
[256], *cmd
;
7854 dprint((5, "PEMessageCmd"));
7856 snprintf(err
= errbuf
, sizeof(errbuf
), "Unknown %s request",
7857 Tcl_GetStringFromObj(objv
[0], NULL
));
7859 if(!(ps_global
&& ps_global
->mail_stream
)){
7860 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: No open mailbox",
7861 Tcl_GetStringFromObj(objv
[0], NULL
));
7864 Tcl_WrongNumArgs(interp
, 0, objv
, "PEMessage <uid> cmd ?args?");
7866 else if(Tcl_GetLongFromObj(interp
, objv
[1], &uidl
) != TCL_OK
){
7867 return(TCL_ERROR
); /* conversion problem? */
7869 else if(!peMessageNumber(uidl
)){
7870 snprintf(err
= errbuf
, sizeof(errbuf
), "%s: UID %ld doesn't exist",
7871 Tcl_GetStringFromObj(objv
[0], NULL
), uidl
);
7873 else if((cmd
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
7875 for(i
= 0; message_cmds
[i
].cmd
; i
++)
7876 if(!strcmp(cmd
, message_cmds
[i
].cmd
)){
7877 for(j
= 0; j
< message_cmds
[i
].hcount
; j
++)
7878 if(message_cmds
[i
].h
[j
].argcount
== objc
)
7879 return((*message_cmds
[i
].h
[j
].f
)(interp
, uid
, objc
- 3,
7880 &((Tcl_Obj
**)objv
)[3]));
7882 snprintf(err
= errbuf
, sizeof(errbuf
),
7883 "PEMessage: %s: mismatched argument count", cmd
);
7888 Tcl_SetResult(interp
, err
, TCL_STATIC
);
7894 * return the uid's ordinal number within the CURRENT SORT
7897 peMessageNumber(imapuid_t uid
)
7899 return(mn_raw2m(sp_msgmap(ps_global
->mail_stream
), peSequenceNumber(uid
)));
7903 * return the uid's RAW message number (for c-client reference, primarily)
7906 peSequenceNumber(imapuid_t uid
)
7908 return(mail_msgno(ps_global
->mail_stream
, uid
));
7913 peMessageSize(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7917 if((raw
= peSequenceNumber(uid
))
7918 && pine_mail_fetchstructure(ps_global
->mail_stream
, raw
, NULL
)){
7919 Tcl_SetResult(interp
,
7920 long2string(mail_elt(ps_global
->mail_stream
,
7925 Tcl_SetResult(interp
, "0", TCL_STATIC
);
7932 peMessageDate(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7939 if((raw
= peSequenceNumber(uid
))
7940 && (env
= pine_mail_fetchstructure(ps_global
->mail_stream
, raw
, NULL
))){
7941 if(objc
== 1 && objv
[0]){
7942 if(mail_parse_date(&mc
, env
->date
)){
7943 if((cmd
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
){
7944 if(!strucmp(cmd
,"day")){
7945 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%02d", mc
.day
);
7946 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
7949 else if(!strucmp(cmd
,"month")){
7950 Tcl_SetResult(interp
, month_abbrev(mc
.month
), TCL_VOLATILE
);
7953 else if(!strucmp(cmd
,"year")){
7954 Tcl_SetResult(interp
, int2string(mc
.year
+ BASEYEAR
), TCL_VOLATILE
);
7958 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "peMessageDate cmd: %.20s", cmd
);
7959 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
7963 Tcl_SetResult(interp
, "peMessageDate: can't get command", TCL_STATIC
);
7966 Tcl_SetResult(interp
, "peMessageDate: can't parse date", TCL_STATIC
);
7969 Tcl_SetResult(interp
, env
->date
? (char *) env
->date
: "", TCL_VOLATILE
);
7974 Tcl_SetResult(interp
, "Can't get message structure", TCL_STATIC
);
7981 peMessageFromAddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7983 return(peMessageField(interp
, uid
, "from"));
7988 peMessageToAddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7990 return(peMessageField(interp
, uid
, "to"));
7995 peMessageCcAddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
7997 return(peMessageField(interp
, uid
, "cc"));
8002 peMessageSubject(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8004 return(peMessageField(interp
, uid
, "subject"));
8009 peMessageField(Tcl_Interp
*interp
, imapuid_t uid
, char *field
)
8015 if((raw
= peSequenceNumber(uid
))
8016 && (env
= pine_mail_fetchstructure(ps_global
->mail_stream
, raw
, NULL
))){
8017 if(!strucmp(field
, "from")){
8018 if(env
->from
&& env
->from
->mailbox
)
8019 snprintf(s
= tmp_20k_buf
, SIZEOF_20KBUF
, "%.256s%s%.256s", env
->from
->mailbox
,
8020 (env
->from
->host
) ? "@" : "", (env
->from
->host
) ? env
->from
->host
: "");
8022 else if(!strucmp(field
, "to")){
8023 if(env
->to
&& env
->to
->mailbox
)
8024 snprintf(s
= tmp_20k_buf
, SIZEOF_20KBUF
, "%.256s%s%.256s", env
->to
->mailbox
,
8025 (env
->to
->host
) ? "@" : "", (env
->to
->host
) ? env
->to
->host
: "");
8027 else if(!strucmp(field
, "cc")){
8028 if(env
->cc
&& env
->cc
->mailbox
)
8029 snprintf(s
= tmp_20k_buf
, SIZEOF_20KBUF
, "%.256s%s%.256s", env
->cc
->mailbox
,
8030 (env
->cc
->host
) ? "@" : "", (env
->cc
->host
) ? env
->cc
->host
: "");
8032 else if(!strucmp(field
, "subject")){
8034 snprintf(s
= tmp_20k_buf
, SIZEOF_20KBUF
, "%.256s", env
->subject
);
8037 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "Unknown message field: %.20s", field
);
8038 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
8042 Tcl_SetResult(interp
, s
, TCL_VOLATILE
);
8046 Tcl_SetResult(interp
, "Can't read message envelope", TCL_STATIC
);
8052 peMessageStatus(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8057 if((raw
= peSequenceNumber(uid
)) != 0L){
8058 if(!((mc
= mail_elt(ps_global
->mail_stream
, raw
))
8060 mail_fetch_flags(ps_global
->mail_stream
,
8061 ulong2string(uid
), FT_UID
);
8062 mc
= mail_elt(ps_global
->mail_stream
, raw
);
8066 Tcl_ListObjAppendElement(interp
,
8067 Tcl_GetObjResult(interp
),
8068 Tcl_NewStringObj("Deleted", -1));
8071 Tcl_ListObjAppendElement(interp
,
8072 Tcl_GetObjResult(interp
),
8073 Tcl_NewStringObj("Answered", -1));
8076 Tcl_ListObjAppendElement(interp
,
8077 Tcl_GetObjResult(interp
),
8078 Tcl_NewStringObj("New", -1));
8081 Tcl_ListObjAppendElement(interp
,
8082 Tcl_GetObjResult(interp
),
8083 Tcl_NewStringObj("Important", -1));
8091 peMessageCharset(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8093 /* everthing coming out of pith better be utf-8 */
8094 Tcl_SetResult(interp
, "UTF-8", TCL_STATIC
);
8100 peMessageNeedPassphrase(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8103 return((ps_global
&& ps_global
->smime
&& ps_global
->smime
->need_passphrase
) ? TCL_OK
: TCL_ERROR
);
8111 peMsgnoFromUID(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8113 Tcl_SetResult(interp
, long2string(peMessageNumber(uid
)), TCL_VOLATILE
);
8119 * peInterpWritec - collect filtered output, appending to the
8120 * command's result list on each EOL
8123 peInterpWritec(int c
)
8125 unsigned char ch
= (unsigned char) (0xff & c
);
8128 return(peInterpFlush() == TCL_OK
);
8130 so_writec(ch
, peED
.store
);
8137 * peInterpFlush - write accumulated line to result object mapping
8138 * embedded data into exportable tcl list members
8144 char *line
, *p
, *tp
, *tp2
, col1
[32], col2
[32];
8145 Tcl_Obj
*lobjp
, *objColor
, *objPair
;
8147 line
= (char *) so_text(peED
.store
);
8149 if((lobjp
= Tcl_NewListObj(0, NULL
)) != NULL
){
8150 if((p
= strindex(line
, TAG_EMBED
)) != NULL
){
8155 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", line
);
8164 for(n
= 0, i
= *++p
; i
> 0; i
--)
8165 n
= (n
* 10) + (*++p
- '0');
8167 line
= ++p
; /* prepare for next section of line */
8172 if((h
= get_handle(peED
.handles
, n
)) != NULL
)
8176 Tcl_Obj
*llObj
, *rObj
;
8178 llObj
= Tcl_NewListObj(0, NULL
);
8179 Tcl_ListObjAppendElement(peED
.interp
, llObj
, Tcl_NewStringObj("img", -1));
8181 rObj
= Tcl_NewListObj(0, NULL
);
8182 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.img
.src
? h
->h
.img
.src
: "", -1));
8183 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.img
.alt
? h
->h
.img
.alt
: "", -1));
8185 Tcl_ListObjAppendElement(peED
.interp
, llObj
, rObj
);
8187 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, llObj
);
8195 Tcl_Obj
*llObj
, *rObj
;
8197 llObj
= Tcl_NewListObj(0, NULL
);
8198 Tcl_ListObjAppendElement(peED
.interp
, llObj
, Tcl_NewStringObj("urlstart", -1));
8200 rObj
= Tcl_NewListObj(0, NULL
);
8201 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.url
.path
? h
->h
.url
.path
: "", -1));
8202 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.url
.name
? h
->h
.url
.name
: "", -1));
8204 Tcl_ListObjAppendElement(peED
.interp
, llObj
, rObj
);
8206 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, llObj
);
8213 Tcl_Obj
*alObj
, *rObj
, *tObj
, *stObj
, *fnObj
, *eObj
;
8215 alObj
= Tcl_NewListObj(0, NULL
);
8216 Tcl_ListObjAppendElement(peED
.interp
, alObj
, Tcl_NewStringObj("attach", -1));
8218 peGetMimeTyping(mail_body(ps_global
->mail_stream
,
8219 peSequenceNumber(peED
.uid
),
8220 (unsigned char *) h
->h
.attach
->number
),
8221 &tObj
, &stObj
, &fnObj
, &eObj
);
8224 rObj
= Tcl_NewListObj(0, NULL
);
8225 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewLongObj(peED
.uid
));
8226 Tcl_ListObjAppendElement(peED
.interp
, rObj
, Tcl_NewStringObj(h
->h
.attach
->number
, -1));
8227 Tcl_ListObjAppendElement(peED
.interp
, rObj
, tObj
);
8228 Tcl_ListObjAppendElement(peED
.interp
, rObj
, stObj
);
8229 Tcl_ListObjAppendElement(peED
.interp
, rObj
, fnObj
);
8230 Tcl_ListObjAppendElement(peED
.interp
, rObj
, eObj
);
8232 Tcl_ListObjAppendElement(peED
.interp
, alObj
, rObj
);
8234 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, alObj
);
8248 if((tp
= peColorStr(++p
, col1
)) && (strcmp(tp
, peED
.color
.fg
) || strcmp(tp
, peED
.color
.fgdef
))){
8250 if(p
[11] == TAG_EMBED
8251 && p
[12] == TAG_BGCOLOR
8252 && (tp2
= peColorStr(p
+ 13, col2
))){
8253 objColor
= Tcl_NewListObj(0, NULL
);
8254 objPair
= Tcl_NewListObj(0, NULL
);
8255 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8256 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8257 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp2
, -1));
8258 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8259 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8260 strcpy(peED
.color
.bg
, tp2
);
8263 else if(strcmp(peED
.color
.bg
, peED
.color
.bgdef
)){
8264 objColor
= Tcl_NewListObj(0, NULL
);
8265 objPair
= Tcl_NewListObj(0, NULL
);
8266 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8267 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8268 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(peED
.color
.bgdef
, -1));
8269 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8270 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8271 strcpy(peED
.color
.bg
, peED
.color
.bgdef
);
8274 peAppListF(peED
.interp
, lobjp
, "%s%s", "fgcolor", tp
);
8276 strcpy(peED
.color
.fg
, tp
);
8283 if((tp
= peColorStr(++p
, col1
)) && (strcmp(tp
, peED
.color
.bg
) || strcmp(tp
, peED
.color
.bgdef
))){
8285 if(p
[11] == TAG_EMBED
8286 && p
[12] == TAG_FGCOLOR
8287 && (tp2
= peColorStr(p
+ 13, col2
))){
8288 objColor
= Tcl_NewListObj(0, NULL
);
8289 objPair
= Tcl_NewListObj(0, NULL
);
8290 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8291 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp2
, -1));
8292 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8293 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8294 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8295 strcpy(peED
.color
.fg
, tp2
);
8298 else if(strcmp(peED
.color
.fg
, peED
.color
.fgdef
)){
8299 objColor
= Tcl_NewListObj(0, NULL
);
8300 objPair
= Tcl_NewListObj(0, NULL
);
8301 Tcl_ListObjAppendElement(peED
.interp
, objColor
, Tcl_NewStringObj("color", -1));
8302 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(peED
.color
.fgdef
, -1));
8303 Tcl_ListObjAppendElement(peED
.interp
, objPair
, Tcl_NewStringObj(tp
, -1));
8304 Tcl_ListObjAppendElement(peED
.interp
, objColor
, objPair
);
8305 Tcl_ListObjAppendElement(peED
.interp
, lobjp
, objColor
);
8306 strcpy(peED
.color
.fg
, peED
.color
.fgdef
);
8309 peAppListF(peED
.interp
, lobjp
, "%s%s", "bgcolor", tp
);
8311 strcpy(peED
.color
.bg
, tp
);
8318 peAppListF(peED
.interp
, lobjp
, "%s%s", "italic", "on");
8322 case TAG_ITALICOFF
:
8323 peAppListF(peED
.interp
, lobjp
, "%s%s", "italic", "off");
8328 peAppListF(peED
.interp
, lobjp
, "%s%s", "bold", "on");
8333 peAppListF(peED
.interp
, lobjp
, "%s%s", "bold", "off");
8338 peAppListF(peED
.interp
, lobjp
, "%s%s", "underline", "on");
8343 peAppListF(peED
.interp
, lobjp
, "%s%s", "underline", "off");
8348 peAppListF(peED
.interp
, lobjp
, "%s%s", "strikethru", "on");
8352 case TAG_STRIKEOFF
:
8353 peAppListF(peED
.interp
, lobjp
, "%s%s", "strikethru", "off");
8358 peAppListF(peED
.interp
, lobjp
, "%s%s", "bigfont", "on");
8363 peAppListF(peED
.interp
, lobjp
, "%s%s", "bigfont", "off");
8368 peAppListF(peED
.interp
, lobjp
, "%s%s", "smallfont", "on");
8373 peAppListF(peED
.interp
, lobjp
, "%s%s", "smallfont", "off");
8378 case TAG_HANDLEOFF
:
8380 peAppListF(peED
.interp
, lobjp
, "%s%s", "urlend", "");
8383 /* fall thru and advance "line" */
8391 while((p
= strindex(line
, TAG_EMBED
)) != NULL
);
8394 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", line
);
8397 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", line
);
8400 peAppListF(peED
.interp
, lobjp
, "%s%s", "t", "");
8402 if(Tcl_ListObjAppendElement(peED
.interp
, peED
.obj
, lobjp
) == TCL_OK
){
8403 so_truncate(peED
.store
, 0L);
8413 * peInterpWritec - collect filtered output, appending to the
8414 * command's result list on each EOL
8424 peColorStr(char *s
, char *b
)
8432 for(j
= 0; j
< 3; j
++, s
++)
8433 if(isdigit((unsigned char) *s
))
8434 color
= (color
* 10) + (*s
- '0');
8436 s
++; /* advance past ',' */
8438 sprintf(b
+ strlen(b
), "%2.2x", color
);
8452 * returns a list of elements
8455 peMessageHeader(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8459 int flags
, rv
= TCL_OK
;
8466 * ONLY full header mode (raw) output should get written to the
8467 * writec function we pass format_header. If there's something
8468 * in the store after formatting ,we'll write it to the Tcl result
8469 * then, not as its accumulated
8471 peED
.interp
= interp
;
8472 peED
.obj
= Tcl_NewStringObj("", -1);
8475 so_seek(peED
.store
, 0L, 0);
8477 peED
.store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
8479 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_NOHTMLREL
| FM_HTMLRELATED
;
8482 peED
.color
.fg
[0] = '\0';
8483 if((color
= pico_get_last_fg_color()) && (color
= color_to_asciirgb(color
))){
8484 peInterpWritec(TAG_EMBED
);
8485 peInterpWritec(TAG_FGCOLOR
);
8486 gf_puts(color
, peInterpWritec
);
8487 strcpy(peED
.color
.fgdef
, peColorStr(color
, tmp_20k_buf
));
8490 peED
.color
.bg
[0] = '\0';
8491 if((color
= pico_get_last_bg_color()) && (color
= color_to_asciirgb(color
))){
8492 peInterpWritec(TAG_EMBED
);
8493 peInterpWritec(TAG_BGCOLOR
);
8494 gf_puts(color
, peInterpWritec
);
8495 strcpy(peED
.color
.bgdef
, peColorStr(color
,tmp_20k_buf
));
8501 raw
= peSequenceNumber(uid
);
8502 if(peED
.uid
!= uid
){
8506 ps_global
->c_client_error
[0] = ps_global
->last_error
[0] = '\0';
8507 if(!((peED
.env
= pine_mail_fetchstructure(ps_global
->mail_stream
, raw
, &peED
.body
))
8508 && (mc
= mail_elt(ps_global
->mail_stream
, raw
)))){
8511 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
8512 ps_global
->last_error
[0] ? ps_global
->last_error
: "Indeterminate");
8514 dprint((1, "ERROR fetching %s of msg %ld: %s",
8515 peED
.env
? "elt" : "env", mn_get_cur(sp_msgmap(ps_global
->mail_stream
)),
8516 ps_global
->last_error
[0] ? ps_global
->last_error
: "Indeterminate"));
8518 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8522 zero_atmts(ps_global
->atmts
);
8524 if(ps_global
&& ps_global
->smime
&& ps_global
->smime
->need_passphrase
)
8525 ps_global
->smime
->need_passphrase
= 0;
8527 fiddle_smime_message(peED
.body
, raw
);
8529 describe_mime(peED
.body
, "", 1, 1, 0, flags
);
8533 /* NO HANDLES init_handles(&peED.handles);*/
8536 * Collect header pieces into lists via the passed custom formatter. Collect
8537 * everything else in the storage object passed. The latter should only end up
8538 * with raw header data.
8540 * BUG: DEAL WITH COLORS
8543 HD_INIT(&h
, ps_global
->VAR_VIEW_HEADERS
, ps_global
->view_all_except
, FE_DEFAULT
);
8544 if(format_header(ps_global
->mail_stream
, raw
, NULL
, peED
.env
, &h
,
8545 NULL
, NULL
, flags
, peFormatEnvelope
, peInterpWritec
) != 0){
8548 snprintf(buf
, sizeof(buf
), "Error formatting header %ld", peMessageNumber(uid
));
8551 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8557 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "%s%s%o", "raw", "", peED
.obj
);
8559 so_give(&peED
.store
);
8564 peFormatEnvelope(MAILSTREAM
*s
, long int n
, char *sect
, ENVELOPE
*e
, gf_io_t pc
, long int which
, char *oacs
, int flags
)
8566 char *p2
, buftmp
[MAILTMPLEN
];
8572 if((which
& FE_DATE
) && e
->date
) {
8573 if((objHdr
= Tcl_NewListObj(0, NULL
)) != NULL
){
8574 snprintf(buftmp
, sizeof(buftmp
), "%s", (char *) e
->date
);
8575 buftmp
[sizeof(buftmp
)-1] = '\0';
8576 p2
= (char *)rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
, SIZEOF_20KBUF
, buftmp
);
8577 peFormatEnvelopeText("Date", p2
);
8579 /* BUG: how does error feedback bubble back up? */
8582 if((which
& FE_FROM
) && e
->from
)
8583 peFormatEnvelopeAddress(s
, n
, sect
, "From", e
->from
, flags
, oacs
, pc
);
8585 if((which
& FE_REPLYTO
) && e
->reply_to
&& (!e
->from
|| !address_is_same(e
->reply_to
, e
->from
)))
8586 peFormatEnvelopeAddress(s
, n
, sect
, "Reply-To", e
->reply_to
, flags
, oacs
, pc
);
8588 if((which
& FE_TO
) && e
->to
)
8589 peFormatEnvelopeAddress(s
, n
, sect
, "To", e
->to
, flags
, oacs
, pc
);
8591 if((which
& FE_CC
) && e
->cc
)
8592 peFormatEnvelopeAddress(s
, n
, sect
, "Cc", e
->cc
, flags
, oacs
, pc
);
8594 if((which
& FE_BCC
) && e
->bcc
)
8595 peFormatEnvelopeAddress(s
, n
, sect
, "Bcc", e
->bcc
, flags
, oacs
, pc
);
8597 if((which
& FE_RETURNPATH
) && e
->return_path
)
8598 peFormatEnvelopeAddress(s
, n
, sect
, "Return-Path", e
->return_path
, flags
, oacs
, pc
);
8600 if((which
& FE_NEWSGROUPS
) && e
->newsgroups
)
8601 peFormatEnvelopeNewsgroups("Newsgroups", e
->newsgroups
, flags
, pc
);
8603 if((which
& FE_FOLLOWUPTO
) && e
->followup_to
)
8604 peFormatEnvelopeNewsgroups("Followup-To", e
->followup_to
, flags
, pc
);
8606 if((which
& FE_SUBJECT
) && e
->subject
&& e
->subject
[0]){
8607 if((objHdr
= Tcl_NewListObj(0, NULL
)) != NULL
){
8608 char *freeme
= NULL
;
8610 p2
= iutf8ncpy((char *)(tmp_20k_buf
+10000),
8611 (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
, 10000, e
->subject
),
8612 SIZEOF_20KBUF
-10000);
8614 if(flags
& FM_DISPLAY
8615 && (ps_global
->display_keywords_in_subject
8616 || ps_global
->display_keywordinits_in_subject
)){
8618 /* don't bother if no keywords are defined */
8619 if(some_user_flags_defined(s
))
8620 p2
= freeme
= prepend_keyword_subject(s
, n
, p2
,
8621 ps_global
->display_keywords_in_subject
? KW
: KWInit
,
8622 NULL
, ps_global
->VAR_KW_BRACES
);
8625 peFormatEnvelopeText("Subject", p2
);
8628 fs_give((void **) &freeme
);
8632 if((which
& FE_SENDER
) && e
->sender
&& (!e
->from
|| !address_is_same(e
->sender
, e
->from
)))
8633 peFormatEnvelopeAddress(s
, n
, sect
, "Sender", e
->sender
, flags
, oacs
, pc
);
8635 if((which
& FE_MESSAGEID
) && e
->message_id
){
8636 p2
= iutf8ncpy((char *)(tmp_20k_buf
+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
, 10000, e
->message_id
), SIZEOF_20KBUF
-10000);
8637 peFormatEnvelopeText("Message-ID", p2
);
8640 if((which
& FE_INREPLYTO
) && e
->in_reply_to
){
8641 p2
= iutf8ncpy((char *)(tmp_20k_buf
+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
, 10000, e
->in_reply_to
), SIZEOF_20KBUF
-10000);
8642 peFormatEnvelopeText("In-Reply-To", p2
);
8645 if((which
& FE_REFERENCES
) && e
->references
) {
8646 p2
= iutf8ncpy((char *)(tmp_20k_buf
+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
, 10000, e
->references
), SIZEOF_20KBUF
-10000);
8647 peFormatEnvelopeText("References", p2
);
8653 * appends caller's result with: {"text" field_name {field_value}}
8656 peFormatEnvelopeText(char *field_name
, char *field_value
)
8658 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "%s%s%s", "text", field_name
, field_value
);
8663 * appends caller's result with: {"addr" field_name {{{personal} {mailbox}} ... }}
8664 * {"rawaddr" field_name {{raw_address} ... }}
8667 peFormatEnvelopeAddress(MAILSTREAM
*stream
, long int msgno
, char *section
, char *field_name
,
8668 struct mail_address
*addr
, int flags
, char *oacs
, gf_io_t pc
)
8670 char *ptmp
, *mtmp
, *atype
= "addr";
8673 Tcl_Obj
*objAddrList
= NULL
;
8676 extern const char *rspecials
;
8677 extern const char *rspecials_minus_quote_and_dot
;
8683 * quickly run down address list to make sure none are patently bogus.
8684 * If so, just blat raw field out.
8686 for(atmp
= addr
; stream
&& atmp
; atmp
= atmp
->next
)
8687 if(atmp
->host
&& atmp
->host
[0] == '.'){
8688 char *field
, *fields
[2];
8691 if((objAddrList
= Tcl_NewListObj(0,NULL
)) == NULL
)
8692 return; /* BUG: handle list creation failure */
8695 fields
[0] = cpystr(field_name
);
8696 if((ptmp
= strchr(fields
[0], ':')) != NULL
)
8699 if((field
= pine_fetchheader_lines(stream
, msgno
, section
, fields
)) != NULL
){
8702 for(t
= h
= field
; *h
; t
++)
8703 if(*t
== '\015' && *(t
+1) == '\012'){
8704 *t
= '\0'; /* tie off line */
8706 Tcl_ListObjAppendElement(peED
.interp
, objAddrList
, Tcl_NewStringObj(h
,-1));
8708 if(!*(h
= (++t
) + 1)) /* set new h and skip CRLF */
8709 break; /* no more to write */
8711 else if(!*t
){ /* shouldn't happen much */
8713 Tcl_ListObjAppendElement(peED
.interp
, objAddrList
, Tcl_NewStringObj(h
,-1));
8718 fs_give((void **)&field
);
8721 fs_give((void **)&fields
[0]);
8725 if((objAddrList
= Tcl_NewListObj(0,NULL
)) == NULL
|| (tso
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
)
8726 return; /* BUG: handle list creation failure */
8728 gf_set_so_writec(&tpc
, tso
);
8732 atmp
= addr
->next
; /* remember what's next */
8734 if(!addr
->host
&& addr
->mailbox
){
8735 mtmp
= addr
->mailbox
;
8736 addr
->mailbox
= cpystr((char *)rfc1522_decode_to_utf8(
8737 (unsigned char *)tmp_20k_buf
,
8738 SIZEOF_20KBUF
, addr
->mailbox
));
8741 ptmp
= addr
->personal
; /* RFC 1522 personal name? */
8742 addr
->personal
= iutf8ncpy((char *)tmp_20k_buf
, (char *)rfc1522_decode_to_utf8((unsigned char *)(tmp_20k_buf
+10000), SIZEOF_20KBUF
-10000, addr
->personal
), 10000);
8743 tmp_20k_buf
[10000-1] = '\0';
8746 /* Logic taken from: pine_rfc822_write_address_noquote(addr, pc, &group); */
8747 if (addr
->host
) { /* ordinary address? */
8748 if (!(addr
->personal
|| addr
->adl
)){
8749 so_seek(tso
, 0L, 0);
8750 pine_rfc822_address (addr
, tpc
);
8751 peAppListF(peED
.interp
, objAddrList
, "%s%o", "", Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
)));
8753 else { /* no, must use phrase <route-addr> form */
8756 if (addr
->personal
){
8757 so_seek(tso
, 0L, 0);
8758 pine_rfc822_cat (addr
->personal
, rspecials_minus_quote_and_dot
, tpc
);
8759 objTmp
= Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
));
8762 so_seek(tso
, 0L, 0);
8763 pine_rfc822_address(addr
, tpc
);
8764 peAppListF(peED
.interp
, objAddrList
, "%o%o", objTmp
, Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
)));
8770 else if (addr
->mailbox
) { /* start of group? */
8771 so_seek(tso
, 0L, 0);
8772 /* yes, write group name */
8773 pine_rfc822_cat (addr
->mailbox
, rspecials
, tpc
);
8774 peAppListF(peED
.interp
, objAddrList
, "%o%s", Tcl_NewStringObj((char *) so_text(tso
), so_tell(tso
)), "");
8775 group
= 1; /* in a group */
8777 else if (group
) { /* must be end of group (but be paranoid) */
8778 peAppListF(peED
.interp
, objAddrList
, "%s%s", "", ";");
8779 group
= 0; /* no longer in that group */
8782 addr
->personal
= ptmp
; /* restore old personal ptr */
8783 if(!addr
->host
&& addr
->mailbox
){
8784 fs_give((void **)&addr
->mailbox
);
8785 addr
->mailbox
= mtmp
;
8792 gf_clear_so_writec(tso
);
8796 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "%s%s%o", atype
, field_name
, objAddrList
);
8801 * appends caller's result with: {"news" field_name {{newsgroup1} {newsgroup2} ... }}
8804 peFormatEnvelopeNewsgroups(char *field_name
, char *newsgrps
, int flags
, gf_io_t pc
)
8806 char buf
[MAILTMPLEN
];
8809 Tcl_Obj
*objNewsgroups
;
8811 /* BUG: handle list creation failure */
8812 if(!newsgrps
|| !*newsgrps
|| (objNewsgroups
= Tcl_NewListObj(0,NULL
)) == NULL
)
8815 llen
= strlen(field_name
);
8817 for(next_ng
= newsgrps
; *next_ng
&& *next_ng
!= ','; next_ng
++)
8820 strncpy(buf
, newsgrps
, MIN(next_ng
- newsgrps
, sizeof(buf
)-1));
8821 buf
[MIN(next_ng
- newsgrps
, sizeof(buf
)-1)] = '\0';
8823 Tcl_ListObjAppendElement(peED
.interp
, objNewsgroups
, Tcl_NewStringObj(buf
,-1));
8830 peAppListF(peED
.interp
, Tcl_GetObjResult(peED
.interp
), "news", field_name
, objNewsgroups
);
8835 peMessageAttachments(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8840 Tcl_Obj
*objAtt
, *tObj
, *stObj
, *fnObj
;
8841 int flags
, rv
= TCL_OK
;
8844 peED
.interp
= interp
;
8845 peED
.obj
= Tcl_GetObjResult(interp
);
8847 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_HTML
| FM_NOHTMLREL
| FM_HTMLRELATED
| FM_HIDESERVER
;
8849 raw
= peSequenceNumber(uid
);
8851 if(peED
.uid
!= uid
){
8852 memset(&peED
, 0, sizeof(peED
));
8856 ps_global
->c_client_error
[0] = ps_global
->last_error
[0] = '\0';
8857 if(!((peED
.env
= pine_mail_fetchstructure(ps_global
->mail_stream
, raw
, &peED
.body
))
8858 && (mc
= mail_elt(ps_global
->mail_stream
, raw
)))){
8861 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
8862 ps_global
->last_error
[0] ? ps_global
->last_error
: "Indeterminate");
8864 dprint((1, "ERROR fetching %s of msg %ld: %s",
8865 peED
.env
? "elt" : "env", mn_get_cur(sp_msgmap(ps_global
->mail_stream
)),
8866 ps_global
->last_error
[0] ? ps_global
->last_error
: "Indeterminate"));
8868 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8872 zero_atmts(ps_global
->atmts
);
8874 if(ps_global
&& ps_global
->smime
&& ps_global
->smime
->need_passphrase
)
8875 ps_global
->smime
->need_passphrase
= 0;
8877 fiddle_smime_message(peED
.body
, raw
);
8879 describe_mime(peED
.body
, "", 1, 1, 0, flags
);
8883 /* package up attachment list */
8884 for(a
= ps_global
->atmts
; rv
== TCL_OK
&& a
->description
!= NULL
; a
++)
8885 if((objAtt
= Tcl_NewListObj(0, NULL
)) != NULL
8886 && (body
= mail_body(ps_global
->mail_stream
, raw
, (unsigned char *) a
->number
)) != NULL
){
8887 peGetMimeTyping(body
, &tObj
, &stObj
, &fnObj
, NULL
);
8889 if(!(peAppListF(interp
, objAtt
, "%s", a
->number
? a
->number
: "") == TCL_OK
8890 && peAppListF(interp
, objAtt
, "%s", a
->shown
? "shown" : "") == TCL_OK
8891 && Tcl_ListObjAppendElement(interp
, objAtt
, tObj
) == TCL_OK
8892 && Tcl_ListObjAppendElement(interp
, objAtt
, stObj
) == TCL_OK
8893 && Tcl_ListObjAppendElement(interp
, objAtt
, fnObj
) == TCL_OK
8894 && peAppListF(interp
, objAtt
, "%s", a
->body
->description
) == TCL_OK
8895 && Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAtt
) == TCL_OK
))
8906 peMessageBody(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
8909 int flags
, rv
= TCL_OK
;
8913 peED
.interp
= interp
;
8914 peED
.obj
= Tcl_GetObjResult(interp
);
8917 so_seek(peED
.store
, 0L, 0);
8919 peED
.store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
8921 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_NOHTMLREL
| FM_HTMLRELATED
;
8923 if(objc
== 1 && objv
[0]){ /* flags */
8928 Tcl_ListObjGetElements(interp
, objv
[0], &nFlags
, &objFlags
);
8929 for(i
= 0; i
< nFlags
; i
++){
8930 if((flagstr
= Tcl_GetStringFromObj(objFlags
[i
], NULL
)) == NULL
){
8934 if(!strucmp(flagstr
, "html"))
8935 flags
|= (FM_HTML
| FM_HIDESERVER
);
8936 else if(!strucmp(flagstr
, "images"))
8937 flags
|= (FM_HTMLIMAGES
);
8941 peED
.color
.fg
[0] = '\0';
8942 if((color
= pico_get_last_fg_color()) && (color
= color_to_asciirgb(color
))){
8943 peInterpWritec(TAG_EMBED
);
8944 peInterpWritec(TAG_FGCOLOR
);
8945 gf_puts(color
, peInterpWritec
);
8946 strcpy(peED
.color
.fgdef
, peColorStr(color
, tmp_20k_buf
));
8949 peED
.color
.bg
[0] = '\0';
8950 if((color
= pico_get_last_bg_color()) && (color
= color_to_asciirgb(color
))){
8951 peInterpWritec(TAG_EMBED
);
8952 peInterpWritec(TAG_BGCOLOR
);
8953 gf_puts(color
, peInterpWritec
);
8954 strcpy(peED
.color
.bgdef
, peColorStr(color
,tmp_20k_buf
));
8959 init_handles(&peED
.handles
);
8961 raw
= peSequenceNumber(uid
);
8963 if(peED
.uid
!= uid
){
8967 ps_global
->c_client_error
[0] = ps_global
->last_error
[0] = '\0';
8968 if(!((peED
.env
= pine_mail_fetchstructure(ps_global
->mail_stream
, raw
, &peED
.body
))
8969 && (mc
= mail_elt(ps_global
->mail_stream
, raw
)))){
8972 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
8973 ps_global
->last_error
[0] ? ps_global
->last_error
: "Indeterminate");
8975 dprint((1, "ERROR fetching %s of msg %ld: %s",
8976 peED
.env
? "elt" : "env", mn_get_cur(sp_msgmap(ps_global
->mail_stream
)),
8977 ps_global
->last_error
[0] ? ps_global
->last_error
: "Indeterminate"));
8979 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
8983 zero_atmts(ps_global
->atmts
);
8985 if(ps_global
&& ps_global
->smime
&& ps_global
->smime
->need_passphrase
)
8986 ps_global
->smime
->need_passphrase
= 0;
8988 fiddle_smime_message(peED
.body
, raw
);
8990 describe_mime(peED
.body
, "", 1, 1, 0, flags
);
8994 /* format message body */
8999 HD_INIT(&h
, ps_global
->VAR_VIEW_HEADERS
, ps_global
->view_all_except
, FE_DEFAULT
);
9001 /* kind of a hack, the description maybe shouldn't be in the editorial stuff */
9002 if(ps_global
->smime
&& ps_global
->smime
->need_passphrase
)
9003 flags
&= ~FM_NOEDITORIAL
;
9005 if((errstr
= format_body(raw
, peED
.body
, &peED
.handles
, &h
, flags
, FAKE_SCREEN_WIDTH
, peInterpWritec
)) != NULL
){
9006 gf_puts(errstr
, peInterpWritec
);
9013 so_give(&peED
.store
);
9014 free_handles(&peED
.handles
);
9020 peMessageText(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9029 memset(&peED
, 0, sizeof(peED
));
9030 peED
.interp
= interp
;
9031 peED
.obj
= Tcl_GetObjResult(interp
);
9032 peED
.store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
9034 peED
.color
.fg
[0] = '\0';
9035 if((color
= pico_get_last_fg_color()) && (color
= color_to_asciirgb(color
))){
9036 peInterpWritec(TAG_EMBED
);
9037 peInterpWritec(TAG_FGCOLOR
);
9038 gf_puts(color
, peInterpWritec
);
9039 strcpy(peED
.color
.fgdef
, peColorStr(color
, tmp_20k_buf
));
9042 peED
.color
.bg
[0] = '\0';
9043 if((color
= pico_get_last_bg_color()) && (color
= color_to_asciirgb(color
))){
9044 peInterpWritec(TAG_EMBED
);
9045 peInterpWritec(TAG_BGCOLOR
);
9046 gf_puts(color
, peInterpWritec
);
9047 strcpy(peED
.color
.bgdef
, peColorStr(color
,tmp_20k_buf
));
9050 raw
= peSequenceNumber(peED
.uid
= uid
);
9052 ps_global
->c_client_error
[0] = ps_global
->last_error
[0] = '\0';
9053 if(!((env
= pine_mail_fetchstructure(ps_global
->mail_stream
, raw
, &body
))
9054 && (mc
= mail_elt(ps_global
->mail_stream
, raw
)))){
9057 snprintf(buf
, sizeof(buf
), "Error getting message %ld: %s", peMessageNumber(uid
),
9058 ps_global
->last_error
[0] ? ps_global
->last_error
: "Indeterminate");
9060 dprint((1, "ERROR fetching %s of msg %ld: %s",
9061 env
? "elt" : "env", mn_get_cur(sp_msgmap(ps_global
->mail_stream
)),
9062 ps_global
->last_error
[0] ? ps_global
->last_error
: "Indeterminate"));
9064 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
9068 flags
= FM_DISPLAY
| FM_NEW_MESS
| FM_NOEDITORIAL
| FM_NOHTMLREL
| FM_HTMLRELATED
;
9070 init_handles(&peED
.handles
);
9072 (void) format_message(raw
, env
, body
, &peED
.handles
, flags
, peInterpWritec
);
9076 so_give(&peED
.store
);
9077 free_handles(&peED
.handles
);
9083 * peMessagePartFromCID - return part number assoc'd with given uid and CID
9086 peMessagePartFromCID(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9088 char *cid
, sect_buf
[256];
9093 raw
= peSequenceNumber(peED
.uid
= uid
);
9094 ps_global
->c_client_error
[0] = ps_global
->last_error
[0] = '\0';
9096 if(objv
[0] && (cid
= Tcl_GetStringFromObj(objv
[0], NULL
)) && *cid
!= '\0'){
9097 if((env
= pine_mail_fetchstructure(ps_global
->mail_stream
, raw
, &body
)) != NULL
){
9099 if(peLocateBodyByCID(cid
, sect_buf
, body
)){
9100 Tcl_SetResult(interp
, sect_buf
, TCL_VOLATILE
);
9104 Tcl_SetResult(interp
, ps_global
->last_error
[0] ? ps_global
->last_error
: "Error getting CID", TCL_VOLATILE
);
9114 peLocateBodyByCID(char *cid
, char *section
, BODY
*body
)
9116 if(body
->type
== TYPEMULTIPART
){
9117 char subsection
[256], *subp
;
9119 PART
*part
= body
->nested
.part
;
9121 if(!(part
= body
->nested
.part
))
9125 if(section
&& *section
){
9127 n
< sizeof(subsection
)-20 && (*subp
= section
[n
]); n
++, subp
++)
9135 sprintf(subp
, "%d", n
++);
9136 if(peLocateBodyByCID(cid
, subsection
, &part
->body
)){
9137 strcpy(section
, subsection
);
9141 while((part
= part
->next
) != NULL
);
9146 return((body
&& body
->id
) ? !strcmp(cid
, body
->id
) : 0);
9151 * peGetFlag - Return 1 or 0 based on requested flags current state
9153 * Params: argv[0] == flagname
9156 peGetFlag(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9160 Tcl_SetResult(interp
,
9161 int2string(((flagname
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
)
9162 ? peIsFlagged(ps_global
->mail_stream
, uid
, flagname
)
9170 peIsFlagged(MAILSTREAM
*stream
, imapuid_t uid
, char *flagname
)
9173 long raw
= peSequenceNumber(uid
);
9175 if(!((mc
= mail_elt(stream
, raw
)) && mc
->valid
)){
9176 mail_fetch_flags(stream
, ulong2string(uid
), FT_UID
);
9177 mc
= mail_elt(stream
, raw
);
9180 if(!strucmp(flagname
, "deleted"))
9181 return(mc
->deleted
);
9183 if(!strucmp(flagname
, "new"))
9186 if(!strucmp(flagname
, "important"))
9187 return(mc
->flagged
);
9189 if(!strucmp(flagname
, "answered"))
9190 return(mc
->answered
);
9192 if(!strucmp(flagname
, "recent"))
9200 * peSetFlag - Set requested flags value to 1 or 0
9202 * Params: abjv[0] == flagname
9203 * objv[1] == newvalue
9206 peSetFlag(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9208 char *flagname
, *flagstr
= NULL
;
9211 if((flagname
= Tcl_GetStringFromObj(objv
[0], NULL
))
9212 && Tcl_GetIntFromObj(interp
, objv
[1], &value
) != TCL_ERROR
){
9213 if(!strucmp(flagname
, "deleted")){
9214 flagstr
= "\\DELETED";
9216 else if(!strucmp(flagname
, "new")){
9220 else if(!strucmp(flagname
, "important")){
9221 flagstr
= "\\FLAGGED";
9223 else if(!strucmp(flagname
, "answered")){
9224 flagstr
= "\\ANSWERED";
9226 else if(!strucmp(flagname
, "recent")){
9227 flagstr
= "\\RECENT";
9231 ps_global
->c_client_error
[0] = '\0';
9232 mail_flag(ps_global
->mail_stream
,
9234 flagstr
, (value
? ST_SET
: 0L) | ST_UID
);
9235 if(ps_global
->c_client_error
[0] != '\0'){
9236 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "peSetFlag: %.40s",
9237 ps_global
->c_client_error
);
9238 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
9244 Tcl_SetResult(interp
, value
? "1" : "0", TCL_STATIC
);
9250 * peMsgSelect - Return 1 or 0 based on whether given UID is selected
9252 * Params: argv[0] == selected
9255 peMsgSelect(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9259 if(objc
== 1 && objv
[0]){
9260 if(Tcl_GetIntFromObj(interp
, objv
[0], &value
) != TCL_ERROR
){
9262 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
),
9263 peMessageNumber(uid
), MN_SLCT
, 1);
9264 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
),
9265 peMessageNumber(uid
), MN_HIDE
, 0);
9267 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
),
9268 peMessageNumber(uid
), MN_SLCT
, 0);
9269 /* if zoomed, lite hidden bit */
9270 if(any_lflagged(sp_msgmap(ps_global
->mail_stream
), MN_HIDE
))
9271 set_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
),
9272 peMessageNumber(uid
), MN_HIDE
, 1);
9277 Tcl_SetResult(interp
, "peMsgSelect: can't get value", TCL_STATIC
);
9282 Tcl_SetResult(interp
,
9283 (get_lflag(ps_global
->mail_stream
, NULL
,
9284 peSequenceNumber(uid
),
9293 * peAppendIndexParts - append list of digested index pieces to given object
9299 peAppendIndexParts(Tcl_Interp
*interp
, imapuid_t uid
, Tcl_Obj
*aObj
, int *fetched
)
9301 Tcl_Obj
*objField
, *objElement
, *objp
;
9307 if((h
= build_header_work(ps_global
, ps_global
->mail_stream
,
9308 sp_msgmap(ps_global
->mail_stream
), peMessageNumber(uid
),
9309 gPeITop
, gPeICount
, fetched
)) != NULL
){
9310 for(f
= h
->ifield
; f
; f
= f
->next
){
9312 if((objField
= Tcl_NewListObj(0, NULL
)) == NULL
)
9315 for(ie
= f
->ielem
; ie
; ie
= ie
->next
){
9317 if((objElement
= Tcl_NewListObj(0, NULL
)) == NULL
)
9322 #if INTERNAL_INDEX_TRUNCATE
9325 ep
= (char *) fs_get((ie
->datalen
+ 1) * sizeof(char));
9326 sprintf(ep
, "%.*s", ie
->wid
, ie
->data
);
9328 /* and other stuff to pack trunc'd element into a new object */
9331 objp
= Tcl_NewStringObj(ie
->data
, ie
->datalen
);
9334 objp
= Tcl_NewStringObj("", -1);
9336 if(Tcl_ListObjAppendElement(interp
, objElement
, objp
) != TCL_OK
)
9343 if((objp
= Tcl_NewListObj(0, NULL
)) == NULL
)
9346 hex_colorstr(hexcolor
, ie
->color
->fg
);
9347 objColor
= Tcl_NewStringObj(hexcolor
, -1);
9348 if(Tcl_ListObjAppendElement(interp
, objp
, objColor
) != TCL_OK
)
9351 hex_colorstr(hexcolor
, ie
->color
->bg
);
9352 objColor
= Tcl_NewStringObj(hexcolor
, -1);
9353 if(Tcl_ListObjAppendElement(interp
, objp
, objColor
) != TCL_OK
)
9357 objp
= Tcl_NewStringObj("", -1);
9359 if(Tcl_ListObjAppendElement(interp
, objElement
, objp
) != TCL_OK
)
9363 * IF we ever want to map the thread characters into nice
9364 * graphical symbols or take advantage of features like clicking
9365 * on a thread element to collapse and such, we need to have
9366 * element tagging. That's what the object creation and append
9367 * are placeholders for
9371 objp
= Tcl_NewStringObj("threadinfo", -1);
9377 objp
= Tcl_NewStringObj(int2string(ie
->type
), -1);
9381 if(objp
&& Tcl_ListObjAppendElement(interp
, objElement
, objp
) != TCL_OK
)
9384 if(Tcl_ListObjAppendElement(interp
, objField
, objElement
) != TCL_OK
)
9388 if(Tcl_ListObjAppendElement(interp
, aObj
, objField
) != TCL_OK
){
9399 * peAppendIndexColor - append index line's foreground/background color
9405 peAppendIndexColor(Tcl_Interp
*interp
, imapuid_t uid
, Tcl_Obj
*aObj
, int *fetched
)
9407 char hexfg
[32], hexbg
[32];
9410 if((h
= build_header_work(ps_global
, ps_global
->mail_stream
,
9411 sp_msgmap(ps_global
->mail_stream
), peMessageNumber(uid
),
9412 gPeITop
, gPeICount
, fetched
))
9413 && h
->color_lookup_done
9416 hex_colorstr(hexfg
, h
->linecolor
->fg
);
9417 hex_colorstr(hexbg
, h
->linecolor
->bg
);
9419 return(peAppListF(interp
, aObj
, "%s%s", hexfg
, hexbg
));
9422 return(peAppListF(interp
, aObj
, "%s", ""));
9427 * peMessageStatusBits - return list flags indicating pine status bits
9431 * Returns: list of lists where:
9432 * * the first element is the list of
9433 * field elements data
9434 * * the second element is a two element
9435 * list containing the lines foreground
9436 * and background colors
9439 peMessageStatusBits(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9441 Tcl_SetResult(interp
,
9442 peMsgStatBitString(ps_global
, ps_global
->mail_stream
,
9443 sp_msgmap(ps_global
->mail_stream
), peMessageNumber(uid
),
9444 gPeITop
, gPeICount
, NULL
),
9451 peMsgStatBitString(struct pine
*state
,
9459 static char buf
[36];
9465 raw
= mn_m2raw(msgmap
, msgno
);
9466 if((h
= build_header_work(state
, stream
, msgmap
,
9467 msgno
, top_msgno
, msgcount
, fetched
))
9468 && (mc
= mail_elt(stream
, raw
))){
9469 /* return a string representing a bit field where:
9483 buf
[i
++] = (mc
->seen
) ? '0' : '1';
9484 buf
[i
++] = (mc
->deleted
) ? '1' : '0';
9485 buf
[i
++] = (mc
->answered
) ? '1' : '0';
9486 buf
[i
++] = (mc
->flagged
) ? '1' : '0';
9487 buf
[i
++] = (h
->to_us
) ? '1' : '0';
9488 buf
[i
++] = (h
->cc_us
) ? '1' : '0';
9489 buf
[i
++] = (mc
->recent
) ? '1' : '0';
9490 buf
[i
++] = (user_flag_is_set(stream
, raw
, FORWARDED_FLAG
)) ? '1' : '0';
9497 return("100000000");
9502 peMsgStatNameList(Tcl_Interp
*interp
,
9516 objList
= Tcl_NewListObj(0, NULL
);
9517 raw
= mn_m2raw(msgmap
, msgno
);
9518 if((h
= build_header_work(state
, stream
, msgmap
,
9519 msgno
, top_msgno
, msgcount
, fetched
))
9520 && (mc
= mail_elt(stream
, raw
))){
9522 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("new", -1));
9525 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("deleted", -1));
9528 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("answered", -1));
9531 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("flagged", -1));
9534 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("to_us", -1));
9537 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("cc_us", -1));
9540 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("recent", -1));
9542 if(user_flag_is_set(stream
, raw
, FORWARDED_FLAG
))
9543 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("forwarded", -1));
9545 if(get_lflag(ps_global
->mail_stream
, sp_msgmap(ps_global
->mail_stream
), msgno
, MN_SLCT
))
9546 Tcl_ListObjAppendElement(interp
, objList
, Tcl_NewStringObj("selected", -1));
9554 * peReplyHeaders - return subject used in reply to given message
9558 * Returns: list of header value pairs where headers are:
9559 * In-Reply-To:, Subject:, Cc:
9563 peReplyHeaders(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9566 int flags
= RSF_FORCE_REPLY_TO
| RSF_FORCE_REPLY_ALL
, err
= FALSE
;
9567 char *errmsg
= NULL
, *fcc
= NULL
, *sect
= NULL
;
9568 ENVELOPE
*env
, *outgoing
;
9570 ADDRESS
*saved_from
, *saved_to
, *saved_cc
, *saved_resent
;
9572 saved_from
= (ADDRESS
*) NULL
;
9573 saved_to
= (ADDRESS
*) NULL
;
9574 saved_cc
= (ADDRESS
*) NULL
;
9575 saved_resent
= (ADDRESS
*) NULL
;
9577 raw
= peSequenceNumber(uid
);
9579 /* if we're given a valid section number that
9580 * corresponds to a valid msg/rfc822 body part
9581 * then set up headers in attached message.
9583 if(objc
== 1 && objv
[0]
9584 && (sect
= Tcl_GetStringFromObj(objv
[0], NULL
)) && *sect
!= '\0'
9585 && (body
= mail_body(ps_global
->mail_stream
, raw
, (unsigned char *) sect
))
9586 && body
->type
== TYPEMESSAGE
9587 && !strucmp(body
->subtype
, "rfc822")){
9588 env
= body
->nested
.msg
->env
;
9592 env
= mail_fetchstructure(ps_global
->mail_stream
, raw
, NULL
);
9596 if(!reply_harvest(ps_global
, raw
, sect
, env
,
9597 &saved_from
, &saved_to
, &saved_cc
,
9598 &saved_resent
, &flags
)){
9600 Tcl_SetResult(interp
, "", TCL_STATIC
);
9604 outgoing
= mail_newenvelope();
9606 reply_seed(ps_global
, outgoing
, env
,
9607 saved_from
, saved_to
, saved_cc
, saved_resent
,
9608 &fcc
, flags
, &errmsg
);
9611 q_status_message1(SM_ORDER
, 3, 3, "%.200s", errmsg
);
9614 fs_give((void **)&errmsg
);
9617 env
= pine_mail_fetchstructure(ps_global
->mail_stream
, raw
, NULL
);
9619 outgoing
->subject
= reply_subject(env
->subject
, NULL
, 0);
9620 outgoing
->in_reply_to
= reply_in_reply_to(env
);
9622 err
= !(peAppListF(interp
, Tcl_GetObjResult(interp
),
9623 "%s%a", "to", outgoing
->to
) == TCL_OK
9624 && peAppListF(interp
, Tcl_GetObjResult(interp
),
9625 "%s%a", "cc", outgoing
->cc
) == TCL_OK
9626 && peAppListF(interp
, Tcl_GetObjResult(interp
),
9627 "%s%s", "in-reply-to", outgoing
->in_reply_to
) == TCL_OK
9628 && peAppListF(interp
, Tcl_GetObjResult(interp
),
9630 rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
9631 SIZEOF_20KBUF
, outgoing
->subject
)) == TCL_OK
9632 && (fcc
? peFccAppend(interp
, Tcl_GetObjResult(interp
), fcc
, -1) : TRUE
));
9635 /* Fill in x-reply-uid data and append it */
9636 if(!err
&& ps_global
->mail_stream
->uid_validity
){
9637 char *prefix
= reply_quote_str(env
);
9639 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "(%lu %s)(1 %lu %lu)%s",
9640 strlen(prefix
), prefix
,
9641 ps_global
->mail_stream
->uid_validity
, uid
,
9642 ps_global
->mail_stream
->mailbox
);
9644 fs_give((void **) &prefix
);
9646 err
= peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s",
9647 "x-reply-uid", tmp_20k_buf
) != TCL_OK
;
9650 mail_free_envelope(&outgoing
);
9656 Tcl_SetResult(interp
, "", TCL_VOLATILE
);
9664 * peReplyText - return subject used in reply to given message
9672 peReplyText(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9675 char *prefix
, *sect
= NULL
;
9678 BODY
*body
= NULL
, *orig_body
;
9680 REDRAFT_POS_S
*redraft_pos
= NULL
;
9681 Tcl_Obj
*objBody
= NULL
, *objAttach
= NULL
;
9683 msgno
= peSequenceNumber(uid
);
9685 if((msgtext
= (void *) so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
9686 Tcl_SetResult(interp
, "Unable to create storage for reply text", TCL_VOLATILE
);
9690 /*--- Grab current envelope ---*/
9691 /* if we're given a valid section number that
9692 * corresponds to a valid msg/rfc822 body part
9693 * then set up to reply the attached message's
9696 if(objc
== 2 && objv
[1]
9697 && (sect
= Tcl_GetStringFromObj(objv
[1], NULL
)) && *sect
!= '\0'
9698 && (body
= mail_body(ps_global
->mail_stream
, msgno
, (unsigned char *) sect
))
9699 && body
->type
== TYPEMESSAGE
9700 && !strucmp(body
->subtype
, "rfc822")){
9701 env
= body
->nested
.msg
->env
;
9702 orig_body
= body
->nested
.msg
->body
;
9706 env
= mail_fetchstructure(ps_global
->mail_stream
, msgno
, &orig_body
);
9707 if(!(env
&& orig_body
)){
9708 Tcl_SetResult(interp
, "Unable to fetch message parts", TCL_VOLATILE
);
9713 if((prefix
= Tcl_GetStringFromObj(objv
[0], NULL
)) != NULL
)
9714 prefix
= cpystr(prefix
);
9716 prefix
= reply_quote_str(env
);
9719 * BUG? Should there be some way to signal to reply_bddy
9720 * that we'd like it to produced format=flowed body text?
9721 * right now it's hardwired to in pine/reply.c
9724 if((body
= reply_body(ps_global
->mail_stream
, env
, orig_body
,
9725 msgno
, sect
, msgtext
, prefix
,
9726 TRUE
, NULL
, TRUE
, &redraft_pos
)) != NULL
){
9728 objBody
= Tcl_NewListObj(0, NULL
);
9730 peSoStrToList(interp
, objBody
, msgtext
);
9732 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objBody
);
9734 /* sniff for attachments */
9735 objAttach
= peMsgAttachCollector(interp
, body
);
9737 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
9740 pine_free_body(&body
);
9743 Tcl_SetResult(interp
, "Can't create body text", TCL_VOLATILE
);
9747 fs_give((void **) &prefix
);
9754 peSoStrToList(Tcl_Interp
*interp
, Tcl_Obj
*obj
, STORE_S
*so
)
9759 for(ep
= (char *) so_text(so
); *ep
; ep
++){
9762 while(*ep
&& *ep
!= '\n')
9765 objp
= Tcl_NewStringObj(sp
, ep
- sp
);
9767 if(Tcl_ListObjAppendElement(interp
, obj
, objp
) != TCL_OK
)
9776 * peForwardHeaders - return subject used in forward of given message
9784 peForwardHeaders(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9789 char *tmp
, *sect
= NULL
;
9793 raw
= peSequenceNumber(uid
);
9795 /* if we're given a valid section number that
9796 * corresponds to a valid msg/rfc822 body part
9797 * then set up headers in attached message.
9799 if(objc
== 1 && objv
[0]
9800 && (sect
= Tcl_GetStringFromObj(objv
[0], NULL
)) && *sect
!= '\0'
9801 && (body
= mail_body(ps_global
->mail_stream
, raw
, (unsigned char *) sect
))
9802 && body
->type
== TYPEMESSAGE
9803 && !strucmp(body
->subtype
, "rfc822")){
9804 env
= body
->nested
.msg
->env
;
9808 env
= mail_fetchstructure(ps_global
->mail_stream
, raw
, NULL
);
9812 tmp
= forward_subject(env
, FS_NONE
);
9813 result
= peAppListF(interp
, Tcl_GetObjResult(interp
),
9814 "%s%s", "subject", tmp
);
9815 fs_give((void **) &tmp
);
9817 /* Fill in x-reply-uid data and append it */
9818 if(result
== TCL_OK
&& ps_global
->mail_stream
->uid_validity
){
9819 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "()(1 %lu %lu)%s",
9820 ps_global
->mail_stream
->uid_validity
, uid
,
9821 ps_global
->mail_stream
->mailbox
);
9822 result
= peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s",
9823 "x-reply-uid", tmp_20k_buf
) != TCL_OK
;
9829 Tcl_SetResult(interp
, ps_global
->last_error
, TCL_VOLATILE
);
9836 * peForwardText - return body of message used in
9837 * forward of given message
9845 peForwardText(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9848 char *bodtext
, *p
, *sect
= NULL
;
9851 BODY
*body
, *orig_body
;
9853 Tcl_Obj
*objBody
= NULL
, *objAttach
= NULL
;
9855 msgno
= peSequenceNumber(uid
);
9857 if(objc
== 1 && objv
[0])
9858 sect
= Tcl_GetStringFromObj(objv
[0], NULL
);
9860 if((msgtext
= (void *) so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
9861 Tcl_SetResult(interp
, "Unable to create storage for forward text", TCL_VOLATILE
);
9866 if(F_ON(F_FORWARD_AS_ATTACHMENT
, ps_global
)){
9868 long totalsize
= 0L;
9870 /*---- New Body to start with ----*/
9871 body
= mail_newbody();
9872 body
->type
= TYPEMULTIPART
;
9874 /*---- The TEXT part/body ----*/
9875 body
->nested
.part
= mail_newbody_part();
9876 body
->nested
.part
->body
.type
= TYPETEXT
;
9877 body
->nested
.part
->body
.contents
.text
.data
= (unsigned char *) msgtext
;
9879 pp
= &(body
->nested
.part
->next
);
9881 /*---- The Message body subparts ----*/
9882 env
= pine_mail_fetchstructure(ps_global
->mail_stream
, msgno
, NULL
);
9884 if(forward_mime_msg(ps_global
->mail_stream
, msgno
,
9885 (sect
&& *sect
!= '\0') ? sect
: NULL
, env
, pp
, msgtext
)){
9886 totalsize
= (*pp
)->body
.size
.bytes
;
9887 pp
= &((*pp
)->next
);
9891 /*--- Grab current envelope ---*/
9892 /* if we're given a valid section number that
9893 * corresponds to a valid msg/rfc822 body part
9894 * then set up to forward the attached message's
9898 if(sect
&& *sect
!= '\0'
9899 && (body
= mail_body(ps_global
->mail_stream
, msgno
, (unsigned char *) sect
))
9900 && body
->type
== TYPEMESSAGE
9901 && !strucmp(body
->subtype
, "rfc822")){
9902 env
= body
->nested
.msg
->env
;
9903 orig_body
= body
->nested
.msg
->body
;
9907 env
= mail_fetchstructure(ps_global
->mail_stream
, msgno
, &orig_body
);
9908 if(!(env
&& orig_body
)){
9909 Tcl_SetResult(interp
, "Unable to fetch message parts", TCL_VOLATILE
);
9914 body
= forward_body(ps_global
->mail_stream
, env
, orig_body
,
9915 msgno
, sect
, msgtext
, FWD_NONE
);
9919 bodtext
= (char *) so_text(msgtext
);
9921 objBody
= Tcl_NewListObj(0, NULL
);
9923 for(p
= bodtext
; *p
; p
++){
9927 while(*p
&& *p
!= '\n')
9930 objp
= Tcl_NewStringObj(bodtext
, p
- bodtext
);
9932 Tcl_ListObjAppendElement(interp
, objBody
, objp
);
9935 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objBody
);
9937 /* sniff for attachments */
9938 objAttach
= peMsgAttachCollector(interp
, body
);
9939 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
9941 pine_free_body(&body
);
9944 Tcl_SetResult(interp
, "Can't create body text", TCL_VOLATILE
);
9956 * Params: argv[0] == attachment part number
9957 * argv[1] == directory to hold tmp file
9959 * Returns: list containing:
9961 * 0) response: OK or ERROR
9963 * 1) attachment's mime type
9964 * 2) attachment's mime sub-type
9965 * 3) attachment's size in bytes (decoded)
9966 * 4) attachment's given file name (if any)
9967 * 5) tmp file holding raw attachment data
9970 peDetach(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
9972 char *part
, *err
, *tfd
, *tfn
= NULL
, *filename
;
9977 Tcl_Obj
*rvobj
, *tObj
, *stObj
, *fnObj
;
9979 if((part
= Tcl_GetStringFromObj(objv
[0], NULL
))
9980 && (raw
= peSequenceNumber(uid
))
9981 && (body
= mail_body(ps_global
->mail_stream
, raw
, (unsigned char *) part
))){
9983 peGetMimeTyping(body
, &tObj
, &stObj
, &fnObj
, NULL
);
9986 if(!(tfd
= Tcl_GetStringFromObj(objv
[1], NULL
)) || *tfd
== '\0'){
9987 tfn
= temp_nam(tfd
= NULL
, "pd");
9989 else if(is_writable_dir(tfd
) == 0){
9990 tfn
= temp_nam(tfd
, "pd");
9995 filename
= Tcl_GetStringFromObj(fnObj
, NULL
);
9996 dprint((5, "PEDetach(name: %s, tmpfile: %s)",
9997 filename
? filename
: "<null>", tfn
));
9999 if((store
= so_get(FileStar
, tfn
, WRITE_ACCESS
|OWNER_ONLY
)) != NULL
){
10000 gf_set_so_writec(&pc
, store
);
10001 err
= detach(ps_global
->mail_stream
, raw
, part
, 0L, NULL
, pc
, NULL
, 0);
10002 gf_clear_so_writec(store
);
10006 err
= "Can't allocate internal storage";
10009 err
= "Can't get message data";
10015 dprint((1, "PEDetach FAIL: %d: %s", errno
, err
));
10016 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "Detach (%d): %s", errno
, err
);
10017 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
10021 /* package up response */
10022 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10023 Tcl_NewListObj(1, &tObj
));
10025 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10026 Tcl_NewListObj(1, &stObj
));
10028 rvobj
= Tcl_NewLongObj(name_file_size(tfn
));
10029 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10030 Tcl_NewListObj(1, &rvobj
));
10031 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10032 Tcl_NewListObj(1, &fnObj
));
10033 rvobj
= Tcl_NewStringObj(tfn
, -1);
10034 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10035 Tcl_NewListObj(1, &rvobj
));
10044 * Params: argv[0] == attachment part number
10046 * Returns: list containing:
10048 * 0) response: OK or ERROR
10050 * 1) attachment's mime type
10051 * 2) attachment's mime sub-type
10052 * 3) attachment's size in bytes (decoded)
10053 * 4) attachment's given file name (if any)
10054 * 5) tmp file holding raw attachment data
10057 peAttachInfo(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10063 Tcl_Obj
*tObj
, *stObj
, *fnObj
;
10065 if((part
= Tcl_GetStringFromObj(objv
[0], NULL
))
10066 && (raw
= peSequenceNumber(uid
))
10067 && (body
= mail_body(ps_global
->mail_stream
, raw
, (unsigned char *) part
))){
10069 peGetMimeTyping(body
, &tObj
, &stObj
, &fnObj
, NULL
);
10072 Tcl_SetResult(interp
, "Can't get message data", TCL_STATIC
);
10076 /* package up response */
10079 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), fnObj
);
10082 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), tObj
);
10085 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), stObj
);
10088 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10089 Tcl_NewStringObj((body
->encoding
< ENCMAX
)
10090 ? body_encodings
[body
->encoding
]
10094 if((plist
= rfc2231_newparmlist(body
->parameter
)) != NULL
){
10095 Tcl_Obj
*lObj
= Tcl_NewListObj(0, NULL
);
10098 while(rfc2231_list_params(plist
)){
10099 pObj
[0] = Tcl_NewStringObj(plist
->attrib
, -1);
10100 pObj
[1] = Tcl_NewStringObj(plist
->value
, -1);
10101 Tcl_ListObjAppendElement(interp
, lObj
,
10102 Tcl_NewListObj(2, pObj
));
10105 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), lObj
);
10106 rfc2231_free_parmlist(&plist
);
10109 /* size guesstimate */
10110 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10111 Tcl_NewStringObj(comatose((body
->encoding
== ENCBASE64
)
10112 ? ((body
->size
.bytes
* 3)/4)
10113 : body
->size
.bytes
), -1));
10120 * peSaveDefault - Default saved file name for the given message
10121 * specified collection/folder
10125 * Returns: name of saved message folder or empty string
10129 peSaveDefault(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10132 CONTEXT_S
*cntxt
, *cp
;
10138 if(!(env
= pine_mail_fetchstructure(ps_global
->mail_stream
,
10139 rawno
= peSequenceNumber(uid
),
10141 Tcl_SetResult(interp
, ps_global
->last_error
, TCL_VOLATILE
);
10148 if(!(folder
= save_get_default(ps_global
, env
, rawno
, NULL
, &cntxt
))){
10149 Tcl_SetResult(interp
, "Message expunged!", TCL_VOLATILE
);
10150 return(TCL_ERROR
); /* message expunged! */
10153 for(colid
= 0, cp
= ps_global
->context_list
; cp
&& cp
!= cntxt
; colid
++, cp
= cp
->next
)
10159 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10160 Tcl_NewIntObj(colid
));
10161 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10162 Tcl_NewStringObj(folder
, -1));
10168 * peSaveWork - Save message with given UID in current folder to
10169 * specified collection/folder
10171 * Params: argv[0] == destination context number
10172 * argv[1] == testination foldername
10177 peSaveWork(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
, long sflags
)
10179 int flgs
= 0, i
, colid
;
10180 char *folder
, *err
= NULL
;
10183 if(Tcl_GetIntFromObj(interp
, objv
[0], &colid
) != TCL_ERROR
){
10184 if((folder
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
10185 mn_set_cur(sp_msgmap(ps_global
->mail_stream
), peMessageNumber(uid
));
10186 for(i
= 0, cp
= ps_global
->context_list
; cp
; i
++, cp
= cp
->next
)
10191 if(!READONLY_FOLDER(ps_global
->mail_stream
)
10192 && (sflags
& PSW_COPY
) != PSW_COPY
10193 && ((sflags
& PSW_MOVE
) == PSW_MOVE
|| F_OFF(F_SAVE_WONT_DELETE
, ps_global
)))
10196 if(colid
== 0 && !strucmp(folder
, "inbox"))
10197 flgs
|= SV_INBOXWOCNTXT
;
10199 if(sflags
& (PSW_COPY
| PSW_MOVE
))
10200 flgs
|= SV_FIX_DELS
;
10202 i
= save(ps_global
, ps_global
->mail_stream
,
10203 cp
, folder
, sp_msgmap(ps_global
->mail_stream
), flgs
);
10205 if(i
== mn_total_cur(sp_msgmap(ps_global
->mail_stream
))){
10206 if(mn_total_cur(sp_msgmap(ps_global
->mail_stream
)) <= 1L){
10207 if(ps_global
->context_list
->next
10208 && context_isambig(folder
)){
10209 char *tag
= (cp
->nickname
&& strlen(cp
->nickname
)) ? cp
->nickname
: (cp
->label
&& strlen(cp
->label
)) ? cp
->label
: "Folders";
10210 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
10211 "Message %s %s to \"%.15s%s\" in <%.15s%s>",
10212 long2string(mn_get_cur(sp_msgmap(ps_global
->mail_stream
))),
10213 (sflags
& PSW_MOVE
) ? "moved" : "copied",
10215 (strlen(folder
) > 15) ? "..." : "",
10217 (strlen(tag
) > 15) ? "..." : "");
10220 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
10221 "Message %s %s to folder \"%.27s%s\"",
10222 long2string(mn_get_cur(sp_msgmap(ps_global
->mail_stream
))),
10223 (sflags
& PSW_MOVE
) ? "moved" : "copied",
10225 (strlen(folder
) > 27) ? "..." : "");
10228 /* with mn_set_cur above, this *should not* happen */
10229 Tcl_SetResult(interp
, "TOO MANY MESSAGES COPIED", TCL_VOLATILE
);
10233 if(sflags
== PSW_NONE
&& (flgs
& SV_DELETE
)){
10234 strncat(tmp_20k_buf
, " and deleted", SIZEOF_20KBUF
-strlen(tmp_20k_buf
)-1);
10235 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
10238 q_status_message(SM_ORDER
, 0, 3, tmp_20k_buf
);
10242 err
= ps_global
->last_error
;
10245 err
= "open: Unrecognized collection ID";
10248 err
= "open: Can't read folder";
10251 err
= "open: Can't get collection ID";
10253 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
10258 * peSave - Save message with given UID in current folder to
10259 * specified collection/folder
10261 * Params: argv[0] == destination context number
10262 * argv[1] == testination foldername
10264 * NOTE: just a wrapper around peSaveWork
10267 peSave(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10269 return(peSaveWork(interp
, uid
, objc
, objv
, PSW_NONE
));
10274 * peCopy - Copy message with given UID in current folder to
10275 * specified collection/folder
10277 * Params: argv[0] == destination context number
10278 * argv[1] == testination foldername
10280 * NOTE: just a wrapper around peSaveWork that makes sure
10281 * delete-on-save is NOT set
10284 peCopy(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10286 return(peSaveWork(interp
, uid
, objc
, objv
, PSW_COPY
));
10291 * peMove - Move message with given UID in current folder to
10292 * specified collection/folder
10294 * Params: argv[0] == destination context number
10295 * argv[1] == testination foldername
10297 * NOTE: just a wrapper around peSaveWork that makes sure
10298 * delete-on-save IS set so it can be expunged
10301 peMove(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10303 return(peSaveWork(interp
, uid
, objc
, objv
, PSW_MOVE
));
10308 * peGotoDefault - Default Goto command file name for the given message
10309 * specified collection/folder
10313 * Returns: name of Goto command default folder or empty string
10317 peGotoDefault(Tcl_Interp
*interp
, imapuid_t uid
, Tcl_Obj
**objv
)
10319 char *folder
= NULL
;
10320 CONTEXT_S
*cntxt
, *cp
;
10323 cntxt
= broach_get_folder(ps_global
->context_current
, &inbox
, &folder
);
10325 for(colid
= 0, cp
= ps_global
->context_list
; cp
!= cntxt
; colid
++, cp
= cp
->next
)
10331 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10332 Tcl_NewIntObj(colid
));
10333 (void) Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
10334 Tcl_NewStringObj(folder
? folder
: "", -1));
10342 * Params: argv[0] == attachment part number
10344 * Returns: list containing:
10348 peReplyQuote(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
10354 if((env
= pine_mail_fetchstructure(ps_global
->mail_stream
, peSequenceNumber(uid
), NULL
)) != NULL
){
10355 quote
= reply_quote_str(env
);
10356 Tcl_SetResult(interp
, quote
, TCL_VOLATILE
);
10357 fs_give((void **) "e
);
10360 Tcl_SetResult(interp
, ps_global
->last_error
, TCL_VOLATILE
);
10365 Tcl_SetResult(interp
, "> ", TCL_VOLATILE
);
10372 peGetMimeTyping(BODY
*body
, Tcl_Obj
**tObjp
, Tcl_Obj
**stObjp
, Tcl_Obj
**fnObjp
, Tcl_Obj
**extObjp
)
10374 char *ptype
= NULL
, *psubtype
= NULL
, *pfile
= NULL
;
10376 /*------- Figure out suggested file name ----*/
10378 if((pfile
= get_filename_parameter(NULL
, 0, body
, NULL
)) != NULL
){
10380 * if part is generic, see if we can get anything
10381 * more from the suggested filename's extension...
10383 if(body
->type
== TYPEAPPLICATION
10385 || !strucmp(body
->subtype
, "octet-stream"))){
10386 BODY
*fakebody
= mail_newbody();
10388 if(set_mime_type_by_extension(fakebody
, pfile
)){
10389 ptype
= body_type_names(fakebody
->type
);
10390 psubtype
= cpystr(fakebody
->subtype
);
10393 mail_free_body(&fakebody
);
10398 ptype
= body_type_names(body
->type
);
10399 psubtype
= cpystr(body
->subtype
10401 : (body
->type
== TYPETEXT
)
10403 : (body
->type
== TYPEAPPLICATION
)
10409 ptype
= body_type_names(TYPETEXT
);
10410 psubtype
= cpystr("plain");
10414 *extObjp
= Tcl_NewStringObj("", 0);
10416 if(ptype
&& psubtype
&& pfile
){
10419 char extbuf
[32]; /* mailcap.c limits to three */
10421 l
= strlen(ptype
) + strlen(psubtype
) + 1;
10422 mtype
= (char *) fs_get((l
+1) * sizeof(char));
10424 snprintf(mtype
, l
+1, "%s/%s", ptype
, psubtype
);
10426 if(!set_mime_extension_by_type(extbuf
, mtype
)){
10429 for(dotp
= NULL
, p
= pfile
; *p
; p
++)
10434 Tcl_SetStringObj(*extObjp
, dotp
, -1);
10437 Tcl_SetStringObj(*extObjp
, extbuf
, -1);
10439 fs_give((void **) &mtype
);
10444 *tObjp
= Tcl_NewStringObj(ptype
, -1);
10448 *stObjp
= Tcl_NewStringObj(psubtype
, -1);
10450 fs_give((void **) &psubtype
);
10453 *stObjp
= Tcl_NewStringObj("", 0);
10457 *fnObjp
= Tcl_NewStringObj(pfile
, -1);
10459 fs_give((void **) &pfile
);
10462 *fnObjp
= Tcl_NewStringObj("", 0);
10467 * peAppListF - generate a list of elements based on fmt string,
10468 * then append it to the given list object
10472 peAppListF(Tcl_Interp
*interp
, Tcl_Obj
*lobjp
, char *fmt
, ...)
10475 char *p
, *sval
, nbuf
[128];
10479 unsigned long luval
;
10483 Tcl_Obj
*lObj
= NULL
, *sObj
;
10485 if((lObj
= Tcl_NewListObj(0, NULL
)) != NULL
){
10486 va_start(args
, fmt
);
10487 for(p
= fmt
; *p
&& !err
; p
++){
10492 case 'i' : /* int value */
10493 ival
= va_arg(args
, int);
10494 if((sObj
= Tcl_NewIntObj(ival
)) == NULL
)
10499 case 'u' : /* unsigned int value */
10500 uval
= va_arg(args
, unsigned int);
10501 snprintf(nbuf
, sizeof(nbuf
), "%u", uval
);
10502 if((sObj
= Tcl_NewStringObj(nbuf
, -1)) == NULL
)
10507 case 'l' : /* long value */
10510 luval
= va_arg(args
, unsigned long);
10511 snprintf(nbuf
, sizeof(nbuf
), "%lu", luval
);
10512 if((sObj
= Tcl_NewStringObj(nbuf
, -1)) == NULL
)
10516 lval
= va_arg(args
, long);
10517 if((sObj
= Tcl_NewLongObj(lval
)) == NULL
)
10523 case 's' : /* string value */
10524 sval
= va_arg(args
, char *);
10525 sObj
= Tcl_NewStringObj(sval
? sval
: "", -1);
10531 case 'a': /* ADDRESS list */
10532 aval
= va_arg(args
, ADDRESS
*);
10538 len
= est_size(aval
);
10539 tmp
= (char *) fs_get(len
* sizeof(char));
10541 rbuf
.f
= dummy_soutr
;
10545 rbuf
.end
= tmp
+len
-1;
10546 rfc822_output_address_list(&rbuf
, aval
, 0L, NULL
);
10548 p
= (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
, SIZEOF_20KBUF
, tmp
);
10549 sObj
= Tcl_NewStringObj(p
, strlen(p
));
10550 fs_give((void **) &tmp
);
10553 sObj
= Tcl_NewStringObj("", -1);
10557 case 'p': /* PATTERN_S * */
10558 pval
= va_arg(args
, PATTERN_S
*);
10559 sval
= pattern_to_string(pval
);
10560 sObj
= Tcl_NewStringObj(sval
? sval
: "", -1);
10563 case 'v': /* INTVL_S * */
10564 vval
= va_arg(args
, INTVL_S
*);
10566 for(; vval
!= NULL
; vval
= vval
->next
){
10567 peAppListF(interp
, sObj
, "%l%l", vval
->imin
, vval
->imax
);
10571 sObj
= Tcl_NewListObj(0, NULL
);
10575 case 'o': /* Tcl_Obj * */
10576 sObj
= va_arg(args
, Tcl_Obj
*);
10581 Tcl_ListObjAppendElement(interp
, lObj
, sObj
);
10587 return(lObj
? Tcl_ListObjAppendElement(interp
, lobjp
, lObj
) : TCL_ERROR
);
10591 * pePatAppendID - append list of pattern identity variables to given object
10594 pePatAppendID(Tcl_Interp
*interp
, Tcl_Obj
*patObj
, PAT_S
*pat
)
10598 resObj
= Tcl_NewListObj(0, NULL
);
10599 peAppListF(interp
, resObj
, "%s%s", "nickname", pat
->patgrp
->nick
);
10600 peAppListF(interp
, resObj
, "%s%s", "comment", pat
->patgrp
->comment
);
10601 Tcl_ListObjAppendElement(interp
, patObj
, resObj
);
10606 * pePatAppendPattern - append list of pattern variables to given object
10609 pePatAppendPattern(Tcl_Interp
*interp
, Tcl_Obj
*patObj
, PAT_S
*pat
)
10614 resObj
= Tcl_NewListObj(0, NULL
);
10615 peAppListF(interp
, resObj
, "%s%p", "to", pat
->patgrp
->to
);
10616 peAppListF(interp
, resObj
, "%s%p", "from", pat
->patgrp
->from
);
10617 peAppListF(interp
, resObj
, "%s%p", "sender", pat
->patgrp
->sender
);
10618 peAppListF(interp
, resObj
, "%s%p", "cc", pat
->patgrp
->cc
);
10619 peAppListF(interp
, resObj
, "%s%p", "recip", pat
->patgrp
->recip
);
10620 peAppListF(interp
, resObj
, "%s%p", "partic", pat
->patgrp
->partic
);
10621 peAppListF(interp
, resObj
, "%s%p", "news", pat
->patgrp
->news
);
10622 peAppListF(interp
, resObj
, "%s%p", "subj", pat
->patgrp
->subj
);
10623 peAppListF(interp
, resObj
, "%s%p", "alltext", pat
->patgrp
->alltext
);
10624 peAppListF(interp
, resObj
, "%s%p", "bodytext", pat
->patgrp
->bodytext
);
10625 peAppListF(interp
, resObj
, "%s%p", "keyword", pat
->patgrp
->keyword
);
10626 peAppListF(interp
, resObj
, "%s%p", "charset", pat
->patgrp
->charsets
);
10628 peAppListF(interp
, resObj
, "%s%v", "score", pat
->patgrp
->score
);
10629 peAppListF(interp
, resObj
, "%s%v", "age", pat
->patgrp
->age
);
10630 peAppListF(interp
, resObj
, "%s%v", "size", pat
->patgrp
->size
);
10632 if((ah
= pat
->patgrp
->arbhdr
) != NULL
){
10633 Tcl_Obj
*hlObj
, *hObj
;
10635 hlObj
= Tcl_NewListObj(0, NULL
);
10636 Tcl_ListObjAppendElement(interp
, hlObj
, Tcl_NewStringObj("headers", -1));
10638 for(; ah
; ah
= ah
->next
){
10639 hObj
= Tcl_NewListObj(0, NULL
);
10640 peAppListF(interp
, hObj
, "%s%p", ah
->field
? ah
->field
: "", ah
->p
);
10641 Tcl_ListObjAppendElement(interp
, hlObj
, hObj
);
10644 Tcl_ListObjAppendElement(interp
, resObj
, hlObj
);
10647 switch(pat
->patgrp
->fldr_type
){
10649 peAppListF(interp
, resObj
, "%s%s", "ftype", "any");
10652 peAppListF(interp
, resObj
, "%s%s", "ftype", "news");
10655 peAppListF(interp
, resObj
, "%s%s", "ftype", "email");
10657 case FLDR_SPECIFIC
:
10658 peAppListF(interp
, resObj
, "%s%s", "ftype", "specific");
10662 peAppListF(interp
, resObj
, "%s%p", "folder", pat
->patgrp
->folder
);
10663 peAppListF(interp
, resObj
, "%s%s", "stat_new", pePatStatStr(pat
->patgrp
->stat_new
));
10664 peAppListF(interp
, resObj
, "%s%s", "stat_rec", pePatStatStr(pat
->patgrp
->stat_rec
));
10665 peAppListF(interp
, resObj
, "%s%s", "stat_del", pePatStatStr(pat
->patgrp
->stat_del
));
10666 peAppListF(interp
, resObj
, "%s%s", "stat_imp", pePatStatStr(pat
->patgrp
->stat_imp
));
10667 peAppListF(interp
, resObj
, "%s%s", "stat_ans", pePatStatStr(pat
->patgrp
->stat_ans
));
10668 peAppListF(interp
, resObj
, "%s%s", "stat_8bitsubj", pePatStatStr(pat
->patgrp
->stat_8bitsubj
));
10669 peAppListF(interp
, resObj
, "%s%s", "stat_bom", pePatStatStr(pat
->patgrp
->stat_bom
));
10670 peAppListF(interp
, resObj
, "%s%s", "stat_boy", pePatStatStr(pat
->patgrp
->stat_boy
));
10672 Tcl_ListObjAppendElement(interp
, patObj
, resObj
);
10677 pePatStatStr(int value
)
10680 case PAT_STAT_EITHER
:
10696 * peCreateUserContext - create new ps_global and set it up
10699 peCreateUserContext(Tcl_Interp
*interp
, char *user
, char *config
, char *defconf
)
10702 peDestroyUserContext(&ps_global
);
10704 set_collation(1, 1);
10706 ps_global
= new_pine_struct();
10708 /*----------------------------------------------------------------------
10709 Place any necessary constraints on pith processing
10710 ----------------------------------------------------------------------*/
10712 /* got thru close procedure without expunging */
10713 ps_global
->noexpunge_on_close
= 1;
10715 /* do NOT let user set path to local executable */
10716 ps_global
->vars
[V_SENDMAIL_PATH
].is_user
= 0;
10719 /*----------------------------------------------------------------------
10720 Proceed with reading acquiring user settings
10721 ----------------------------------------------------------------------*/
10722 if(ps_global
->pinerc
)
10723 fs_give((void **) &ps_global
->pinerc
);
10726 free_pinerc_s(&ps_global
->prc
);
10728 if(!IS_REMOTE(config
)){
10729 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "Non-Remote config: %s", config
);
10730 return(tmp_20k_buf
);
10733 ps_global
->prc
= new_pinerc_s(config
);
10736 if(ps_global
->pconf
)
10737 free_pinerc_s(&ps_global
->pconf
);
10739 ps_global
->pconf
= new_pinerc_s(defconf
);
10743 * Fake up some user information
10745 ps_global
->ui
.login
= cpystr(user
);
10749 * Prep for IMAP debugging
10751 setup_imap_debug();
10754 /* CHECK FOR AND PASS BACK ANY INIT ERRORS */
10755 return(peLoadConfig(ps_global
));
10761 peDestroyUserContext(struct pine
**pps
)
10764 completely_done_with_adrbks();
10766 free_pinerc_strings(pps
);
10768 imap_flush_passwd_cache(TRUE
);
10770 clear_index_cache(sp_inbox_stream(), 0);
10771 free_newsgrp_cache();
10773 close_patterns(0L);
10775 free_contexts(&ps_global
->context_list
);
10779 free_strlist(&peCertHosts
);
10781 free_pine_struct(pps
);
10786 peLoadConfig(struct pine
*pine_state
)
10789 char *s
, *db
= NULL
;
10790 extern void init_signals(void); /* in signal.c */
10793 return("No global state present");
10796 /*turned off because we don't care about local user*/
10797 /* need home directory early */
10798 get_user_info(&pine_state
->ui
);
10800 pine_state
->home_dir
= cpystr((getenv("HOME") != NULL
)
10802 : pine_state
->ui
.homedir
);
10805 init_pinerc(pine_state
, &db
);
10807 fs_give((void **) &db
);
10810 * Initial allocation of array of stream pool pointers.
10811 * We do this before init_vars so that we can re-use streams used for
10812 * remote config files. These sizes may get changed later.
10814 ps_global
->s_pool
.max_remstream
= 2;
10816 ps_global
->c_client_error
[0] = '\0';
10818 pePrepareForAuthException();
10820 peInitVars(pine_state
);
10822 if((s
= peAuthException()) != NULL
)
10824 else if(ps_global
->c_client_error
[0])
10825 return(ps_global
->c_client_error
);
10827 mail_parameters(NULL
, SET_SENDCOMMAND
, (void *) pine_imap_cmd_happened
);
10828 mail_parameters(NULL
, SET_FREESTREAMSPAREP
, (void *) sp_free_callback
);
10829 mail_parameters(NULL
, SET_FREEELTSPAREP
, (void *) free_pine_elt
);
10832 * Install callback to handle certificate validation failures,
10833 * allowing the user to continue if they wish.
10835 mail_parameters(NULL
, SET_SSLCERTIFICATEQUERY
, (void *) alpine_sslcertquery
);
10836 mail_parameters(NULL
, SET_SSLFAILURE
, (void *) alpine_sslfailure
);
10839 * Set up a c-client read timeout and timeout handler. In general,
10840 * it shouldn't happen, but a server crash or dead link can cause
10841 * pine to appear wedged if we don't set this up...
10843 mail_parameters(NULL
, SET_OPENTIMEOUT
,
10844 (void *)((pine_state
->VAR_TCPOPENTIMEO
10845 && (rv
= atoi(pine_state
->VAR_TCPOPENTIMEO
)) > 4)
10846 ? (long) rv
: 30L));
10847 mail_parameters(NULL
, SET_TIMEOUT
, (void *) alpine_tcptimeout
);
10849 if(pine_state
->VAR_RSHOPENTIMEO
10850 && ((rv
= atoi(pine_state
->VAR_RSHOPENTIMEO
)) == 0 || rv
> 4))
10851 mail_parameters(NULL
, SET_RSHTIMEOUT
, (void *) (long) rv
);
10853 if(pine_state
->VAR_SSHOPENTIMEO
10854 && ((rv
= atoi(pine_state
->VAR_SSHOPENTIMEO
)) == 0 || rv
> 4))
10855 mail_parameters(NULL
, SET_SSHTIMEOUT
, (void *) (long) rv
);
10858 * Tell c-client not to be so aggressive about uid mappings
10860 mail_parameters(NULL
, SET_UIDLOOKAHEAD
, (void *) 20);
10863 * Setup referral handling
10865 mail_parameters(NULL
, SET_IMAPREFERRAL
, (void *) imap_referral
);
10866 mail_parameters(NULL
, SET_MAILPROXYCOPY
, (void *) imap_proxycopy
);
10869 * Install extra headers to fetch along with all the other stuff
10870 * mail_fetch_structure and mail_fetch_overview requests.
10874 if(get_extra_hdrs())
10875 (void) mail_parameters(NULL
, SET_IMAPEXTRAHEADERS
, (void *) get_extra_hdrs());
10877 (void) init_username(pine_state
);
10879 (void) init_hostname(ps_global
);
10882 (void) init_ldap_pname(ps_global
);
10883 #endif /* ENABLE_LDAP */
10885 if(ps_global
->prc
&& ps_global
->prc
->type
== Loc
&&
10886 can_access(ps_global
->pinerc
, ACCESS_EXISTS
) == 0 &&
10887 can_access(ps_global
->pinerc
, EDIT_ACCESS
) != 0)
10888 ps_global
->readonly_pinerc
= 1;
10891 * c-client needs USR2 and we might as well
10892 * do something sensible with HUP and TERM
10896 strncpy(pine_state
->inbox_name
, INBOX_NAME
, sizeof(pine_state
->inbox_name
));
10897 pine_state
->inbox_name
[sizeof(pine_state
->inbox_name
)-1] = '\0';
10899 init_folders(pine_state
); /* digest folder spec's */
10902 * Various options we want to make sure are set OUR way
10904 F_TURN_ON(F_QUELL_IMAP_ENV_CB
, pine_state
);
10905 F_TURN_ON(F_SLCTBL_ITEM_NOBOLD
, pine_state
);
10906 F_TURN_OFF(F_USE_SYSTEM_TRANS
, pine_state
);
10909 * Fake screen dimensions for index formatting and
10910 * message display wrap...
10912 ps_global
->ttyo
= (struct ttyo
*) fs_get(sizeof(struct ttyo
));
10913 ps_global
->ttyo
->screen_rows
= FAKE_SCREEN_LENGTH
;
10914 ps_global
->ttyo
->screen_cols
= FAKE_SCREEN_WIDTH
;
10915 if(ps_global
->VAR_WP_COLUMNS
){
10916 int w
= atoi(ps_global
->VAR_WP_COLUMNS
);
10917 if(w
>= 20 && w
<= 128)
10918 ps_global
->ttyo
->screen_cols
= w
;
10921 ps_global
->ttyo
->header_rows
= 0;
10922 ps_global
->ttyo
->footer_rows
= 0;
10926 if(ps_global
->VAR_NORM_FORE_COLOR
)
10927 pico_nfcolor(ps_global
->VAR_NORM_FORE_COLOR
);
10929 if(ps_global
->VAR_NORM_BACK_COLOR
)
10930 pico_nbcolor(ps_global
->VAR_NORM_BACK_COLOR
);
10932 if(ps_global
->VAR_REV_FORE_COLOR
)
10933 pico_rfcolor(ps_global
->VAR_REV_FORE_COLOR
);
10935 if(ps_global
->VAR_REV_BACK_COLOR
)
10936 pico_rbcolor(ps_global
->VAR_REV_BACK_COLOR
);
10938 pico_set_normal_color();
10945 peCreateStream(Tcl_Interp
*interp
, CONTEXT_S
*context
, char *mailbox
, int do_inbox
)
10947 unsigned long flgs
= 0L;
10950 ps_global
->c_client_error
[0] = ps_global
->last_error
[0] = '\0';
10952 pePrepareForAuthException();
10955 flgs
|= DB_INBOXWOCNTXT
;
10957 if(do_broach_folder(mailbox
, context
, NULL
, flgs
) && ps_global
->mail_stream
){
10958 dprint((SYSDBG_INFO
, "Mailbox open: %s",
10959 ps_global
->mail_stream
->mailbox
? ps_global
->mail_stream
->mailbox
: "<UNKNOWN>"));
10963 Tcl_SetResult(interp
,
10964 (s
= peAuthException())
10966 : (*ps_global
->last_error
)
10967 ? ps_global
->last_error
10975 peDestroyStream(struct pine
*ps
)
10980 cur_is_inbox
= (sp_inbox_stream() == ps_global
->mail_stream
);
10982 /* clean up open streams */
10983 if(ps
->mail_stream
){
10984 expunge_and_close(ps
->mail_stream
, NULL
, EC_NONE
);
10985 ps_global
->mail_stream
= NULL
;
10986 ps_global
->cur_folder
[0] = '\0';
10990 mn_give(&ps
->msgmap
);
10992 if(sp_inbox_stream() && !cur_is_inbox
){
10993 ps
->mail_stream
= sp_inbox_stream();
10994 ps
->msgmap
= sp_msgmap(ps
->mail_stream
);
10995 sp_set_expunge_count(ps_global
->mail_stream
, 0L);
10996 expunge_and_close(sp_inbox_stream(), NULL
, EC_NONE
);
10997 mn_give(&ps
->msgmap
);
11004 * pePrepareForAuthException - set globals to get feedback from bowels of c-client
11007 pePrepareForAuthException(void)
11009 peNoPassword
= peCredentialError
= peCertFailure
= peCertQuery
= 0;
11013 * pePrepareForAuthException - check globals getting feedback from bowels of c-client
11018 static char buf
[CRED_REQ_SIZE
];
11021 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", CERT_QUERY_STRING
, peCredentialRequestor
);
11026 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", CERT_FAILURE_STRING
, peCredentialRequestor
);
11031 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", AUTH_EMPTY_STRING
, peCredentialRequestor
);
11035 if(peCredentialError
){
11036 snprintf(buf
, CRED_REQ_SIZE
, "%s %s", AUTH_FAILURE_STRING
, peCredentialRequestor
);
11045 peInitVars(struct pine
*ps
)
11047 init_vars(ps
, NULL
);
11050 * fix display/keyboard-character-set to utf-8
11055 if(ps
->display_charmap
)
11056 fs_give((void **) &ps
->display_charmap
);
11058 ps
->display_charmap
= cpystr(WP_INTERNAL_CHARSET
);
11060 if(ps
->keyboard_charmap
)
11061 fs_give((void **) &ps
->keyboard_charmap
);
11063 ps
->keyboard_charmap
= cpystr(WP_INTERNAL_CHARSET
);
11065 (void) setup_for_input_output(FALSE
, &ps
->display_charmap
, &ps
->keyboard_charmap
, &ps
->input_cs
, NULL
);;
11071 peMessageBounce(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
11073 char *errstr
= NULL
, *to
, *subj
= NULL
, errbuf
[WP_MAX_POST_ERROR
+ 1];
11075 ENVELOPE
*env
, *outgoing
= NULL
;
11081 rawno
= peSequenceNumber(uid
);
11083 if(objc
> 0 && objv
[0] && (to
= Tcl_GetStringFromObj(objv
[0], NULL
))){
11084 if(objc
== 2 && objv
[1]){
11085 subj
= Tcl_GetStringFromObj(objv
[1], NULL
);
11087 else if((env
= mail_fetchstructure(ps_global
->mail_stream
, rawno
, NULL
)) != NULL
){
11088 subj
= env
->subject
;
11091 Tcl_SetResult(interp
, ps_global
->last_error
, TCL_VOLATILE
);
11095 if((errstr
= bounce_msg_body(ps_global
->mail_stream
, rawno
, NULL
,
11096 &to
, subj
, &outgoing
, &body
, NULL
))){
11097 Tcl_SetResult(interp
, errstr
, TCL_VOLATILE
);
11101 metaenv
= pine_new_env(outgoing
, NULL
, NULL
, custom
= peCustomHdrs());
11103 if(!outgoing
->from
)
11104 outgoing
->from
= generate_from();
11106 rfc822_date(tmp_20k_buf
);
11107 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
11109 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
11110 if(!outgoing
->message_id
)
11111 outgoing
->message_id
= generate_message_id();
11115 if(peDoPost(metaenv
, body
, NULL
, NULL
, errbuf
) != TCL_OK
)
11118 pine_free_body(&body
);
11120 pine_free_env(&metaenv
);
11123 free_customs(custom
);
11125 mail_free_envelope(&outgoing
);
11126 pine_free_body(&body
);
11131 Tcl_SetResult(interp
, (errstr
) ? errstr
: "OK", TCL_VOLATILE
);
11132 return(errstr
? TCL_ERROR
: TCL_OK
);
11137 peMessageSpamNotice(interp
, uid
, objc
, objv
)
11138 Tcl_Interp
*interp
;
11143 char *to
, *subj
= NULL
, errbuf
[WP_MAX_POST_ERROR
+ 1], *rs
= NULL
;
11147 rawno
= peSequenceNumber(uid
);
11149 if(objv
[0] && (to
= Tcl_GetStringFromObj(objv
[0], NULL
)) && strlen(to
)){
11152 subj
= Tcl_GetStringFromObj(objv
[1], NULL
);
11154 rs
= peSendSpamReport(rawno
, to
, subj
, errbuf
);
11158 Tcl_SetResult(interp
, (rs
) ? rs
: "OK", TCL_VOLATILE
);
11159 return(rs
? TCL_ERROR
: TCL_OK
);
11164 peSendSpamReport(long rawno
, char *to
, char *subj
, char *errbuf
)
11166 char *errstr
= NULL
, *tmp_a_string
;
11167 ENVELOPE
*env
, *outgoing
;
11171 static char *fakedomain
= "@";
11175 if((env
= mail_fetchstructure(ps_global
->mail_stream
, rawno
, NULL
)) == NULL
){
11176 return(ps_global
->last_error
);
11179 /* empty subject gets "spam" subject */
11180 if(!(subj
&& *subj
))
11181 subj
= env
->subject
;
11183 /*---- New Body to start with ----*/
11184 body
= mail_newbody();
11185 body
->type
= TYPEMULTIPART
;
11187 /*---- The TEXT part/body ----*/
11188 body
->nested
.part
= mail_newbody_part();
11189 body
->nested
.part
->body
.type
= TYPETEXT
;
11191 if((msgtext
= (void *)so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
11192 pine_free_body(&body
);
11193 return("peSendSpamReport: Can't allocate text");
11196 sprintf(tmp_20k_buf
,
11197 "The attached message is being reported to <%s> as Spam\n",
11199 so_puts((STORE_S
*) msgtext
, tmp_20k_buf
);
11200 body
->nested
.part
->body
.contents
.text
.data
= msgtext
;
11203 /*---- Attach the raw message ----*/
11204 if(forward_mime_msg(ps_global
->mail_stream
, rawno
, NULL
, env
,
11205 &(body
->nested
.part
->next
), msgtext
)){
11206 outgoing
= mail_newenvelope();
11207 metaenv
= pine_new_env(outgoing
, NULL
, NULL
, custom
= peCustomHdrs());
11210 pine_free_body(&body
);
11211 return("peSendSpamReport: Can't generate forwarded message");
11214 /* rfc822_parse_adrlist feels free to destroy input so copy */
11215 tmp_a_string
= cpystr(to
);
11216 rfc822_parse_adrlist(&outgoing
->to
, tmp_a_string
,
11217 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
))
11218 ? fakedomain
: ps_global
->maildomain
);
11219 fs_give((void **) &tmp_a_string
);
11221 outgoing
->from
= generate_from();
11222 outgoing
->subject
= cpystr(subj
);
11223 outgoing
->return_path
= rfc822_cpy_adr(outgoing
->from
);
11224 outgoing
->message_id
= generate_message_id();
11226 rfc822_date(tmp_20k_buf
);
11227 outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
11229 /* NO FCC for Spam Reporting */
11231 if(peDoPost(metaenv
, body
, NULL
, NULL
, errbuf
) != TCL_OK
)
11234 pine_free_body(&body
);
11236 pine_free_env(&metaenv
);
11239 free_customs(custom
);
11241 mail_free_envelope(&outgoing
);
11242 pine_free_body(&body
);
11248 /* * * * * * * * * * * * * Start of Composer Routines * * * * * * * * * * * */
11252 * PEComposeCmd - export various bits of alpine state
11255 PEComposeCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
11257 char *err
= "PECompose: Unknown request";
11259 dprint((2, "PEComposeCmd"));
11262 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
11264 else if(!ps_global
){
11265 Tcl_SetResult(interp
, "peCompose: no config present", TCL_STATIC
);
11269 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
11272 if(!strcmp(s1
, "post")){
11273 long flags
= PMC_NONE
;
11274 if(F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
))
11275 flags
|= PMC_FORCE_QUAL
;
11277 return(peMsgCollector(interp
, objc
- 2, (Tcl_Obj
**) &objv
[2], peDoPost
, flags
));
11279 else if(objc
== 2){
11280 if(!strcmp(s1
, "userhdrs")){
11283 PINEFIELD
*custom
, *cp
;
11285 static char *standard
[] = {"To", "Cc", "Bcc", "Fcc", "Attach", "Subject", NULL
};
11287 custom
= peCustomHdrs();
11289 for(i
= 0; standard
[i
]; i
++){
11291 for(cp
= custom
; cp
; cp
= cp
->next
)
11292 if(!strucmp(cp
->name
, standard
[i
]))
11295 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", standard
[i
], p
);
11298 for(cp
= custom
; cp
!= NULL
; cp
= cp
->next
){
11299 if(!strucmp(cp
->name
, "from")){
11300 if(F_OFF(F_ALLOW_CHANGING_FROM
, ps_global
))
11303 if(cp
->textbuf
&& strlen(cp
->textbuf
)){
11309 tmp_20k_buf
[0] = '\0';
11310 rbuf
.f
= dummy_soutr
;
11312 rbuf
.beg
= tmp_20k_buf
;
11313 rbuf
.cur
= tmp_20k_buf
;
11314 rbuf
.end
= tmp_20k_buf
+SIZEOF_20KBUF
-1;
11315 rfc822_output_address_list(&rbuf
, from
= generate_from(), 0L, NULL
);
11317 mail_free_address(&from
);
11323 for(i
= 0; standard
[i
]; i
++)
11324 if(!strucmp(standard
[i
], cp
->name
))
11331 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", cp
->name
, p
);
11335 free_customs(custom
);
11339 else if(!strcmp(s1
, "syshdrs")){
11341 static char *extras
[] = {"In-Reply-To", "X-Reply-UID", NULL
};
11343 for(i
= 0; extras
[i
]; i
++)
11344 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s%s", extras
[i
], NULL
);
11348 else if(!strcmp(s1
, "composehdrs")){
11351 if((p
= ps_global
->VAR_COMP_HDRS
) && *p
){
11353 Tcl_ListObjAppendElement(interp
,
11354 Tcl_GetObjResult(interp
),
11355 Tcl_NewStringObj(*p
, (q
= strchr(*p
, ':'))
11359 Tcl_SetResult(interp
, "", TCL_STATIC
);
11363 else if(!strcmp(s1
, "fccdefault")){
11365 CONTEXT_S
*c
= default_save_context(ps_global
->context_list
), *c2
;
11367 for(c2
= ps_global
->context_list
; c
&& c
!= c2
; c2
= c2
->next
)
11370 Tcl_ListObjAppendElement(interp
,
11371 Tcl_GetObjResult(interp
),
11372 Tcl_NewIntObj(ci
));
11373 Tcl_ListObjAppendElement(interp
,
11374 Tcl_GetObjResult(interp
),
11375 Tcl_NewStringObj(ps_global
->VAR_DEFAULT_FCC
11376 ? ps_global
->VAR_DEFAULT_FCC
11380 else if(!strcmp(s1
, "noattach")){
11381 peFreeAttach(&peCompAttach
);
11382 Tcl_SetResult(interp
, "OK", TCL_VOLATILE
);
11385 else if(!strcmp(s1
, "from")){
11387 ADDRESS
*from
= generate_from();
11388 tmp_20k_buf
[0] = '\0';
11389 rbuf
.f
= dummy_soutr
;
11391 rbuf
.beg
= tmp_20k_buf
;
11392 rbuf
.cur
= tmp_20k_buf
;
11393 rbuf
.end
= tmp_20k_buf
+SIZEOF_20KBUF
-1;
11394 rfc822_output_address_list(&rbuf
, from
, 0L, NULL
);
11396 mail_free_address(&from
);
11397 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
11400 else if(!strcmp(s1
, "attachments")){
11402 Tcl_Obj
*objAttach
;
11404 for(p
= peCompAttach
; p
; p
= p
->next
)
11406 objAttach
= Tcl_NewListObj(0, NULL
);
11409 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(p
->id
,-1));
11412 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(p
->l
.f
.remote
,-1));
11415 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewLongObj(p
->l
.f
.size
));
11418 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s", p
->l
.f
.type
, p
->l
.f
.subtype
);
11419 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(tmp_20k_buf
,-1));
11421 /* append to list */
11422 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
11427 objAttach
= Tcl_NewListObj(0, NULL
);
11430 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(p
->id
,-1));
11433 if((name
= get_filename_parameter(NULL
, 0, p
->l
.b
.body
, NULL
)) != NULL
){
11434 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(name
, -1));
11435 fs_give((void **) &name
);
11438 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj("Unknown", -1));
11441 Tcl_ListObjAppendElement(interp
, objAttach
,
11442 Tcl_NewLongObj((p
->l
.b
.body
->encoding
== ENCBASE64
)
11443 ? ((p
->l
.b
.body
->size
.bytes
* 3)/4)
11444 : p
->l
.b
.body
->size
.bytes
));
11447 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s",
11448 body_type_names(p
->l
.b
.body
->type
),
11449 p
->l
.b
.body
->subtype
? p
->l
.b
.body
->subtype
: "Unknown");
11450 Tcl_ListObjAppendElement(interp
, objAttach
, Tcl_NewStringObj(tmp_20k_buf
, -1));
11452 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
11458 else if(objc
== 3){
11459 if(!strcmp(s1
, "unattach")){
11462 if((id
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
11463 if(peClearAttachID(id
)){
11464 Tcl_SetResult(interp
, "OK", TCL_STATIC
);
11468 err
= "Can't access attachment id";
11471 err
= "Can't read attachment id";
11473 else if(!strcmp(s1
, "attachinfo")){
11477 /* return: remote-filename size "type/subtype" */
11478 if((id
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
11479 if((a
= peGetAttachID(id
)) != NULL
){
11482 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(a
->l
.f
.remote
,-1));
11485 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewLongObj(a
->l
.f
.size
));
11488 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s", a
->l
.f
.type
, a
->l
.f
.subtype
);
11489 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(tmp_20k_buf
,-1));
11492 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
11493 Tcl_NewStringObj((a
->l
.f
.description
) ? a
->l
.f
.description
: "",-1));
11500 if((name
= get_filename_parameter(NULL
, 0, a
->l
.b
.body
, NULL
)) != NULL
){
11501 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(name
, -1));
11502 fs_give((void **) &name
);
11505 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj("Unknown", -1));
11508 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
11509 Tcl_NewLongObj((a
->l
.b
.body
->encoding
== ENCBASE64
)
11510 ? ((a
->l
.b
.body
->size
.bytes
* 3)/4)
11511 : a
->l
.b
.body
->size
.bytes
));
11514 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s",
11515 body_type_names(a
->l
.b
.body
->type
),
11516 a
->l
.b
.body
->subtype
? a
->l
.b
.body
->subtype
: "Unknown");
11518 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(tmp_20k_buf
, -1));
11521 if(a
->l
.b
.body
->description
){
11522 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%.*s", 256, a
->l
.b
.body
->description
);
11524 else if((s
= parameter_val(a
->l
.b
.body
->parameter
, "description")) != NULL
){
11525 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%.*s", 256, s
);
11526 fs_give((void **) &s
);
11529 tmp_20k_buf
[0] = '\0';
11531 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), Tcl_NewStringObj(tmp_20k_buf
, -1));
11536 err
= "Unknown attachment type";
11539 err
= "Can't access attachment id";
11542 err
= "Can't read attachment id";
11545 else if(objc
== 7){
11546 if(!strcmp(s1
, "attach")){
11547 char *file
, *remote
, *type
, *subtype
, *desc
;
11549 if((file
= Tcl_GetStringFromObj(objv
[2], NULL
))
11550 && (type
= Tcl_GetStringFromObj(objv
[3], NULL
))
11551 && (subtype
= Tcl_GetStringFromObj(objv
[4], NULL
))
11552 && (remote
= Tcl_GetStringFromObj(objv
[5], NULL
))){
11555 desc
= Tcl_GetStringFromObj(objv
[6], &dl
);
11558 Tcl_SetResult(interp
, peFileAttachID(file
, type
, subtype
, remote
, desc
, dl
), TCL_VOLATILE
);
11562 err
= "Can't read file description";
11565 err
= "Can't read file name";
11571 Tcl_SetResult(interp
, err
, TCL_STATIC
);
11579 COMPATT_S
*p
= (COMPATT_S
*) fs_get(sizeof(COMPATT_S
));
11580 memset(p
, 0, sizeof(COMPATT_S
));
11586 peFreeAttach(COMPATT_S
**a
)
11589 fs_give((void **) &(*a
)->id
);
11593 fs_give((void **) &(*a
)->l
.f
.type
);
11595 if((*a
)->l
.f
.subtype
)
11596 fs_give((void **) &(*a
)->l
.f
.subtype
);
11598 if((*a
)->l
.f
.remote
)
11599 fs_give((void **) &(*a
)->l
.f
.remote
);
11601 if((*a
)->l
.f
.local
){
11602 (void) unlink((*a
)->l
.f
.local
);
11603 fs_give((void **) &(*a
)->l
.f
.local
);
11606 if((*a
)->l
.f
.description
)
11607 fs_give((void **) &(*a
)->l
.f
.description
);
11609 else if((*a
)->body
){
11610 pine_free_body(&(*a
)->l
.b
.body
);
11613 peFreeAttach(&(*a
)->next
);
11614 fs_give((void **) a
);
11620 peFileAttachID(char *f
, char *t
, char *st
, char *r
, char *d
, int dl
)
11622 COMPATT_S
*ap
= peNewAttach(), *p
;
11626 ap
->l
.f
.local
= cpystr(f
);
11627 ap
->l
.f
.size
= name_file_size(f
);
11629 hval
= line_hash(f
);
11630 while(1) /* collisions? */
11631 if(peGetAttachID(ap
->id
= cpystr(long2string(hval
)))){
11632 fs_give((void **) &ap
->id
);
11638 ap
->l
.f
.remote
= cpystr(r
? r
: "");
11639 ap
->l
.f
.type
= cpystr(t
? t
: "Text");
11640 ap
->l
.f
.subtype
= cpystr(st
? st
: "Plain");
11642 ap
->l
.f
.description
= fs_get(dl
+ 1);
11643 snprintf(ap
->l
.f
.description
, dl
+ 1, "%s", d
);
11645 if((p
= peCompAttach
) != NULL
){
11651 while((p
= p
->next
) != NULL
);
11661 peBodyAttachID(BODY
*b
)
11663 COMPATT_S
*ap
= peNewAttach(), *p
;
11664 unsigned long hval
;
11667 ap
->l
.b
.body
= copy_body(NULL
, b
);
11669 hval
= b
->id
? line_hash(b
->id
) : time(0);
11670 while(1) /* collisions? */
11671 if(peGetAttachID(ap
->id
= cpystr(ulong2string(hval
)))){
11672 fs_give((void **) &ap
->id
);
11678 /* move contents pointer to copy */
11679 peBodyMoveContents(b
, ap
->l
.b
.body
);
11681 if((p
= peCompAttach
) != NULL
){
11687 while((p
= p
->next
) != NULL
);
11697 peBodyMoveContents(BODY
*bs
, BODY
*bd
)
11700 if(bs
->type
== TYPEMULTIPART
&& bd
->type
== TYPEMULTIPART
){
11701 PART
*ps
= bs
->nested
.part
,
11702 *pd
= bd
->nested
.part
;
11703 do /* for each part */
11704 peBodyMoveContents(&ps
->body
, &pd
->body
);
11705 while ((ps
= ps
->next
) && (pd
= pd
->next
)); /* until done */
11707 else if(bs
->contents
.text
.data
){
11708 bd
->contents
.text
.data
= bs
->contents
.text
.data
;
11709 bs
->contents
.text
.data
= NULL
;
11717 peGetAttachID(char *h
)
11721 for(p
= peCompAttach
; p
; p
= p
->next
)
11722 if(!strcmp(p
->id
, h
))
11730 peClearAttachID(char *h
)
11732 COMPATT_S
*pp
, *pt
= NULL
;
11734 for(pp
= peCompAttach
; pp
; pp
= pp
->next
){
11735 if(!strcmp(pp
->id
, h
)){
11737 pt
->next
= pp
->next
;
11739 peCompAttach
= pp
->next
;
11754 * peDoPost - handle preparing header and body text for posting, prepare
11755 * for any Fcc, then call the mailer to send it out
11758 peDoPost(METAENV
*metaenv
, BODY
*body
, char *fcc
, CONTEXT_S
**fcc_cntxtp
, char *errp
)
11760 int rv
= TCL_OK
, recipients
;
11763 if(commence_fcc(fcc
, fcc_cntxtp
, TRUE
)){
11765 ps_global
->c_client_error
[0] = ps_global
->last_error
[0] = '\0';
11766 pePrepareForAuthException();
11768 if((recipients
= (metaenv
->env
->to
|| metaenv
->env
->cc
|| metaenv
->env
->bcc
))
11769 && call_mailer(metaenv
, body
, NULL
, 0, NULL
, NULL
) < 0){
11770 if((s
= peAuthException()) != NULL
){
11773 else if(ps_global
->last_error
[0]){
11774 sprintf(errp
, "Send Error: %.*s", 64, ps_global
->last_error
);
11776 else if(ps_global
->c_client_error
[0]){
11777 sprintf(errp
, "Send Error: %.*s", 64, ps_global
->c_client_error
);
11780 strcpy(errp
, "Sending Failure");
11783 dprint((1, "call_mailer failed!"));
11785 else if(fcc
&& fcc_cntxtp
&& !wrapup_fcc(fcc
, *fcc_cntxtp
, recipients
? NULL
: metaenv
, body
)){
11786 strcpy(errp
, "Fcc Failed!. No message saved.");
11788 dprint((1, "explicit fcc write failed!"));
11792 REPLY_S
*reply
= NULL
;
11794 /* success, now look for x-reply-uid to flip answered flag for? */
11796 for(pf
= metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
11797 if(!strucmp(pf
->name
, "x-reply-uid")){
11799 if((reply
= (REPLY_S
*) build_reply_uid(pf
->textbuf
)) != NULL
){
11801 update_answered_flags(reply
);
11804 fs_give((void **) &reply
->mailbox
);
11807 fs_give((void **) &reply
->prefix
);
11809 if(reply
->data
.uid
.msgs
)
11810 fs_give((void **) &reply
->data
.uid
.msgs
);
11812 fs_give((void **) &reply
);
11821 dprint((1,"can't open fcc, cont"));
11823 strcpy(errp
, "Can't open Fcc");
11833 * pePostponeCmd - export various bits of alpine state
11836 PEPostponeCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
11838 char *err
= "PEPostpone: unknown request";
11842 dprint((2, "PEPostponeCmd"));
11845 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
11847 else if(!ps_global
){
11848 Tcl_SetResult(interp
, "pePostpone: no config present", TCL_STATIC
);
11852 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
11855 if(!strcmp(s1
, "extract")){
11856 if(Tcl_GetLongFromObj(interp
, objv
[2], &uidl
) == TCL_OK
){
11857 Tcl_Obj
*objHdr
= NULL
, *objBod
= NULL
, *objAttach
= NULL
, *objOpts
= NULL
;
11858 MAILSTREAM
*stream
;
11860 ENVELOPE
*env
= NULL
;
11861 PINEFIELD
*custom
= NULL
, *cp
;
11862 REPLY_S
*reply
= NULL
;
11863 ACTION_S
*role
= NULL
;
11867 char *fcc
= NULL
, *lcc
= NULL
;
11868 unsigned flags
= REDRAFT_DEL
| REDRAFT_PPND
;
11871 if(objc
> 3){ /* optional flags */
11873 Tcl_Obj
**objFlags
;
11876 Tcl_ListObjGetElements(interp
, objv
[3], &nFlags
, &objFlags
);
11877 for(i
= 0; i
< nFlags
; i
++){
11878 if((flagstr
= Tcl_GetStringFromObj(objFlags
[i
], NULL
)) == NULL
){
11882 if(!strucmp(flagstr
, "html"))
11883 flags
|= REDRAFT_HTML
;
11886 /* BUG: should probably complain if argc > 4 */
11889 && postponed_stream(&stream
, ps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0)
11891 if((so
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
11892 if((n
= mail_msgno(stream
, uid
)) > 0L){
11893 if(redraft_work(&stream
, n
, &env
, &b
, &fcc
, &lcc
, &reply
,
11894 NULL
, &custom
, &role
, /* should role be NULL? */
11896 char *charset
= NULL
;
11898 /* prepare to package up for caller */
11899 objHdr
= Tcl_NewListObj(0, NULL
);
11901 /* determine body part's charset */
11902 if((charset
= parameter_val(b
->parameter
,"charset")) != NULL
){
11903 objOpts
= Tcl_NewListObj(0, NULL
);
11904 peAppListF(interp
, objOpts
, "%s%s", "charset", charset
);
11905 fs_give((void **) &charset
);
11908 /* body part's MIME subtype */
11909 if(b
->subtype
&& strucmp(b
->subtype
,"plain")){
11911 objOpts
= Tcl_NewListObj(0, NULL
);
11913 peAppListF(interp
, objOpts
, "%s%s", "subtype", b
->subtype
);
11916 peAppListF(interp
, objHdr
, "%s%a", "from",
11917 role
&& role
->from
? role
->from
: env
->from
);
11918 peAppListF(interp
, objHdr
, "%s%a", "to", env
->to
);
11919 peAppListF(interp
, objHdr
, "%s%a", "cc", env
->cc
);
11920 peAppListF(interp
, objHdr
, "%s%a", "bcc", env
->bcc
);
11921 peAppListF(interp
, objHdr
, "%s%s", "in-reply-to", env
->in_reply_to
);
11922 peAppListF(interp
, objHdr
, "%s%s", "subject",
11923 rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
11924 SIZEOF_20KBUF
, env
->subject
));
11927 peFccAppend(interp
, objHdr
, fcc
, -1);
11929 for(cp
= custom
; cp
&& cp
->name
; cp
= cp
->next
)
11932 strncpy(tmp_20k_buf
, cp
->name
, SIZEOF_20KBUF
);
11933 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
11934 peAppListF(interp
, objHdr
, "%s%a",
11935 lcase((unsigned char *) tmp_20k_buf
), *cp
->addr
);
11943 break; /* ignored */
11946 strncpy(tmp_20k_buf
, cp
->name
, SIZEOF_20KBUF
);
11947 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
11948 peAppListF(interp
, objHdr
, "%s%s",
11949 lcase((unsigned char *) tmp_20k_buf
), cp
->textbuf
? cp
->textbuf
: cp
->val
);
11954 /* blat x-Reply-UID: for possible use? */
11956 char uidbuf
[MAILTMPLEN
], *p
;
11959 for(i
= 0L, p
= tmp_20k_buf
; reply
->data
.uid
.msgs
[i
]; i
++){
11961 sstrncpy(&p
, ",", SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
11963 sstrncpy(&p
,ulong2string(reply
->data
.uid
.msgs
[i
]), SIZEOF_20KBUF
-(p
-tmp_20k_buf
));
11966 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
11968 snprintf(uidbuf
, sizeof(uidbuf
), "(%s%s%s)(%ld %lu %s)%s",
11969 reply
->prefix
? int2string(strlen(reply
->prefix
))
11970 : (reply
->forwarded
) ? "" : "0 ",
11971 reply
->prefix
? " " : "",
11972 reply
->prefix
? reply
->prefix
: "",
11973 i
, reply
->data
.uid
.validity
,
11974 tmp_20k_buf
, reply
->mailbox
);
11976 peAppListF(interp
, objHdr
, "%s%s", "x-reply-uid", uidbuf
);
11979 fs_give((void **) &reply
->mailbox
);
11980 fs_give((void **) &reply
->prefix
);
11981 fs_give((void **) &reply
->data
.uid
.msgs
);
11982 fs_give((void **) &reply
);
11985 objBod
= Tcl_NewListObj(0, NULL
);
11986 peSoStrToList(interp
, objBod
, so
);
11988 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objHdr
);
11989 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objBod
);
11991 objAttach
= peMsgAttachCollector(interp
, b
);
11993 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objAttach
);
11996 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),objOpts
);
12001 fs_give((void **) &fcc
);
12004 fs_give((void **) &lcc
);
12006 mail_free_envelope(&env
);
12007 pine_free_body(&b
);
12008 free_action(&role
);
12010 /* if Drafts got whacked, open INBOX */
12011 if(!ps_global
->mail_stream
)
12012 do_broach_folder(ps_global
->inbox_name
,
12013 ps_global
->context_list
,
12014 NULL
, DB_INBOXWOCNTXT
);
12022 err
= "Unknown UID";
12025 err
= "No internal storage";
12027 /* redraft_work cleaned up the "stream" */
12030 err
= "No Postponed stream";
12033 err
= "Malformed extract request";
12035 else if(objc
== 2){
12036 if(!strcmp(s1
, "any")){
12037 MAILSTREAM
*stream
;
12039 if(postponed_stream(&stream
, ps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12040 Tcl_SetResult(interp
, "1", TCL_STATIC
);
12042 if(stream
!= ps_global
->mail_stream
)
12043 pine_mail_close(stream
);
12046 Tcl_SetResult(interp
, "0", TCL_STATIC
);
12050 else if(!strcmp(s1
, "count")){
12051 MAILSTREAM
*stream
;
12053 if(postponed_stream(&stream
, ps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12054 Tcl_SetResult(interp
, long2string(stream
->nmsgs
), TCL_STATIC
);
12056 if(stream
!= ps_global
->mail_stream
)
12057 pine_mail_close(stream
);
12060 Tcl_SetResult(interp
, "-1", TCL_STATIC
);
12064 else if(!strcmp(s1
, "list")){
12065 MAILSTREAM
*stream
;
12067 Tcl_Obj
*objEnv
= NULL
, *objEnvList
;
12070 if(postponed_stream(&stream
, ps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12071 if(!stream
->nmsgs
){
12072 (void) redraft_cleanup(&stream
, FALSE
, REDRAFT_PPND
);
12073 Tcl_SetResult(interp
, "", TCL_STATIC
);
12077 objEnvList
= Tcl_NewListObj(0, NULL
);
12079 for(n
= 1; n
<= stream
->nmsgs
; n
++){
12080 if((env
= pine_mail_fetchstructure(stream
, n
, NULL
)) != NULL
){
12081 objEnv
= Tcl_NewListObj(0, NULL
);
12083 peAppListF(interp
, objEnv
, "%s%s", "uid",
12084 ulong2string(mail_uid(stream
, n
)));
12086 peAppListF(interp
, objEnv
, "%s%a", "to", env
->to
);
12088 date_str((char *)env
->date
, iSDate
, 1, tmp_20k_buf
, SIZEOF_20KBUF
, 0);
12090 peAppListF(interp
, objEnv
, "%s%s", "date", tmp_20k_buf
);
12092 peAppListF(interp
, objEnv
, "%s%s", "subj",
12093 rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
12094 SIZEOF_20KBUF
, env
->subject
));
12096 Tcl_ListObjAppendElement(interp
, objEnvList
, objEnv
);
12100 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objEnvList
);
12102 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
12103 Tcl_NewStringObj("utf-8", -1));
12105 if(stream
!= ps_global
->mail_stream
)
12106 pine_mail_close(stream
);
12112 else if(objc
== 3){
12113 if(!strcmp(s1
, "append")){
12116 if((rv
= peMsgCollector(interp
, objc
- 2, (Tcl_Obj
**) &objv
[2], peDoPostpone
, PMC_NONE
)) == TCL_OK
)
12117 Tcl_SetResult(interp
, ulong2string(get_last_append_uid()), TCL_VOLATILE
);
12121 else if(!strcmp(s1
, "draft")){
12124 if((rv
= peMsgCollector(interp
, objc
- 2, (Tcl_Obj
**) &objv
[2], peDoPostpone
, PMC_PRSRV_ATT
)) == TCL_OK
)
12125 Tcl_SetResult(interp
, ulong2string(get_last_append_uid()), TCL_VOLATILE
);
12129 else if(!strcmp(s1
, "delete")){
12130 if(Tcl_GetLongFromObj(interp
, objv
[2], &uidl
) == TCL_OK
){
12131 MAILSTREAM
*stream
;
12135 if(postponed_stream(&stream
, ps_global
->VAR_POSTPONED_FOLDER
, "Postponed", 0) && stream
){
12136 if((rawno
= mail_msgno(stream
, uid
)) > 0L){
12137 mail_flag(stream
, long2string(rawno
), "\\DELETED", ST_SET
);
12138 ps_global
->expunge_in_progress
= 1;
12139 mail_expunge(stream
);
12140 ps_global
->expunge_in_progress
= 0;
12141 if(stream
!= ps_global
->mail_stream
)
12142 pine_mail_actually_close(stream
);
12147 err
= "PEPostpone delete: UID no longer exists";
12150 err
= "PEPostpone delete: No Postponed stream";
12153 err
= "PEPostpone delete: No uid provided";
12159 Tcl_SetResult(interp
, err
, TCL_STATIC
);
12165 * peDoPostpone - handle postponing after message collection
12168 peDoPostpone(METAENV
*metaenv
, BODY
*body
, char *fcc
, CONTEXT_S
**fcc_cntxtp
, char *errp
)
12175 * resolve fcc and store it in fcc custom header field data
12177 if(fcc
&& *fcc
&& fcc_cntxtp
&& *fcc_cntxtp
)
12178 for(pf
= metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
12179 if(!strucmp("fcc", pf
->name
)){
12180 char *name
, *rs
, path_in_context
[MAILTMPLEN
];
12182 if(pf
->textbuf
) /* free old value */
12183 fs_give((void **) &pf
->textbuf
);
12185 /* replace nickname with full name */
12186 if(!(name
= folder_is_nick(fcc
, FOLDERS(*fcc_cntxtp
), FN_NONE
)))
12189 if(context_isambig(name
) && !(((*fcc_cntxtp
)->use
) & CNTXT_SAVEDFLT
)){
12190 context_apply(path_in_context
, *fcc_cntxtp
, name
, sizeof(path_in_context
));
12191 rs
= IS_REMOTE(path_in_context
) ? path_in_context
: NULL
;
12197 pf
->textbuf
= cpystr(rs
);
12198 pf
->text
= &pf
->textbuf
;
12204 au
= mail_parameters(NIL
, GET_APPENDUID
, NIL
);
12205 mail_parameters(NIL
, SET_APPENDUID
, (void *) appenduid_cb
);
12207 rv
= write_postponed(metaenv
, body
);
12209 mail_parameters(NIL
, SET_APPENDUID
, (void *) au
);
12211 return((rv
< 0) ? TCL_ERROR
: TCL_OK
);
12216 * peMsgCollector - Collect message parts and call specified handler
12219 peMsgCollector(Tcl_Interp
*interp
,
12222 int (*postfunc
)(METAENV
*, BODY
*, char *, CONTEXT_S
**, char *),
12225 Tcl_Obj
**objMsg
, **objField
, **objBody
;
12226 int i
, j
, vl
, nMsg
, nField
, nBody
;
12227 char *field
, *value
, *err
= NULL
;
12230 STRLIST_S
*tp
, *lp
;
12231 static char *fakedomain
= "@";
12233 memset(&md
, 0, sizeof(MSG_COL_S
));
12234 md
.postop_fcc_no_attach
= -1;
12235 md
.postfunc
= postfunc
;
12236 md
.qualified_addrs
= ((flags
& PMC_FORCE_QUAL
) == PMC_FORCE_QUAL
);
12239 Tcl_SetResult(interp
, "Malformed message data", TCL_STATIC
);
12242 else if(!ps_global
){
12243 Tcl_SetResult(interp
, "No open folder", TCL_STATIC
);
12247 md
.outgoing
= mail_newenvelope();
12249 md
.metaenv
= pine_new_env(md
.outgoing
, NULL
, NULL
, md
.custom
= peCustomHdrs());
12251 Tcl_ListObjGetElements(interp
, objv
[0], &nMsg
, &objMsg
);
12252 for(i
= 0; i
< nMsg
; i
++){
12253 if(Tcl_ListObjGetElements(interp
, objMsg
[i
], &nField
, &objField
) != TCL_OK
){
12254 err
= ""; /* interp's result object has error message */
12255 return(peMsgCollected(interp
, &md
, err
, flags
));
12258 if(nField
&& (field
= Tcl_GetStringFromObj(objField
[0], NULL
))){
12259 if(!strcmp(field
, "body")){
12261 err
= "Too many bodies";
12262 return(peMsgCollected(interp
, &md
, err
, flags
));
12264 else if((md
.msgtext
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
12265 /* mark storage object as user edited */
12266 (void) so_attr(md
.msgtext
, "edited", "1");
12268 Tcl_ListObjGetElements(interp
, objField
[1], &nBody
, &objBody
);
12269 for(j
= 0; j
< nBody
; j
++){
12270 value
= Tcl_GetStringFromObj(objBody
[j
], &vl
);
12272 so_nputs(md
.msgtext
, value
, vl
);
12273 so_puts(md
.msgtext
, "\n");
12276 err
= "Value read failure";
12277 return(peMsgCollected(interp
, &md
, err
, flags
));
12282 err
= "Can't acquire body storage";
12283 return(peMsgCollected(interp
, &md
, err
, flags
));
12286 else if(!strucmp(field
, "attach")){
12291 && (id
= Tcl_GetStringFromObj(objField
[1], NULL
))
12292 && (a
= peGetAttachID(id
))){
12293 tp
= new_strlist(id
);
12294 if((lp
= md
.attach
) != NULL
){
12300 while((lp
= lp
->next
) != NULL
);
12306 strcpy(err
= tmp_20k_buf
, "Unknown attachment ID");
12307 return(peMsgCollected(interp
, &md
, err
, flags
));
12310 else if(!strucmp(field
, "fcc")){
12314 if(Tcl_ListObjGetElements(interp
, objField
[1], &nFcc
, &objFcc
) == TCL_OK
12316 && Tcl_GetIntFromObj(interp
, objFcc
[0], &md
.fcc_colid
) == TCL_OK
12317 && (value
= Tcl_GetStringFromObj(objFcc
[1], NULL
))){
12319 fs_give((void **) &md
.fcc
);
12321 md
.fcc
= cpystr(value
);
12324 strcpy(err
= tmp_20k_buf
, "Unrecognized Fcc specification");
12325 return(peMsgCollected(interp
, &md
, err
, flags
));
12328 else if(!strucmp(field
, "postoption")){
12333 if(Tcl_ListObjGetElements(interp
, objField
[1], &nPO
, &objPO
) == TCL_OK
12335 && (value
= Tcl_GetStringFromObj(objPO
[0], NULL
))){
12336 if(!strucmp(value
,"fcc-without-attachments")){
12337 if(Tcl_GetIntFromObj(interp
, objPO
[1], &ival
) == TCL_OK
){
12338 md
.postop_fcc_no_attach
= (ival
!= 0);
12341 sprintf(err
= tmp_20k_buf
, "Malformed Post Option: fcc-without-attachments");
12342 return(peMsgCollected(interp
, &md
, err
, flags
));
12345 else if(!strucmp(value
, "charset")){
12346 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12349 for(p
= value
; ; p
++){ /* sanity check */
12351 md
.charset
= cpystr(value
);
12355 if(isspace((unsigned char ) *p
)
12356 || !isprint((unsigned char) *p
))
12359 if(p
- value
> 255)
12364 err
= "Post option read failure";
12365 return(peMsgCollected(interp
, &md
, err
, flags
));
12368 else if(!strucmp(value
, "flowed")){
12369 if(F_OFF(F_QUELL_FLOWED_TEXT
,ps_global
)){
12370 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12371 if(!strucmp(value
, "yes"))
12375 err
= "Post option read failure";
12376 return(peMsgCollected(interp
, &md
, err
, flags
));
12380 else if(!strucmp(value
, "subtype")){
12381 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12382 if(!strucmp(value
, "html"))
12386 err
= "Post option read failure";
12387 return(peMsgCollected(interp
, &md
, err
, flags
));
12390 else if(!strucmp(value
, "priority")){
12391 if((value
= Tcl_GetStringFromObj(objPO
[1], NULL
)) != NULL
){
12392 char *priority
= NULL
;
12394 if(!strucmp(value
, "highest"))
12395 priority
= "Highest";
12396 else if(!strucmp(value
, "high"))
12398 else if(!strucmp(value
, "normal"))
12399 priority
= "Normal";
12400 else if(!strucmp(value
, "low"))
12402 else if(!strucmp(value
, "lowest"))
12403 priority
= "Lowest";
12406 if((pf
= set_priority_header(md
.metaenv
, priority
)) != NULL
)
12407 pf
->text
= &pf
->textbuf
;
12411 err
= "Post option read failure";
12412 return(peMsgCollected(interp
, &md
, err
, flags
));
12416 sprintf(err
= tmp_20k_buf
, "Unknown Post Option: %s", value
);
12417 return(peMsgCollected(interp
, &md
, err
, flags
));
12421 sprintf(err
= tmp_20k_buf
, "Malformed Post Option");
12422 return(peMsgCollected(interp
, &md
, err
, flags
));
12427 sprintf(err
= tmp_20k_buf
, "Malformed header (%s)", field
);
12428 return(peMsgCollected(interp
, &md
, err
, flags
));
12431 if((value
= Tcl_GetStringFromObj(objField
[1], &vl
)) != NULL
){
12432 ADDRESS
**addrp
= NULL
;
12433 char **valp
= NULL
, *valcpy
;
12435 if(!strucmp(field
, "from")){
12436 addrp
= &md
.outgoing
->from
;
12438 else if(!strucmp(field
, "reply-to")){
12439 addrp
= &md
.outgoing
->reply_to
;
12441 else if(!strucmp(field
, "to")){
12442 addrp
= &md
.outgoing
->to
;
12444 else if(!strucmp(field
, "cc")){
12445 addrp
= &md
.outgoing
->cc
;
12447 else if(!strucmp(field
, "bcc")){
12448 addrp
= &md
.outgoing
->bcc
;
12450 else if(!strucmp(field
, "subject")){
12451 valp
= &md
.outgoing
->subject
;
12453 else if(!strucmp(field
, "in-reply-to")){
12454 valp
= &md
.outgoing
->in_reply_to
;
12456 else if(!strucmp(field
, "newsgroups")){
12457 valp
= &md
.outgoing
->newsgroups
;
12459 else if(!strucmp(field
, "followup-to")){
12460 valp
= &md
.outgoing
->followup_to
;
12462 else if(!strucmp(field
, "references")){
12463 valp
= &md
.outgoing
->references
;
12465 else if(!strucmp(field
, "x-reply-uid")){
12466 for(pf
= md
.metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
12467 if(!strucmp(pf
->name
, "x-reply-uid")){
12468 valp
= pf
->text
= &pf
->textbuf
;
12472 else if(!strucmp(field
, "x-auth-received")){
12473 for(pf
= md
.metaenv
->local
; pf
&& pf
->name
; pf
= pf
->next
)
12474 if(!strucmp(pf
->name
, "x-auth-received")){
12475 valp
= pf
->text
= &pf
->textbuf
;
12480 for(pf
= md
.metaenv
->custom
; pf
&& pf
->name
; pf
= pf
->next
)
12481 if(!strucmp(field
, pf
->name
)){
12482 if(pf
->type
== Address
)
12485 valp
= &pf
->textbuf
;
12486 else if(pf
->textbuf
)
12487 fs_give((void **) &pf
->textbuf
);
12493 dprint((2, "\nPOST: unrecognized field - %s\n", field
));
12498 fs_give((void **) valp
);
12500 sprintf(*valp
= fs_get((vl
+ 1) * sizeof(char)), "%.*s", vl
, value
);
12504 sprintf(valcpy
= fs_get((vl
+ 1) * sizeof(char)), "%.*s", vl
, value
);
12506 for(; *addrp
; addrp
= &(*addrp
)->next
)
12509 rfc822_parse_adrlist(addrp
, valcpy
,
12510 (flags
& PMC_FORCE_QUAL
)
12511 ? fakedomain
: ps_global
->maildomain
);
12512 fs_give((void **) &valcpy
);
12516 err
= "Value read failure";
12517 return(peMsgCollected(interp
, &md
, err
, flags
));
12523 return(peMsgCollected(interp
, &md
, err
, flags
));
12528 * peMsgCollected - Dispatch collected message data and cleanup
12531 peMsgCollected(Tcl_Interp
*interp
, MSG_COL_S
*md
, char *err
, long flags
)
12533 int rv
= TCL_OK
, non_ascii
= FALSE
;
12535 BODY
*body
= NULL
, *tbp
= NULL
;
12536 char errbuf
[WP_MAX_POST_ERROR
+ 1], *charset
;
12541 so_give(&md
->msgtext
);
12545 else if(md
->qualified_addrs
&& check_addresses(md
->metaenv
) == CA_BAD
){
12546 sprintf(err
= tmp_20k_buf
, "Address must be fully qualified.");
12550 /* sniff body for possible multipart wrapping to protect encoding */
12551 so_seek(md
->msgtext
, 0L, 0);
12553 while(so_readc(&c
, md
->msgtext
))
12554 if(!c
|| c
& 0x80){
12559 if(!md
->outgoing
->from
)
12560 md
->outgoing
->from
= generate_from();
12562 rfc822_date(tmp_20k_buf
);
12563 md
->outgoing
->date
= (unsigned char *) cpystr(tmp_20k_buf
);
12564 md
->outgoing
->return_path
= rfc822_cpy_adr(md
->outgoing
->from
);
12565 md
->outgoing
->message_id
= generate_message_id();
12567 body
= mail_newbody();
12569 /* wire any attachments to body */
12570 if(md
->attach
|| (non_ascii
&& F_OFF(F_COMPOSE_ALWAYS_DOWNGRADE
, ps_global
))){
12575 /* setup slot for message text */
12576 body
->type
= TYPEMULTIPART
;
12577 body
->nested
.part
= mail_newbody_part();
12578 tbp
= &body
->nested
.part
->body
;
12580 /* link in attachments */
12581 for(lp
= md
->attach
, np
= &body
->nested
.part
->next
; lp
; lp
= lp
->next
, np
= &(*np
)->next
){
12582 if(!(a
= peGetAttachID(lp
->name
))){
12583 err
= "Unknown Attachment ID";
12588 *np
= mail_newbody_part();
12591 (*np
)->body
.id
= generate_message_id();
12592 (*np
)->body
.description
= cpystr(a
->l
.f
.description
);
12594 /* set name parameter */
12595 for(pp
= &(*np
)->body
.parameter
; *pp
; )
12596 if(!struncmp((*pp
)->attribute
, "name", 4)
12597 && (!*((*pp
)->attribute
+ 4)
12598 || *((*pp
)->attribute
+ 4) == '*')){
12599 PARAMETER
*free_me
= *pp
;
12601 free_me
->next
= NULL
;
12602 mail_free_body_parameter(&free_me
);
12608 set_parameter(pp
, "name", a
->l
.f
.remote
);
12610 /* Then set the Content-Disposition ala RFC1806 */
12611 if(!(*np
)->body
.disposition
.type
){
12612 (*np
)->body
.disposition
.type
= cpystr("attachment");
12613 for(pp
= &(*np
)->body
.disposition
.parameter
; *pp
; )
12614 if(!struncmp((*pp
)->attribute
, "filename", 4)
12615 && (!*((*pp
)->attribute
+ 4)
12616 || *((*pp
)->attribute
+ 4) == '*')){
12617 PARAMETER
*free_me
= *pp
;
12619 free_me
->next
= NULL
;
12620 mail_free_body_parameter(&free_me
);
12626 set_parameter(pp
, "filename", a
->l
.f
.remote
);
12629 if(((*np
)->body
.contents
.text
.data
= (void *) so_get(FileStar
, a
->l
.f
.local
, READ_ACCESS
)) != NULL
){
12630 (*np
)->body
.type
= mt_translate_type(a
->l
.f
.type
);
12631 (*np
)->body
.subtype
= cpystr(a
->l
.f
.subtype
);
12632 (*np
)->body
.encoding
= ENCBINARY
;
12633 (*np
)->body
.size
.bytes
= name_file_size(a
->l
.f
.local
);
12635 if((*np
)->body
.type
== TYPEOTHER
12636 && !set_mime_type_by_extension(&(*np
)->body
, a
->l
.f
.local
))
12637 set_mime_type_by_grope(&(*np
)->body
);
12639 so_release((STORE_S
*)(*np
)->body
.contents
.text
.data
);
12643 err
= "Can't open uploaded attachment";
12649 BODY
*newbody
= copy_body(NULL
, a
->l
.b
.body
);
12650 (*np
)->body
= *newbody
;
12651 fs_give((void **) &newbody
);
12652 peBodyMoveContents(a
->l
.b
.body
, &(*np
)->body
);
12655 err
= "BOTCH: Unknown attachment type";
12664 /* assign MIME parameters to text body part */
12665 tbp
->type
= TYPETEXT
;
12666 if(md
->html
) tbp
->subtype
= cpystr("HTML");
12668 tbp
->contents
.text
.data
= (void *) md
->msgtext
;
12669 tbp
->encoding
= ENCOTHER
;
12671 /* set any text flowed param */
12673 peMsgSetParm(&tbp
->parameter
, "format", "flowed");
12676 CONTEXT_S
*fcc_cntxt
= ps_global
->context_list
;
12678 while(md
->fcc_colid
--)
12679 if(fcc_cntxt
->next
)
12680 fcc_cntxt
= fcc_cntxt
->next
;
12682 if(md
->postop_fcc_no_attach
>= 0){
12683 int oldval
= F_ON(F_NO_FCC_ATTACH
, ps_global
);
12684 F_SET(F_NO_FCC_ATTACH
, ps_global
, md
->postop_fcc_no_attach
);
12685 md
->postop_fcc_no_attach
= oldval
;
12688 pine_encode_body(body
);
12690 rv
= (*md
->postfunc
)(md
->metaenv
, body
, md
->fcc
, &fcc_cntxt
, errbuf
);
12692 if(md
->postop_fcc_no_attach
>= 0){
12693 F_SET(F_NO_FCC_ATTACH
, ps_global
, md
->postop_fcc_no_attach
);
12697 if((flags
& PMC_PRSRV_ATT
) == 0)
12698 peFreeAttach(&peCompAttach
);
12701 /* maintain pointers to attachments */
12702 (void) peMsgAttachCollector(NULL
, body
);
12707 pine_free_body(&body
);
12711 fs_give((void **) &md
->charset
);
12713 free_strlist(&md
->attach
);
12715 pine_free_env(&md
->metaenv
);
12718 free_customs(md
->custom
);
12720 mail_free_envelope(&md
->outgoing
);
12723 Tcl_SetResult(interp
, err
, TCL_VOLATILE
);
12730 peMsgSetParm(PARAMETER
**pp
, char *pa
, char *pv
)
12732 for(; *pp
; pp
= &(*pp
)->next
)
12733 if(!strucmp(pa
, (*pp
)->attribute
)){
12735 fs_give((void **) &(*pp
)->value
);
12741 *pp
= mail_newbody_parameter();
12742 (*pp
)->attribute
= cpystr(pa
);
12745 (*pp
)->value
= cpystr(pv
);
12750 peMsgAttachCollector(Tcl_Interp
*interp
, BODY
*b
)
12752 char *id
, *name
= NULL
;
12754 Tcl_Obj
*aListObj
= NULL
, *aObj
= NULL
;
12756 peFreeAttach(&peCompAttach
);
12759 aListObj
= Tcl_NewListObj(0, NULL
);
12761 if(b
->type
== TYPEMULTIPART
){
12763 * Walk first level, clipping branches and adding them
12764 * to the attachment list...
12766 for(part
= b
->nested
.part
->next
; part
; part
= part
->next
) {
12767 id
= peBodyAttachID(&part
->body
);
12768 aObj
= Tcl_NewListObj(0, NULL
);
12771 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj(id
, -1));
12774 if((name
= get_filename_parameter(NULL
, 0, &part
->body
, NULL
)) != NULL
){
12775 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj(name
, -1));
12776 fs_give((void **) &name
);
12779 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj("Unknown", -1));
12782 Tcl_ListObjAppendElement(interp
, aObj
,
12783 Tcl_NewLongObj((part
->body
.encoding
== ENCBASE64
)
12784 ? ((part
->body
.size
.bytes
* 3)/4)
12785 : part
->body
.size
.bytes
));
12788 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s/%s",
12789 body_type_names(part
->body
.type
),
12790 part
->body
.subtype
? part
->body
.subtype
: rfc822_default_subtype (part
->body
.type
));
12791 Tcl_ListObjAppendElement(interp
, aObj
, Tcl_NewStringObj(tmp_20k_buf
, -1));
12792 Tcl_ListObjAppendElement(interp
, aListObj
, aObj
);
12802 peFccAppend(Tcl_Interp
*interp
, Tcl_Obj
*obj
, char *fcc
, int colid
)
12804 Tcl_Obj
*objfcc
= NULL
;
12807 colid
= (ps_global
->context_list
&& (ps_global
->context_list
->use
& CNTXT_INCMNG
)) ? 1 : 0;
12809 return((objfcc
= Tcl_NewListObj(0, NULL
))
12810 && Tcl_ListObjAppendElement(interp
, objfcc
, Tcl_NewStringObj("fcc", -1)) == TCL_OK
12811 && peAppListF(interp
, objfcc
, "%i%s", colid
, fcc
) == TCL_OK
12812 && Tcl_ListObjAppendElement(interp
, obj
, objfcc
) == TCL_OK
);
12816 /* * * * * * * * * * * * * Start of Address Management Routines * * * * * * * * * * * */
12820 * PEAddressCmd - export various bits of address book/directory access
12823 PEAddressCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
12827 dprint((2, "PEAddressCmd"));
12830 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
12833 else if(!ps_global
){
12834 Tcl_SetResult(interp
, "PEAddress: no open folder", TCL_STATIC
);
12837 else if((op
= Tcl_GetStringFromObj(objv
[1], NULL
)) != NULL
){
12839 if(!strcmp(op
, "safecheck")){
12840 if(peInitAddrbooks(interp
, 1) != TCL_OK
)
12844 else if(!strcmp(op
, "books")){
12848 * return the list of configured address books
12851 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
12854 for(i
= 0; i
< as
.n_addrbk
; i
++){
12857 objmv
[0] = Tcl_NewIntObj(i
);
12858 if(as
.adrbks
[i
].abnick
){
12859 objmv
[1] = Tcl_NewStringObj(as
.adrbks
[i
].abnick
, -1);
12864 snprintf(buf
, sizeof(buf
), "Address book number %d", i
+ 1);
12865 objmv
[1] = Tcl_NewStringObj(buf
, -1);
12868 objmv
[2] = Tcl_NewStringObj(as
.adrbks
[i
].filename
? as
.adrbks
[i
].filename
: "", -1);
12870 objmv
[3] = Tcl_NewIntObj(as
.adrbks
[i
].access
== ReadWrite
);
12872 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
12873 Tcl_NewListObj(4, objmv
));
12879 else if(objc
== 3){
12880 if(!strcmp(op
, "parselist")){
12882 ADDRESS
*addrlist
= NULL
, *atmp
, *anextp
;
12883 static char *fakedomain
= "@";
12885 if((addrstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
)
12886 addrstr
= cpystr(addrstr
); /* can't munge tcl copy */
12888 ps_global
->c_client_error
[0] = '\0';
12889 rfc822_parse_adrlist(&addrlist
, addrstr
,
12890 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
))
12891 ? fakedomain
: ps_global
->maildomain
);
12893 fs_give((void **) &addrstr
);
12894 if(ps_global
->c_client_error
[0]){
12895 Tcl_SetResult(interp
, ps_global
->c_client_error
, TCL_STATIC
);
12899 for(atmp
= addrlist
; atmp
; ){
12902 anextp
= atmp
->next
;
12904 tmp_20k_buf
[0] = '\0';
12905 rbuf
.f
= dummy_soutr
;
12907 rbuf
.beg
= tmp_20k_buf
;
12908 rbuf
.cur
= tmp_20k_buf
;
12909 rbuf
.end
= tmp_20k_buf
+SIZEOF_20KBUF
-1;
12910 rfc822_output_address_list(&rbuf
, atmp
, 0L, NULL
);
12912 Tcl_ListObjAppendElement(interp
,
12913 Tcl_GetObjResult(interp
),
12914 Tcl_NewStringObj(tmp_20k_buf
, -1));
12918 mail_free_address(&addrlist
);
12921 else if(!strcmp(op
, "xlookup")){
12923 ADDRESS
*addrlist
= NULL
, *atmp
, *anextp
;
12924 static char *fakedomain
= "@";
12926 if((addrstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
)
12927 addrstr
= cpystr(addrstr
); /* can't munge tcl copy */
12929 ps_global
->c_client_error
[0] = '\0';
12930 rfc822_parse_adrlist(&addrlist
, addrstr
,
12931 (F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
))
12932 ? fakedomain
: ps_global
->maildomain
);
12934 fs_give((void **) &addrstr
);
12935 if(ps_global
->c_client_error
[0]){
12936 Tcl_SetResult(interp
, ps_global
->c_client_error
, TCL_STATIC
);
12940 for(atmp
= addrlist
; atmp
; ){
12941 anextp
= atmp
->next
;
12943 tmp_20k_buf
[0] = '\0';
12945 if(atmp
->host
[0] == '@'){
12946 /* leading ampersand means "missing-hostname" */
12951 rbuf
.f
= dummy_soutr
;
12953 rbuf
.beg
= tmp_20k_buf
;
12954 rbuf
.cur
= tmp_20k_buf
;
12955 rbuf
.end
= tmp_20k_buf
+SIZEOF_20KBUF
-1;
12956 rfc822_output_address_list(&rbuf
, atmp
, 0L, NULL
);
12958 Tcl_ListObjAppendElement(interp
,
12959 Tcl_GetObjResult(interp
),
12960 Tcl_NewStringObj(tmp_20k_buf
, -1));
12962 } /* else group syntax, move on */
12967 mail_free_address(&addrlist
);
12970 else if(!strcmp(op
, "format")){
12974 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
12980 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
)
12981 for(i
= 0; i
< as
.n_addrbk
; i
++)
12983 addrbook_new_disp_form(&as
.adrbks
[booknum
], ps_global
->VAR_ABOOK_FORMATS
, booknum
, NULL
);
12985 for(i
= 0; i
< NFIELDS
&& as
.adrbks
[booknum
].disp_form
[i
].type
!= Notused
; i
++){
12986 switch(as
.adrbks
[booknum
].disp_form
[i
].type
){
13010 objmv
[0] = Tcl_NewStringObj(s
, -1);
13011 objmv
[1] = Tcl_NewIntObj((100 * as
.adrbks
[booknum
].disp_form
[i
].width
) / ps_global
->ttyo
->screen_cols
);
13012 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13013 Tcl_NewListObj(2, objmv
));
13021 snprintf(buf
, sizeof(buf
), "PEAddress list: unknown address book number \"%d\"", booknum
);
13022 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13025 else if(!strcmp(op
, "list")){
13026 int i
, j
, k
, n
, booknum
;
13029 Tcl_Obj
*objev
[NFIELDS
+ 1], *objhv
[2];
13031 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13037 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
)
13038 for(i
= 0; i
< as
.n_addrbk
; i
++)
13040 addrbook_new_disp_form(&as
.adrbks
[booknum
], ps_global
->VAR_ABOOK_FORMATS
, booknum
, NULL
);
13043 (ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, i
));
13046 /* first member is type: Single, List or Lookup */
13054 default : /* not set!?! */
13061 objhv
[0] = Tcl_NewStringObj(ae
->nickname
, -1);
13062 objhv
[1] = Tcl_NewStringObj(s
, -1);
13063 objev
[n
= 0] = Tcl_NewListObj(2, objhv
);
13066 * set fields based on VAR_ABOOK_FORMATS
13069 for(j
= 0; j
< NFIELDS
&& as
.adrbks
[booknum
].disp_form
[j
].type
!= Notused
; j
++){
13070 switch(as
.adrbks
[booknum
].disp_form
[j
].type
){
13072 objev
[++n
] = Tcl_NewStringObj(ae
->nickname
, -1);
13075 objev
[++n
] = Tcl_NewStringObj(ae
->fullname
, -1);
13078 if(ae
->tag
== Single
){
13079 objev
[++n
] = Tcl_NewStringObj(ae
->addr
.addr
, -1);
13084 for(k
= 0; ae
->addr
.list
[k
]; k
++)
13087 objav
= (Tcl_Obj
**) fs_get(k
* sizeof(Tcl_Obj
*));
13088 for(k
= 0; ae
->addr
.list
[k
]; k
++)
13089 objav
[k
] = Tcl_NewStringObj(ae
->addr
.list
[k
], -1);
13091 objev
[++n
] = Tcl_NewListObj(k
, objav
);
13092 fs_give((void **) &objav
);
13096 objev
[++n
] = Tcl_NewStringObj(ae
->fcc
? ae
->fcc
: "", -1);
13099 objev
[++n
] = Tcl_NewStringObj(ae
->extra
? ae
->extra
: "", -1);
13107 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13108 Tcl_NewListObj(n
+ 1, objev
));
13114 snprintf(buf
, sizeof(buf
), "PEAddress list: unknown address book number \"%d\"", booknum
);
13115 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13119 else if(objc
== 4){
13120 if(!strcmp(op
, "verify")){
13122 * The object here is to check the following list of field values
13123 * to see that they are valid address list, expanding if necessary.
13124 * The first argument is the list of field values, with "to" being
13125 * first. The second arg is the current fcc value.
13127 * The return value is of the following form:
13129 * { {{errstr {{oldstr newstr {ldap-opts ...}} ...}} ...} newfcc}
13132 char *addrstr
, *newaddr
= NULL
, *error
= NULL
,
13133 *tstr1
, *tstr2
, *fcc
, *newfcc
= NULL
;
13135 int rv
, badadrs
, i
, numlistvals
,
13136 numldapqueries
= 0;
13137 Tcl_Obj
*resObj
= NULL
, *secObj
, *strObj
, *adrObj
, *res2Obj
;
13141 wpldap_global
->query_no
++;
13142 if(wpldap_global
->ldap_search_list
){
13143 wpldap_global
->ldap_search_list
=
13144 free_wpldapres(wpldap_global
->ldap_search_list
);
13147 tsl
= &(wpldap_global
->ldap_search_list
);
13148 #endif /* ENABLE_LDAP */
13150 if(Tcl_ListObjGetElements(interp
, objv
[2], &numlistvals
,
13151 &objVal
) == TCL_OK
){
13152 if((fcc
= Tcl_GetStringFromObj(objv
[3], NULL
)) == NULL
)
13154 res2Obj
= Tcl_NewListObj(0, NULL
);
13155 for(i
= 0; i
< numlistvals
; i
++){
13158 if((addrstr
= Tcl_GetStringFromObj(objVal
[i
], NULL
)) == NULL
)
13161 addrstr
= cpystr(addrstr
); /* can't munge tcl copy */
13163 toaddr
.arg
.str
= cpystr(addrstr
);
13164 l
= strlen(addrstr
);
13166 resObj
= Tcl_NewListObj(0, NULL
);
13167 secObj
= Tcl_NewListObj(0, NULL
);
13168 for(tstr1
= addrstr
; tstr1
; tstr1
= tstr2
){
13169 tstr2
= strqchr(tstr1
, ',', 0, -1);
13173 strncpy(toaddr
.arg
.str
, tstr1
, l
);
13174 toaddr
.arg
.str
[l
] = '\0';
13176 removing_leading_and_trailing_white_space(toaddr
.arg
.str
);
13177 if(*toaddr
.arg
.str
){
13178 if(i
== 0 && tstr1
== addrstr
)
13179 newfcc
= cpystr(fcc
);
13181 rv
= our_build_address(toaddr
, &newaddr
, &error
, &newfcc
, NULL
);
13184 strObj
= Tcl_NewListObj(0, NULL
);
13185 Tcl_ListObjAppendElement(interp
, strObj
,
13186 Tcl_NewStringObj(toaddr
.arg
.str
, -1));
13187 Tcl_ListObjAppendElement(interp
, strObj
,
13188 Tcl_NewStringObj(newaddr
,-1));
13189 /* append whether or not ldap stuff
13192 adrObj
= Tcl_NewListObj(0,NULL
);
13195 LDAP_CHOOSE_S
*tres
;
13196 LDAP_SERV_RES_S
*trl
;
13201 tres
= (LDAP_CHOOSE_S
*)fs_get(sizeof(LDAP_CHOOSE_S
));
13202 for(trl
= (*tsl
)->reslist
; trl
;
13204 for(e
= ldap_first_entry(trl
->ld
,
13207 e
= ldap_next_entry(trl
->ld
, e
)){
13208 tres
->ld
= trl
->ld
;
13209 tres
->selected_entry
= e
;
13210 tres
->info_used
= trl
->info_used
;
13211 tres
->serv
= trl
->serv
;
13212 if((newadr
= address_from_ldap(tres
)) != NULL
){
13213 if(newadr
->mailbox
&& newadr
->host
){
13217 len
= est_size(newadr
);
13218 ret_to
= (char *)fs_get(len
* sizeof(char));
13220 rbuf
.f
= dummy_soutr
;
13224 rbuf
.end
= ret_to
+len
-1;
13225 rfc822_output_address_list(&rbuf
, newadr
, 0L, NULL
);
13227 Tcl_ListObjAppendElement(interp
,
13228 adrObj
, Tcl_NewStringObj(ret_to
, -1));
13229 fs_give((void **)&ret_to
);
13231 mail_free_address(&newadr
);
13235 fs_give((void **)&tres
);
13237 tsl
= &((*tsl
)->next
);
13239 #endif /* ENABLE_LDAP */
13240 Tcl_ListObjAppendElement(interp
, strObj
, adrObj
);
13241 Tcl_ListObjAppendElement(interp
, secObj
, strObj
);
13253 resObj
= Tcl_NewListObj(0, NULL
);
13254 Tcl_ListObjAppendElement(interp
, resObj
,
13255 Tcl_NewStringObj(badadrs
13256 ? (error
? error
: "Unknown")
13258 Tcl_ListObjAppendElement(interp
, resObj
, secObj
);
13259 Tcl_ListObjAppendElement(interp
, res2Obj
, resObj
);
13260 fs_give((void **) &addrstr
);
13261 fs_give((void **) &toaddr
.arg
.str
);
13263 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), res2Obj
);
13264 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13265 Tcl_NewStringObj(newfcc
? newfcc
13266 : (fcc
? fcc
: ""), -1));
13267 if(newfcc
) fs_give((void **)&newfcc
);
13272 else if(!strcmp(op
, "expand")){
13274 char *addrstr
, *newaddr
= NULL
, *error
= NULL
, *fcc
, *newfcc
= NULL
;
13278 * Return value will be of the form:
13280 * ldap-query-number,
13284 * ldap-query-number will be nonzero if
13285 * there is something interesting to display as a result
13286 * of an ldap query.
13290 * Given what looks like an rfc822 address line, parse the
13291 * contents and expand any tokens that look like they ought
13295 if((addrstr
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
13297 toaddr
.arg
.str
= cpystr(addrstr
); /* can't munge tcl copy */
13298 fcc
= Tcl_GetStringFromObj(objv
[3], NULL
);
13300 wpldap_global
->query_no
++;
13301 if(wpldap_global
->ldap_search_list
){
13302 wpldap_global
->ldap_search_list
=
13303 free_wpldapres(wpldap_global
->ldap_search_list
);
13305 #endif /* ENABLE_LDAP */
13306 newfcc
= cpystr(fcc
);
13307 rv
= our_build_address(toaddr
, &newaddr
, &error
, &newfcc
, NULL
);
13308 fs_give((void **) &toaddr
.arg
.str
);
13312 * c-client quotes results with spaces in them, so we'll go
13313 * through and unquote them.
13315 if(wpldap_global
->ldap_search_list
){
13317 char *tstr1
, *tstr2
;
13318 char *qstr1
, *newnewaddr
;
13321 for(tres
= wpldap_global
->ldap_search_list
;
13322 tres
; tres
= tres
->next
){
13323 if(strqchr(tres
->str
, ' ', 0, -1)){
13324 qstr1len
= strlen(tres
->str
) + 3;
13325 qstr1
= (char *)fs_get(qstr1len
*sizeof(char));
13326 snprintf(qstr1
, qstr1len
, "\"%.*s\"", qstr1len
, tres
->str
);
13327 for(tstr1
= newaddr
; tstr1
; tstr1
= tstr2
){
13328 tstr2
= strqchr(tstr1
, ',', 0, -1);
13329 if(strncmp(qstr1
, tstr1
, tstr2
? tstr2
- tstr1
13330 : strlen(tstr1
)) == 0){
13332 l
= strlen(newaddr
) + strlen(tres
->str
) + 2
13333 + (tstr2
? strlen(tstr2
) : 0);
13334 newnewaddr
= (char *) fs_get(l
* sizeof(char));
13335 snprintf(newnewaddr
, l
, "%.*s%s%s", (int) (tstr1
- newaddr
),
13336 newaddr
, tres
->str
, tstr2
? tstr2
: "");
13337 fs_give((void **)&newaddr
);
13338 newaddr
= newnewaddr
;
13343 if(tstr2
&& *tstr2
== ' ')
13347 fs_give((void **) &qstr1
);
13351 #endif /* ENABLE_LDAP */
13352 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13353 Tcl_NewStringObj(newaddr
, -1)) != TCL_OK
)
13356 if(wpldap_global
->ldap_search_list
){
13357 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13358 Tcl_NewIntObj(wpldap_global
->query_no
)) != TCL_OK
)
13362 #endif /* ENABLE_LDAP */
13363 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13364 Tcl_NewIntObj(0)) != TCL_OK
)
13366 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13367 Tcl_NewStringObj(newfcc
? newfcc
13368 : (fcc
? fcc
: ""), -1)) != TCL_OK
)
13370 if(newfcc
) fs_give((void **)&newfcc
);
13375 Tcl_SetResult(interp
, error
? error
: "Indeterminate error", TCL_VOLATILE
);
13376 if(newfcc
) fs_give((void **)&newfcc
);
13381 else if(!strcmp(op
, "complete")){
13383 * CMD: complete uid
13385 * Look for possible completions for
13386 * given query_string.
13388 * ARGS: <query_string> <uid>
13390 * Returns: candidate list: {nickname {personal mailbox}}
13392 char *query
, *errstr
;
13394 COMPLETE_S
*completions
, *cp
;
13396 if(peInitAddrbooks(interp
, 0) == TCL_OK
){
13397 if((query
= Tcl_GetStringFromObj(objv
[2], NULL
)) != NULL
){
13398 if(Tcl_GetLongFromObj(interp
, objv
[3], &uid
) == TCL_OK
){
13400 completions
= adrbk_list_of_completions(query
,
13401 ps_global
->mail_stream
,
13404 ((strlen(query
) >= 5) ? ALC_INCLUDE_LDAP
: 0) |
13405 #endif /* ENABLE_LDAP */
13409 for(cp
= completions
; cp
; cp
= cp
->next
)
13410 peAppListF(interp
, Tcl_GetObjResult(interp
), "%s %s %s",
13411 cp
->nickname
? cp
->nickname
: "",
13412 cp
->full_address
? cp
->full_address
: "",
13413 cp
->fcc
? cp
->fcc
: "");
13415 free_complete_s(&completions
);
13418 Tcl_SetResult(interp
, "", TCL_STATIC
);
13423 errstr
= "PEAddress: Cannot read UID";
13426 errstr
= "PEAddress: Cannot get completion query";
13429 errstr
= "PEAddress: Address Book initialization failed";
13431 Tcl_SetResult(interp
, errstr
, TCL_STATIC
);
13435 else if(objc
== 5){
13436 if(!strcmp(op
, "entry")){
13437 int booknum
, i
, aindex
;
13438 char *nick
, *astr
= NULL
, *errstr
= NULL
, *fccstr
= NULL
, buf
[128];
13442 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13446 * Given an address book handle and nickname, return address
13448 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
)
13449 for(i
= 0; i
< as
.n_addrbk
; i
++)
13451 if((nick
= Tcl_GetStringFromObj(objv
[3], NULL
)) == NULL
){
13452 Tcl_SetResult(interp
, "PEAddress list: Can't get nickname", TCL_STATIC
);
13455 if(Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
13456 || (*nick
== '\0' && aindex
< 0)){
13457 Tcl_SetResult(interp
, "PEAddress list: Can't get aindex", TCL_STATIC
);
13461 ? (ae
= adrbk_lookup_by_nick(as
.adrbks
[booknum
].address_book
, nick
, NULL
))
13462 : (ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, aindex
))){
13464 bldto
.arg
.abe
= ae
;
13466 (void) our_build_address(bldto
, &astr
, &errstr
, &fccstr
, NULL
);
13470 fs_give((void **) &astr
);
13472 Tcl_SetResult(interp
, errstr
, TCL_VOLATILE
);
13480 l
= (4*strlen(astr
) + 1) * sizeof(char);
13481 p
= (char *) fs_get(l
);
13482 if(rfc1522_decode_to_utf8((unsigned char *) p
, l
, astr
) == (unsigned char *) p
){
13483 fs_give((void **) &astr
);
13487 fs_give((void **)&p
);
13492 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13493 Tcl_NewStringObj(astr
, -1));
13494 fs_give((void **) &astr
);
13497 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13498 Tcl_NewStringObj(*fccstr
? fccstr
: "\"\"", -1));
13499 fs_give((void **) &fccstr
);
13502 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
13503 Tcl_NewStringObj("", -1));
13506 Tcl_SetResult(interp
, "", TCL_STATIC
);
13511 snprintf(buf
, sizeof(buf
), "PEAddress list: unknown address book ID %d", booknum
);
13512 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13515 else if(!strcmp(op
, "fullentry")){
13516 int booknum
, j
, aindex
;
13521 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13525 * Given an address book handle and nickname, return
13526 * nickname, fullname, address(es), fcc, and comments
13528 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
){
13529 if(booknum
>= 0 && booknum
< as
.n_addrbk
){
13530 if((nick
= Tcl_GetStringFromObj(objv
[3], NULL
)) == NULL
)
13532 if(Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
13533 || (*nick
== '\0' && aindex
< 0))
13536 ? (ae
= adrbk_lookup_by_nick(as
.adrbks
[booknum
].address_book
, nick
, NULL
))
13537 : (ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, aindex
))){
13538 Tcl_ListObjAppendElement(interp
,
13539 Tcl_GetObjResult(interp
),
13540 Tcl_NewStringObj(ae
->nickname
? ae
->nickname
: "", -1));
13541 Tcl_ListObjAppendElement(interp
,
13542 Tcl_GetObjResult(interp
),
13543 Tcl_NewStringObj(ae
->fullname
? ae
->fullname
: "", -1));
13544 resObj
= Tcl_NewListObj(0,NULL
);
13545 if(ae
->tag
== Single
)
13546 Tcl_ListObjAppendElement(interp
,
13548 Tcl_NewStringObj(ae
->addr
.addr
? ae
->addr
.addr
: "", -1));
13550 for(j
= 0; ae
->addr
.list
[j
]; j
++)
13551 Tcl_ListObjAppendElement(interp
, resObj
,
13552 Tcl_NewStringObj(ae
->addr
.list
[j
] ? ae
->addr
.list
[j
] : "", -1));
13554 Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), resObj
);
13555 Tcl_ListObjAppendElement(interp
,
13556 Tcl_GetObjResult(interp
),
13557 Tcl_NewStringObj(ae
->fcc
? ae
->fcc
: "", -1));
13558 Tcl_ListObjAppendElement(interp
,
13559 Tcl_GetObjResult(interp
),
13560 Tcl_NewStringObj(ae
->extra
? ae
->extra
: "", -1));
13567 else if(!strcmp(op
, "delete")){
13568 char *nick
, buf
[256];
13569 int booknum
, aindex
;
13570 adrbk_cntr_t old_entry
;
13572 if(peInitAddrbooks(interp
, 0) != TCL_OK
){
13573 snprintf(buf
, sizeof(buf
), "PEAddress delete: couldn't init addressbooks");
13574 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13577 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
){
13578 nick
= Tcl_GetStringFromObj(objv
[3], NULL
);
13579 removing_leading_and_trailing_white_space(nick
);
13583 if(booknum
>= 0 && booknum
< as
.n_addrbk
) {
13584 if(as
.adrbks
[booknum
].access
!= ReadWrite
) return TCL_ERROR
;
13585 ab
= as
.adrbks
[booknum
].address_book
;
13588 snprintf(buf
, sizeof(buf
), "PEAddress delete: Book number out of range");
13589 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13592 if((Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
)
13593 || (*nick
== '\0' && aindex
< 0))
13595 adrbk_check_validity(ab
, 1L);
13596 if(ab
->flags
& FILE_OUTOFDATE
||
13597 (ab
->rd
&& ab
->rd
->flags
& REM_OUTOFDATE
)){
13598 Tcl_SetResult(interp
,
13599 "Address book out of sync. Cannot update at this moment",
13604 snprintf(buf
, sizeof(buf
), "PEAddress delete: No nickname");
13605 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13609 ? (!adrbk_lookup_by_nick(ab
, nick
, &old_entry
))
13610 : ((old_entry
= (adrbk_cntr_t
)aindex
) == -1)){
13611 snprintf(buf
, sizeof(buf
), "PEAddress delete: Nickname \"%.128s\" not found", nick
);
13612 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13615 if(adrbk_delete(ab
, old_entry
, 0, 0, 1, 1)){
13616 snprintf(buf
, sizeof(buf
), "PEAddress delete: Couldn't delete addressbook entry");
13617 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13623 else if((objc
== 10 || objc
== 11) && !strcmp(op
, "edit")){
13624 if(!strcmp(op
, "edit")){
13625 int booknum
, adri
, add
, rv
, aindex
;
13626 char *nick
, *fn
, *fcc
, *comment
, *addrfield
,
13627 buf
[256], **addrs
, *orignick
= NULL
;
13628 AdrBk_Entry
*ae
= NULL
;
13630 adrbk_cntr_t old_entry
= NO_NEXT
, new_entry
;
13632 ADDRESS
*adr
= NULL
;
13635 if(peInitAddrbooks(interp
, 0) != TCL_OK
)
13637 if(Tcl_GetIntFromObj(interp
, objv
[2], &booknum
) == TCL_OK
){
13638 if(as
.adrbks
[booknum
].access
!= ReadWrite
) return TCL_ERROR
;
13639 nick
= Tcl_GetStringFromObj(objv
[3], NULL
);
13640 removing_leading_and_trailing_white_space(nick
);
13641 if(Tcl_GetIntFromObj(interp
, objv
[4], &aindex
) != TCL_OK
){
13642 Tcl_SetResult(interp
, "No Address Handle", TCL_VOLATILE
);
13645 fn
= Tcl_GetStringFromObj(objv
[5], NULL
);
13646 removing_leading_and_trailing_white_space(fn
);
13647 if(!*fn
) fn
= NULL
;
13648 addrfield
= Tcl_GetStringFromObj(objv
[6], NULL
);
13649 removing_leading_and_trailing_white_space(addrfield
);
13650 if(!*addrfield
) addrfield
= NULL
;
13652 if(Tcl_ListObjGetElements(interp, objv[7], &numlistvals, &objVal) != TCL_OK)
13655 fcc
= Tcl_GetStringFromObj(objv
[7], NULL
);
13656 removing_leading_and_trailing_white_space(fcc
);
13657 if(!*fcc
) fcc
= NULL
;
13658 comment
= Tcl_GetStringFromObj(objv
[8], NULL
);
13659 removing_leading_and_trailing_white_space(comment
);
13660 if(!*comment
) comment
= NULL
;
13661 if(Tcl_GetIntFromObj(interp
, objv
[9], &add
) != TCL_OK
)
13665 * if objc == 11 then that means that they changed the
13666 * value of nick to something else, and this one is the
13669 orignick
= Tcl_GetStringFromObj(objv
[10], NULL
);
13670 removing_leading_and_trailing_white_space(orignick
);
13672 if((addrs
= parse_addrlist(addrfield
)) != NULL
){
13673 int tbuflen
= strlen(addrfield
);
13675 if(!(tbuf
= (char *) fs_get(sizeof(char) * (tbuflen
+128)))){
13676 Tcl_SetResult(interp
, "malloc error", TCL_VOLATILE
);
13677 fs_give((void **) &addrs
);
13680 for(adri
= 0; addrs
[adri
]; adri
++){
13681 if(*(addrs
[adri
])){
13682 ps_global
->c_client_error
[0] = '\0';
13683 strncpy(tbuf
, addrs
[adri
], tbuflen
+128);
13684 tbuf
[tbuflen
+128-1] = '\0';
13685 rfc822_parse_adrlist(&adr
, tbuf
, "@");
13686 if(adr
) mail_free_address(&adr
);
13688 if(ps_global
->c_client_error
[0]){
13689 snprintf(buf
, sizeof(buf
),"Problem with address %.10s%s: %s",
13690 addrs
[adri
], strlen(addrs
[adri
]) > 10 ?
13691 "..." : "", ps_global
->c_client_error
);
13692 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13694 fs_give((void **) &tbuf
);
13695 fs_give((void **) &addrs
);
13700 if(tbuf
) fs_give((void **)&tbuf
);
13704 /* addrs[adri] = NULL; */
13706 if(adri
> 1) tag
= List
;
13709 if(booknum
>= 0 && booknum
< as
.n_addrbk
) {
13710 ab
= as
.adrbks
[booknum
].address_book
;
13714 fs_give((void **) &addrs
);
13717 adrbk_check_validity(ab
, 1L);
13718 if(ab
->flags
& FILE_OUTOFDATE
||
13719 (ab
->rd
&& ab
->rd
->flags
& REM_OUTOFDATE
)){
13720 Tcl_SetResult(interp
,
13721 "Address book out of sync. Cannot update at this moment",
13726 ae
= adrbk_get_ae(as
.adrbks
[booknum
].address_book
, aindex
);
13728 old_entry
= (adrbk_cntr_t
) aindex
;
13731 Tcl_SetResult(interp
, "No Address Handle!", TCL_VOLATILE
);
13735 else if(nick
&& *nick
&& adrbk_lookup_by_nick(ab
, nick
, NULL
)){
13736 snprintf(buf
, sizeof(buf
), "Entry with nickname %.128s already exists.",
13738 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13740 fs_give((void **) &addrs
);
13744 ((tag
== List
&& ae
->tag
== Single
) ||
13745 (tag
== Single
&& ae
->tag
== List
))){
13746 if(adrbk_delete(ab
, old_entry
, 0,0,1,0)){
13747 snprintf(buf
, sizeof(buf
), "Problem updating from %s to %s.",
13748 ae
->tag
== Single
? "Single" : "List",
13749 tag
== List
? "List" : "Single");
13750 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13752 fs_give((void **) &addrs
);
13755 old_entry
= NO_NEXT
;
13757 if((rv
= adrbk_add(ab
, old_entry
,
13760 tag
== List
? (char *)addrs
:
13761 (addrs
&& *addrs
) ? *addrs
: "",
13763 comment
? comment
: "",
13764 tag
, &new_entry
, NULL
, 0, 1,
13765 tag
== List
? 0 : 1)) != 0){
13766 snprintf(buf
, sizeof(buf
), "Couldn't add entry! rv=%d.", rv
);
13767 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13769 fs_give((void **) &addrs
);
13773 adrbk_listdel_all(ab
, new_entry
);
13774 adrbk_nlistadd(ab
, new_entry
, NULL
, NULL
, addrs
, 0, 1, 1);
13778 snprintf(buf
, sizeof(buf
), "Unknown address book ID %d", booknum
);
13779 Tcl_SetResult(interp
, buf
, TCL_VOLATILE
);
13785 Tcl_SetResult(interp
, "PEAddress: unrecognized command", TCL_STATIC
);
13791 peInitAddrbooks(Tcl_Interp
*interp
, int safe
)
13793 if(ps_global
->remote_abook_validity
> 0)
13794 (void)adrbk_check_and_fix_all(safe
, 0, 0);
13796 if(!init_addrbooks(NoDisplay
, 1, 1, 0)){
13797 Tcl_SetResult(interp
, "No Address Book Configured", TCL_STATIC
);
13807 peRuleStatVal(char *str
, int *n
)
13812 if(!strcmp(str
, "either"))
13813 *n
= PAT_STAT_EITHER
;
13814 else if(!strcmp(str
, "yes"))
13816 else if(!strcmp(str
, "no"))
13825 #define RS_RULE_EDIT 0x0001
13826 #define RS_RULE_ADD 0x0002
13827 #define RS_RULE_DELETE 0x0004
13828 #define RS_RULE_SHUFFUP 0x0008
13829 #define RS_RULE_SHUFFDOWN 0x0010
13830 #define RS_RULE_GETPAT 0x0100
13831 #define RS_RULE_FINDPAT 0x0200
13834 peRuleSet(Tcl_Interp
*interp
, Tcl_Obj
**objv
)
13836 char *rule
, *patvar
, *patval
, *actvar
, *actval
, *tstr
, *ruleaction
;
13837 int rno
, nPat
, nPatEmnt
, nAct
, nActEmnt
, i
, rv
= 0;
13838 Tcl_Obj
**objPat
, **objPatEmnt
, **objAct
, **objActEmnt
;
13839 long rflags
= PAT_USE_CHANGED
, aflags
= 0;
13841 PAT_S
*pat
, *new_pat
;
13843 if(!(rule
= Tcl_GetStringFromObj(objv
[0], NULL
)))
13846 if(!(ruleaction
= Tcl_GetStringFromObj(objv
[1], NULL
)))
13849 if(Tcl_GetIntFromObj(interp
, objv
[2], &rno
) == TCL_ERROR
)
13852 if(!(strcmp(rule
, "filter")))
13853 rflags
|= ROLE_DO_FILTER
;
13854 else if(!(strcmp(rule
, "score")))
13855 rflags
|= ROLE_DO_SCORES
;
13856 else if(!(strcmp(rule
, "indexcolor")))
13857 rflags
|= ROLE_DO_INCOLS
;
13861 if(!(strcmp(ruleaction
, "edit"))){
13862 aflags
|= RS_RULE_EDIT
;
13863 aflags
|= RS_RULE_GETPAT
;
13864 aflags
|= RS_RULE_FINDPAT
;
13866 else if(!(strcmp(ruleaction
, "add"))){
13867 aflags
|= RS_RULE_ADD
;
13868 aflags
|= RS_RULE_GETPAT
;
13870 else if(!(strcmp(ruleaction
, "delete"))){
13871 aflags
|= RS_RULE_DELETE
;
13872 aflags
|= RS_RULE_FINDPAT
;
13874 else if(!(strcmp(ruleaction
, "shuffup"))){
13875 aflags
|= RS_RULE_SHUFFUP
;
13876 aflags
|= RS_RULE_FINDPAT
;
13878 else if(!(strcmp(ruleaction
, "shuffdown"))){
13879 aflags
|= RS_RULE_SHUFFDOWN
;
13880 aflags
|= RS_RULE_FINDPAT
;
13882 else return(TCL_ERROR
);
13884 if(aflags
& RS_RULE_FINDPAT
){
13885 if(any_patterns(rflags
, &pstate
)){
13886 for(pat
= first_pattern(&pstate
), i
= 0;
13888 pat
= next_pattern(&pstate
), i
++);
13889 if(i
!= rno
) return(TCL_ERROR
);
13892 if(aflags
& RS_RULE_GETPAT
){
13895 Tcl_ListObjGetElements(interp
, objv
[3], &nPat
, &objPat
);
13896 Tcl_ListObjGetElements(interp
, objv
[4], &nAct
, &objAct
);
13898 new_pat
= (PAT_S
*)fs_get(sizeof(PAT_S
));
13899 memset(new_pat
, 0, sizeof(PAT_S
));
13900 new_pat
->patgrp
= (PATGRP_S
*)fs_get(sizeof(PATGRP_S
));
13901 memset(new_pat
->patgrp
, 0, sizeof(PATGRP_S
));
13902 new_pat
->action
= (ACTION_S
*)fs_get(sizeof(ACTION_S
));
13903 memset(new_pat
->action
, 0, sizeof(ACTION_S
));
13905 /* Set up the pattern group */
13906 for(i
= 0; i
< nPat
; i
++){
13907 Tcl_ListObjGetElements(interp
, objPat
[i
], &nPatEmnt
, &objPatEmnt
);
13908 if(nPatEmnt
!= 2) return(TCL_ERROR
);
13909 patvar
= Tcl_GetStringFromObj(objPatEmnt
[0], NULL
);
13910 patval
= Tcl_GetStringFromObj(objPatEmnt
[1], NULL
);
13911 if(!patvar
|| !patval
) return(TCL_ERROR
);
13915 tstr
= cpystr(patval
);
13916 removing_leading_and_trailing_white_space(tstr
);
13918 fs_give((void **) &tstr
);
13921 if(!(strcmp(patvar
, "nickname"))){
13922 new_pat
->patgrp
->nick
= tstr
;
13925 else if(!(strcmp(patvar
, "comment"))){
13926 new_pat
->patgrp
->comment
= tstr
;
13929 else if(!(strcmp(patvar
, "to"))){
13930 new_pat
->patgrp
->to
= string_to_pattern(tstr
);
13932 else if(!(strcmp(patvar
, "from"))){
13933 new_pat
->patgrp
->from
= string_to_pattern(tstr
);
13935 else if(!(strcmp(patvar
, "sender"))){
13936 new_pat
->patgrp
->sender
= string_to_pattern(tstr
);
13938 else if(!(strcmp(patvar
, "cc"))){
13939 new_pat
->patgrp
->cc
= string_to_pattern(tstr
);
13941 else if(!(strcmp(patvar
, "recip"))){
13942 new_pat
->patgrp
->recip
= string_to_pattern(tstr
);
13944 else if(!(strcmp(patvar
, "partic"))){
13945 new_pat
->patgrp
->partic
= string_to_pattern(tstr
);
13947 else if(!(strcmp(patvar
, "news"))){
13948 new_pat
->patgrp
->news
= string_to_pattern(tstr
);
13950 else if(!(strcmp(patvar
, "subj"))){
13951 new_pat
->patgrp
->subj
= string_to_pattern(tstr
);
13953 else if(!(strcmp(patvar
, "bodytext"))){
13954 new_pat
->patgrp
->bodytext
= string_to_pattern(tstr
);
13956 else if(!(strcmp(patvar
, "alltext"))){
13957 new_pat
->patgrp
->alltext
= string_to_pattern(tstr
);
13959 else if(!(strcmp(patvar
, "keyword"))){
13960 new_pat
->patgrp
->keyword
= string_to_pattern(tstr
);
13962 else if(!(strcmp(patvar
, "charset"))){
13963 new_pat
->patgrp
->charsets
= string_to_pattern(tstr
);
13965 else if(!(strcmp(patvar
, "ftype"))){
13966 if(!tstr
) return(TCL_ERROR
);
13968 if(!(strcmp(tstr
, "any")))
13969 new_pat
->patgrp
->fldr_type
= FLDR_ANY
;
13970 else if(!(strcmp(tstr
, "news")))
13971 new_pat
->patgrp
->fldr_type
= FLDR_NEWS
;
13972 else if(!(strcmp(tstr
, "email")))
13973 new_pat
->patgrp
->fldr_type
= FLDR_EMAIL
;
13974 else if(!(strcmp(tstr
, "specific")))
13975 new_pat
->patgrp
->fldr_type
= FLDR_SPECIFIC
;
13977 free_pat(&new_pat
);
13981 else if(!(strcmp(patvar
, "folder"))){
13982 new_pat
->patgrp
->folder
= string_to_pattern(tstr
);
13984 else if(!(strcmp(patvar
, "stat_new"))){
13985 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_new
)){
13986 free_pat(&new_pat
);
13990 else if(!(strcmp(patvar
, "stat_rec"))){
13991 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_rec
)){
13992 free_pat(&new_pat
);
13996 else if(!(strcmp(patvar
, "stat_del"))){
13997 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_del
)){
13998 free_pat(&new_pat
);
14002 else if(!(strcmp(patvar
, "stat_imp"))){
14003 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_imp
)){
14004 free_pat(&new_pat
);
14008 else if(!(strcmp(patvar
, "stat_ans"))){
14009 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_ans
)){
14010 free_pat(&new_pat
);
14014 else if(!(strcmp(patvar
, "stat_8bitsubj"))){
14015 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_8bitsubj
)){
14016 free_pat(&new_pat
);
14020 else if(!(strcmp(patvar
, "stat_bom"))){
14021 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_bom
)){
14022 free_pat(&new_pat
);
14026 else if(!(strcmp(patvar
, "stat_boy"))){
14027 if(peRuleStatVal(tstr
, &new_pat
->patgrp
->stat_boy
)){
14028 free_pat(&new_pat
);
14032 else if(!(strcmp(patvar
, "age"))){
14033 new_pat
->patgrp
->age
= parse_intvl(tstr
);
14035 else if(!(strcmp(patvar
, "size"))){
14036 new_pat
->patgrp
->size
= parse_intvl(tstr
);
14038 else if(!(strcmp(patvar
, "score"))){
14039 new_pat
->patgrp
->score
= parse_intvl(tstr
);
14041 else if(!(strcmp(patvar
, "addrbook"))){
14043 if(!strcmp(tstr
, "either"))
14044 new_pat
->patgrp
->inabook
= IAB_EITHER
;
14045 else if(!strcmp(tstr
, "yes"))
14046 new_pat
->patgrp
->inabook
= IAB_YES
;
14047 else if(!strcmp(tstr
, "no"))
14048 new_pat
->patgrp
->inabook
= IAB_NO
;
14049 else if(!strcmp(tstr
, "yesspecific"))
14050 new_pat
->patgrp
->inabook
= IAB_SPEC_YES
;
14051 else if(!strcmp(tstr
, "nospecific"))
14052 new_pat
->patgrp
->inabook
= IAB_SPEC_NO
;
14060 free_pat(&new_pat
);
14062 else if(!(strcmp(patvar
, "specificabook"))){
14063 new_pat
->patgrp
->abooks
= string_to_pattern(tstr
);
14065 else if(!(strcmp(patvar
, "headers"))){
14067 int nHdrList
, nHdrPair
, n
;
14068 Tcl_Obj
**objHdrList
, **objHdrPair
;
14070 Tcl_ListObjGetElements(interp
, objPatEmnt
[1], &nHdrList
, &objHdrList
);
14072 for(ahp
= &new_pat
->patgrp
->arbhdr
; *ahp
; ahp
= &(*ahp
)->next
)
14075 for (n
= 0; n
< nHdrList
; n
++){
14079 Tcl_ListObjGetElements(interp
, objHdrList
[n
], &nHdrPair
, &objHdrPair
);
14083 hdrfld
= Tcl_GetStringFromObj(objHdrPair
[0], NULL
);
14084 hdrval
= Tcl_GetStringFromObj(objHdrPair
[1], NULL
);
14087 *ahp
= (ARBHDR_S
*) fs_get(sizeof(ARBHDR_S
));
14088 memset(*ahp
, 0, sizeof(ARBHDR_S
));
14090 (*ahp
)->field
= cpystr(hdrfld
);
14092 (*ahp
)->p
= string_to_pattern(hdrval
);
14095 (*ahp
)->isemptyval
= 1;
14097 ahp
= &(*ahp
)->next
;
14102 free_pat(&new_pat
);
14107 fs_give((void **) &tstr
);
14113 if((new_pat
->patgrp
->inabook
& (IAB_SPEC_YES
| IAB_SPEC_NO
)) == 0
14114 && new_pat
->patgrp
->abooks
)
14115 free_pattern(&new_pat
->patgrp
->abooks
);
14117 if(new_pat
->patgrp
->fldr_type
!= FLDR_SPECIFIC
&& new_pat
->patgrp
->folder
)
14118 free_pattern(&new_pat
->patgrp
->folder
);
14120 /* set up the action */
14121 if(!(strcmp(rule
, "filter")))
14122 new_pat
->action
->is_a_filter
= 1;
14123 else if(!(strcmp(rule
, "role")))
14124 new_pat
->action
->is_a_role
= 1;
14125 else if(!(strcmp(rule
, "score")))
14126 new_pat
->action
->is_a_score
= 1;
14127 else if(!(strcmp(rule
, "indexcolor")))
14128 new_pat
->action
->is_a_incol
= 1;
14130 free_pat(&new_pat
);
14134 for(i
= 0; i
< nAct
; i
++){
14135 Tcl_ListObjGetElements(interp
, objAct
[i
], &nActEmnt
, &objActEmnt
);
14137 free_pat(&new_pat
);
14141 actvar
= Tcl_GetStringFromObj(objActEmnt
[0], NULL
);
14142 actval
= Tcl_GetStringFromObj(objActEmnt
[1], NULL
);
14143 if(!actvar
|| !actval
){
14144 free_pat(&new_pat
);
14148 if(new_pat
->action
->is_a_filter
&& !(strcmp(actvar
, "action"))){
14149 if(!strcmp(actval
, "delete"))
14150 new_pat
->action
->kill
= 1;
14151 else if(!strcmp(actval
, "move"))
14152 new_pat
->action
->kill
= 0;
14154 free_pat(&new_pat
);
14158 else if(new_pat
->action
->is_a_filter
&& !(strcmp(actvar
, "folder"))){
14159 tstr
= cpystr(actval
);
14160 removing_leading_and_trailing_white_space(tstr
);
14161 if(!(*tstr
)) fs_give((void **)&tstr
);
14162 new_pat
->action
->folder
= string_to_pattern(tstr
);
14163 if(tstr
) fs_give((void **)&tstr
);
14165 else if(new_pat
->action
->is_a_filter
&& !(strcmp(actvar
, "moind"))){
14166 if(!strcmp(actval
, "1"))
14167 new_pat
->action
->move_only_if_not_deleted
= 1;
14168 else if(!strcmp(actval
, "0"))
14169 new_pat
->action
->move_only_if_not_deleted
= 0;
14171 free_pat(&new_pat
);
14175 else if(new_pat
->action
->is_a_incol
&& !(strcmp(actvar
, "fg"))){
14176 char asciicolor
[256];
14178 if(ascii_colorstr(asciicolor
, actval
) == 0) {
14179 if(!new_pat
->action
->incol
){
14180 new_pat
->action
->incol
= new_color_pair(asciicolor
,NULL
);
14183 snprintf(new_pat
->action
->incol
->fg
,
14184 sizeof(new_pat
->action
->incol
->fg
), "%s", asciicolor
);
14187 else if(new_pat
->action
->is_a_incol
&& !(strcmp(actvar
, "bg"))){
14188 char asciicolor
[256];
14190 if(ascii_colorstr(asciicolor
, actval
) == 0) {
14191 if(!new_pat
->action
->incol
){
14192 new_pat
->action
->incol
= new_color_pair(NULL
, asciicolor
);
14195 snprintf(new_pat
->action
->incol
->bg
,
14196 sizeof(new_pat
->action
->incol
->bg
), "%s", asciicolor
);
14199 else if(new_pat
->action
->is_a_score
&& !(strcmp(actvar
, "scoreval"))){
14200 long scoreval
= (long) atoi(actval
);
14202 if(scoreval
>= SCORE_MIN
&& scoreval
<= SCORE_MAX
)
14203 new_pat
->action
->scoreval
= scoreval
;
14205 else if(new_pat
->action
->is_a_score
&& !(strcmp(actvar
, "scorehdr"))){
14206 HEADER_TOK_S
*hdrtok
;
14208 if((hdrtok
= stringform_to_hdrtok(actval
)) != NULL
)
14209 new_pat
->action
->scorevalhdrtok
= hdrtok
;
14212 free_pat(&new_pat
);
14217 if(new_pat
->action
->is_a_filter
&& new_pat
->action
->kill
&& new_pat
->action
->folder
)
14218 fs_give((void **)&new_pat
->action
->folder
);
14219 else if(new_pat
->action
->is_a_filter
&& new_pat
->action
->kill
== 0 && new_pat
->action
->folder
== 0){
14220 free_pat(&new_pat
);
14221 Tcl_SetResult(interp
, "No folder set for Move", TCL_VOLATILE
);
14226 if(aflags
& RS_RULE_EDIT
)
14227 rv
= edit_pattern(new_pat
, rno
, rflags
);
14228 else if(aflags
& RS_RULE_ADD
)
14229 rv
= add_pattern(new_pat
, rflags
);
14230 else if(aflags
& RS_RULE_DELETE
)
14231 rv
= delete_pattern(rno
, rflags
);
14232 else if(aflags
& RS_RULE_SHUFFUP
)
14233 rv
= shuffle_pattern(rno
, 1, rflags
);
14234 else if(aflags
& RS_RULE_SHUFFDOWN
)
14235 rv
= shuffle_pattern(rno
, -1, rflags
);
14239 return(rv
? TCL_ERROR
: TCL_OK
);
14245 peAEToAddress(AdrBk_Entry
*ae
)
14247 char *list
, *l1
, *l2
;
14250 ADDRESS
*addr
= NULL
;
14252 if(ae
->tag
== List
){
14254 for(l2
= ae
->addr
.list
; *l2
; l2
++)
14255 length
+= (strlen(*l2
) + 1);
14257 list
= (char *) fs_get(length
+ 1);
14260 for(l2
= ae
->addr
.list
; *l2
; l2
++){
14261 if(l1
!= list
&& l1
-list
< length
+1)
14264 strncpy(l1
, *l2
, length
+1-(l1
-list
));
14268 list
[length
] = '\0';
14271 bldto
.arg
.str
= list
;
14272 adr2
= expand_address(bldto
, userdomain
, localdomain
,
14273 loop_detected
, fcc
, did_set
,
14274 lcc
, error
, 1, simple_verify
,
14277 fs_give((void **) &list
);
14279 else if(ae
->tag
== Single
){
14280 if(strucmp(ae
->addr
.addr
, a
->mailbox
)){
14282 bldto
.arg
.str
= ae
->addr
.addr
;
14283 adr2
= expand_address(bldto
, userdomain
,
14284 localdomain
, loop_detected
,
14286 error
, 1, simple_verify
,
14291 * A loop within plain single entry is ignored.
14292 * Set up so later code thinks we expanded.
14294 adr2
= mail_newaddr();
14295 adr2
->mailbox
= cpystr(ae
->addr
.addr
);
14296 adr2
->host
= cpystr(userdomain
);
14297 adr2
->adl
= cpystr(a
->adl
);
14302 * Personal names: If the expanded address has a personal
14303 * name and the address book entry is a list with a fullname,
14304 * tack the full name from the address book on in front.
14305 * This mainly occurs with a distribution list where the
14306 * list has a full name, and the first person in the list also
14309 * This algorithm doesn't work very well if lists are
14310 * included within lists, but it's not clear what would
14313 if(ae
->fullname
&& ae
->fullname
[0]){
14314 if(adr2
->personal
&& adr2
->personal
[0]){
14315 if(ae
->tag
== List
){
14316 /* combine list name and existing name */
14319 if(!simple_verify
){
14321 l
= strlen(adr2
->personal
) + strlen(ae
->fullname
) + 4;
14322 name
= (char *)fs_get((l
+1) * sizeof(char));
14323 snprintf(name
, l
+1, "%s -- %s", ae
->fullname
,
14325 fs_give((void **)&adr2
->personal
);
14326 adr2
->personal
= name
;
14330 /* replace with nickname fullname */
14331 fs_give((void **)&adr2
->personal
);
14332 adr2
->personal
= adrbk_formatname(ae
->fullname
,
14337 if(abe
-p
>tag
!= List
|| !simple_verify
){
14339 fs_give((void **)&adr2
->personal
);
14341 adr2
->personal
= adrbk_formatname(abe
->fullname
,
14353 peAEFcc(AdrBk_Entry
*ae
)
14357 if(ae
->fcc
&& ae
->fcc
[0]){
14359 if(!strcmp(ae
->fcc
, "\"\""))
14362 fcc
= cpystr(ae
->fcc
);
14365 else if(ae
->nickname
&& ae
->nickname
[0] &&
14366 (ps_global
->fcc_rule
== FCC_RULE_NICK
||
14367 ps_global
->fcc_rule
== FCC_RULE_NICK_RECIP
)){
14369 * else if fcc-rule=fcc-by-nickname, use that
14372 fcc
= cpystr(ae
->nickname
);
14383 extern PINEFIELD
*parse_custom_hdrs(char **, CustomType
);
14385 return(parse_custom_hdrs(ps_global
->VAR_CUSTOM_HDRS
, UseAsDef
));
14391 * PEClistCmd - Collection list editing tools
14394 PEClistCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
14396 char *err
= "Unknown PEClist request";
14398 dprint((2, "PEClistCmd"));
14401 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
14404 char *s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
14407 if(objc
== 3){ /* delete */
14408 if(!strcmp(s1
, "delete")){
14409 int cl
, i
, n
, deln
;
14411 CONTEXT_S
*del_ctxt
, *tmp_ctxt
, *new_ctxt
;
14413 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14414 Tcl_SetResult(interp
,
14415 "cledit malformed: first arg must be int",
14419 for(i
= 0, del_ctxt
= ps_global
->context_list
;
14420 del_ctxt
&& i
< cl
; i
++, del_ctxt
= del_ctxt
->next
);
14421 if(!del_ctxt
) return(TCL_ERROR
);
14422 for(n
= 0; del_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14424 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14426 deln
= del_ctxt
->var
.i
;
14427 for(i
= 0; del_ctxt
->var
.v
->current_val
.l
[i
]; i
++){
14429 newl
[i
] = cpystr(del_ctxt
->var
.v
->current_val
.l
[i
]);
14431 newl
[i
-1] = cpystr(del_ctxt
->var
.v
->current_val
.l
[i
]);
14433 n
= set_variable_list(del_ctxt
->var
.v
- ps_global
->vars
,
14434 *newl
? newl
: NULL
, TRUE
, Main
);
14435 free_list_array(&newl
);
14436 set_current_val(del_ctxt
->var
.v
, TRUE
, FALSE
);
14438 Tcl_SetResult(interp
,
14439 "Error saving changes",
14443 for(tmp_ctxt
= del_ctxt
->next
; tmp_ctxt
&& tmp_ctxt
->var
.v
==
14444 del_ctxt
->var
.v
; tmp_ctxt
= tmp_ctxt
->next
)
14446 if((tmp_ctxt
= del_ctxt
->next
) != NULL
)
14447 tmp_ctxt
->prev
= del_ctxt
->prev
;
14448 if((tmp_ctxt
= del_ctxt
->prev
) != NULL
)
14449 tmp_ctxt
->next
= del_ctxt
->next
;
14450 if(!del_ctxt
->prev
&& !del_ctxt
->next
){
14451 new_ctxt
= new_context(del_ctxt
->var
.v
->current_val
.l
[0], NULL
);
14452 ps_global
->context_list
= new_ctxt
;
14453 if(!new_ctxt
->var
.v
)
14454 new_ctxt
->var
= del_ctxt
->var
;
14456 else if(ps_global
->context_list
== del_ctxt
){
14457 ps_global
->context_list
= del_ctxt
->next
;
14458 if(!ps_global
->context_list
)
14459 return TCL_ERROR
; /* this shouldn't happen */
14461 if(ps_global
->context_last
== del_ctxt
)
14462 ps_global
->context_last
= NULL
;
14463 if(ps_global
->context_current
== del_ctxt
){
14464 strncpy(ps_global
->cur_folder
,
14465 ps_global
->mail_stream
->mailbox
,
14466 sizeof(ps_global
->cur_folder
));
14467 ps_global
->cur_folder
[sizeof(ps_global
->cur_folder
)-1] = '\0';
14468 ps_global
->context_current
= ps_global
->context_list
;
14470 del_ctxt
->prev
= NULL
;
14471 del_ctxt
->next
= NULL
;
14472 free_context(&del_ctxt
);
14473 init_inbox_mapping(ps_global
->VAR_INBOX_PATH
,
14474 ps_global
->context_list
);
14477 else if(!strcmp(s1
, "shuffdown")){
14479 CONTEXT_S
*sh_ctxt
, *nsh_ctxt
, *tctxt
;
14480 char **newl
, *tmpch
;
14482 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14483 Tcl_SetResult(interp
,
14484 "cledit malformed: first arg must be int",
14488 for(sh_ctxt
= ps_global
->context_list
, i
= 0;
14489 sh_ctxt
&& i
< cl
; i
++, sh_ctxt
= sh_ctxt
->next
);
14490 if(!sh_ctxt
|| !sh_ctxt
->next
){
14491 Tcl_SetResult(interp
,
14492 "invalid context list number",
14496 if(sh_ctxt
->var
.v
== sh_ctxt
->next
->var
.v
){
14497 shn
= sh_ctxt
->var
.i
;
14498 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14499 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14501 for(i
= 0; sh_ctxt
->var
.v
->current_val
.l
[i
]; i
++){
14503 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
+1]);
14504 else if(i
== shn
+ 1)
14505 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14507 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14509 n
= set_variable_list(sh_ctxt
->var
.v
- ps_global
->vars
,
14511 free_list_array(&newl
);
14512 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14514 Tcl_SetResult(interp
,
14515 "Error saving changes",
14519 nsh_ctxt
= sh_ctxt
->next
;
14524 nsh_ctxt
= sh_ctxt
->next
;
14525 shn
= sh_ctxt
->var
.i
;
14526 tmpch
= cpystr(sh_ctxt
->var
.v
->current_val
.l
[shn
]);
14527 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14529 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14531 for(i
= 0; sh_ctxt
->var
.v
->current_val
.l
[i
+1]; i
++)
14532 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14533 n
= set_variable_list(sh_ctxt
->var
.v
- ps_global
->vars
,
14534 newl
, FALSE
, Main
);
14535 free_list_array(&newl
);
14536 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14537 for(n
= 0; nsh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14539 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14541 newl
[0] = cpystr(nsh_ctxt
->var
.v
->current_val
.l
[0]);
14543 for(i
= 2; nsh_ctxt
->var
.v
->current_val
.l
[i
-1]; i
++)
14544 newl
[i
] = cpystr(nsh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14545 n
= set_variable_list(nsh_ctxt
->var
.v
- ps_global
->vars
,
14547 free_list_array(&newl
);
14548 set_current_val(nsh_ctxt
->var
.v
, TRUE
, FALSE
);
14549 sh_ctxt
->var
.v
= nsh_ctxt
->var
.v
;
14550 sh_ctxt
->var
.i
= 1;
14551 /* this for loop assumes that there are only two variable lists,
14552 * folder-collections and news-collections, a little more will
14553 * have to be done if we want to accomodate for the INHERIT
14554 * option introduced in 4.30.
14556 for(tctxt
= nsh_ctxt
->next
; tctxt
; tctxt
= tctxt
->next
)
14559 if(sh_ctxt
->prev
) sh_ctxt
->prev
->next
= nsh_ctxt
;
14560 nsh_ctxt
->prev
= sh_ctxt
->prev
;
14561 sh_ctxt
->next
= nsh_ctxt
->next
;
14562 nsh_ctxt
->next
= sh_ctxt
;
14563 sh_ctxt
->prev
= nsh_ctxt
;
14564 if(sh_ctxt
->next
) sh_ctxt
->next
->prev
= sh_ctxt
;
14565 if(ps_global
->context_list
== sh_ctxt
)
14566 ps_global
->context_list
= nsh_ctxt
;
14567 init_inbox_mapping(ps_global
->VAR_INBOX_PATH
,
14568 ps_global
->context_list
);
14571 else if(!strcmp(s1
, "shuffup")){
14573 CONTEXT_S
*sh_ctxt
, *psh_ctxt
, *tctxt
;
14574 char **newl
, *tmpch
;
14576 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14577 Tcl_SetResult(interp
,
14578 "cledit malformed: first arg must be int",
14582 for(sh_ctxt
= ps_global
->context_list
, i
= 0;
14583 sh_ctxt
&& i
< cl
; i
++, sh_ctxt
= sh_ctxt
->next
);
14584 if(!sh_ctxt
|| !sh_ctxt
->prev
){
14585 Tcl_SetResult(interp
,
14586 "invalid context list number",
14590 if(sh_ctxt
->var
.v
== sh_ctxt
->prev
->var
.v
){
14591 shn
= sh_ctxt
->var
.i
;
14592 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14593 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14595 for(i
= 0; sh_ctxt
->var
.v
->current_val
.l
[i
]; i
++){
14597 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14598 else if(i
== shn
- 1)
14599 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
+1]);
14601 newl
[i
] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14603 i
= set_variable_list(sh_ctxt
->var
.v
- ps_global
->vars
,
14605 free_list_array(&newl
);
14606 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14608 Tcl_SetResult(interp
,
14609 "Error saving changes",
14613 psh_ctxt
= sh_ctxt
->prev
;
14618 psh_ctxt
= sh_ctxt
->prev
;
14619 shn
= sh_ctxt
->var
.i
;
14620 tmpch
= cpystr(sh_ctxt
->var
.v
->current_val
.l
[shn
]);
14621 for(n
= 0; sh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14623 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14625 for(i
= 1; sh_ctxt
->var
.v
->current_val
.l
[i
]; i
++)
14626 newl
[i
-1] = cpystr(sh_ctxt
->var
.v
->current_val
.l
[i
]);
14627 i
= set_variable_list(sh_ctxt
->var
.v
- ps_global
->vars
,
14628 newl
, FALSE
, Main
);
14629 free_list_array(&newl
);
14631 Tcl_SetResult(interp
,
14632 "Error saving changes",
14636 set_current_val(sh_ctxt
->var
.v
, TRUE
, FALSE
);
14637 for(n
= 0; psh_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14639 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14641 for(i
= 0; psh_ctxt
->var
.v
->current_val
.l
[i
+1]; i
++)
14642 newl
[i
] = cpystr(psh_ctxt
->var
.v
->current_val
.l
[i
]);
14644 newl
[i
] = cpystr(psh_ctxt
->var
.v
->current_val
.l
[i
-1]);
14645 i
= set_variable_list(psh_ctxt
->var
.v
- ps_global
->vars
,
14647 free_list_array(&newl
);
14649 Tcl_SetResult(interp
,
14650 "Error saving changes",
14654 set_current_val(psh_ctxt
->var
.v
, TRUE
, FALSE
);
14655 for(tctxt
= sh_ctxt
->next
; tctxt
; tctxt
= tctxt
->next
)
14657 sh_ctxt
->var
.v
= psh_ctxt
->var
.v
;
14658 sh_ctxt
->var
.i
= n
- 2;
14659 /* There MUST be at least 2 collections in the list */
14662 if(sh_ctxt
->next
) sh_ctxt
->next
->prev
= psh_ctxt
;
14663 psh_ctxt
->next
= sh_ctxt
->next
;
14664 sh_ctxt
->prev
= psh_ctxt
->prev
;
14665 psh_ctxt
->prev
= sh_ctxt
;
14666 sh_ctxt
->next
= psh_ctxt
;
14667 if(sh_ctxt
->prev
) sh_ctxt
->prev
->next
= sh_ctxt
;
14668 if(ps_global
->context_list
== psh_ctxt
)
14669 ps_global
->context_list
= sh_ctxt
;
14670 init_inbox_mapping(ps_global
->VAR_INBOX_PATH
,
14671 ps_global
->context_list
);
14675 else if(objc
== 7){
14676 if(!strcmp(s1
, "edit") || !strcmp(s1
, "add")){
14677 int cl
, quotes_needed
= 0, i
, add
= 0, n
= 0;
14678 char *nick
, *server
, *path
, *view
,
14679 context_buf
[MAILTMPLEN
*4], **newl
;
14680 CONTEXT_S
*new_ctxt
, *tmp_ctxt
;
14682 if(!strcmp(s1
, "add")) add
= 1;
14684 if(Tcl_GetIntFromObj(interp
, objv
[2], &cl
) == TCL_ERROR
){
14685 Tcl_SetResult(interp
,
14686 "cledit malformed: first arg must be int",
14690 if(!(nick
= Tcl_GetStringFromObj(objv
[3], NULL
))){
14691 Tcl_SetResult(interp
,
14696 if(!(server
= Tcl_GetStringFromObj(objv
[4], NULL
))){
14697 Tcl_SetResult(interp
,
14702 if(!(path
= Tcl_GetStringFromObj(objv
[5], NULL
))){
14703 Tcl_SetResult(interp
,
14708 if(!(view
= Tcl_GetStringFromObj(objv
[6], NULL
))){
14709 Tcl_SetResult(interp
,
14714 removing_leading_and_trailing_white_space(nick
);
14715 removing_leading_and_trailing_white_space(server
);
14716 removing_leading_and_trailing_white_space(path
);
14717 removing_leading_and_trailing_white_space(view
);
14718 if(strchr(nick
, ' '))
14720 if(strlen(nick
)+strlen(server
)+strlen(path
)+strlen(view
) >
14721 MAILTMPLEN
* 4 - 20) { /* for good measure */
14722 Tcl_SetResult(interp
,
14728 if(3 + strlen(nick
) + strlen(server
) + strlen(path
) +
14729 strlen(view
) > MAILTMPLEN
+ 4){
14730 Tcl_SetResult(interp
,
14731 "collection fields too long",
14735 snprintf(context_buf
, sizeof(context_buf
), "%s%s%s%s%s%s[%s]", quotes_needed
?
14736 "\"" : "", nick
, quotes_needed
? "\"" : "",
14737 strlen(nick
) ? " " : "",
14738 server
, path
, view
);
14739 new_ctxt
= new_context(context_buf
, NULL
);
14741 for(tmp_ctxt
= ps_global
->context_list
, i
= 0;
14742 tmp_ctxt
&& i
< cl
; i
++, tmp_ctxt
= tmp_ctxt
->next
);
14744 Tcl_SetResult(interp
,
14745 "invalid context list number",
14749 new_ctxt
->next
= tmp_ctxt
->next
;
14750 new_ctxt
->prev
= tmp_ctxt
->prev
;
14751 if(tmp_ctxt
->prev
&& tmp_ctxt
->prev
->next
== tmp_ctxt
)
14752 tmp_ctxt
->prev
->next
= new_ctxt
;
14753 if(tmp_ctxt
->next
&& tmp_ctxt
->next
->prev
== tmp_ctxt
)
14754 tmp_ctxt
->next
->prev
= new_ctxt
;
14755 if(ps_global
->context_list
== tmp_ctxt
)
14756 ps_global
->context_list
= new_ctxt
;
14757 if(ps_global
->context_current
== tmp_ctxt
){
14758 strncpy(ps_global
->cur_folder
,
14759 ps_global
->mail_stream
->mailbox
,
14760 sizeof(ps_global
->cur_folder
));
14761 ps_global
->cur_folder
[sizeof(ps_global
->cur_folder
)-1] = '\0';
14762 ps_global
->context_current
= new_ctxt
;
14764 if(ps_global
->context_last
== tmp_ctxt
)
14765 ps_global
->context_last
= new_ctxt
;
14766 new_ctxt
->var
= tmp_ctxt
->var
;
14767 tmp_ctxt
->next
= tmp_ctxt
->prev
= NULL
;
14768 free_context(&tmp_ctxt
);
14771 for(tmp_ctxt
= ps_global
->context_list
;
14772 tmp_ctxt
->next
; tmp_ctxt
= tmp_ctxt
->next
);
14773 new_ctxt
->prev
= tmp_ctxt
;
14774 tmp_ctxt
->next
= new_ctxt
;
14775 new_ctxt
->var
.v
= tmp_ctxt
->var
.v
;
14776 new_ctxt
->var
.i
= tmp_ctxt
->var
.i
+ 1;
14778 if(!new_ctxt
->var
.v
){
14779 Tcl_SetResult(interp
,
14784 for(n
= 0; new_ctxt
->var
.v
->current_val
.l
[n
]; n
++);
14786 newl
= (char **) fs_get((n
+ 1) * sizeof(char *));
14788 for(n
= 0; new_ctxt
->var
.v
->current_val
.l
[n
]; n
++)
14789 newl
[n
] = (n
== new_ctxt
->var
.i
)
14790 ? cpystr(context_buf
)
14791 : cpystr(new_ctxt
->var
.v
->current_val
.l
[n
]);
14792 if(add
) newl
[n
++] = cpystr(context_buf
);
14793 n
= set_variable_list(new_ctxt
->var
.v
- ps_global
->vars
,
14795 free_list_array(&newl
);
14796 set_current_val(new_ctxt
->var
.v
, TRUE
, FALSE
);
14797 init_inbox_mapping(ps_global
->VAR_INBOX_PATH
,
14798 ps_global
->context_list
);
14800 Tcl_SetResult(interp
,
14801 "Error saving changes",
14811 Tcl_SetResult(interp
, err
, TCL_STATIC
);
14817 * peTakeaddr - Take Address
14820 peTakeaddr(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
14822 TA_S
*talist
= NULL
, *current
, *head
;
14823 Tcl_Obj
*itemObj
, *secObj
= NULL
, *resObj
= NULL
;
14826 mn_set_cur(sp_msgmap(ps_global
->mail_stream
), peMessageNumber(uid
));
14828 if(set_up_takeaddr('a', ps_global
, sp_msgmap(ps_global
->mail_stream
),
14829 &talist
, &anum
, TA_NOPROMPT
, NULL
) < 0
14830 || (talist
== NULL
)){
14831 Tcl_SetResult(interp
,
14832 "Take address failed to set up",
14837 for(head
= talist
; head
->prev
; head
= head
->prev
);
14839 * Return value will be of the form:
14841 * { "line to print",
14842 * {"personal", "mailbox", "host"} # addr
14843 * {"nick", "fullname", "fcc", "comment"} # suggested
14848 * The two list items will be empty if that line is
14849 * just informational.
14851 itemObj
= Tcl_NewListObj(0, NULL
);
14852 for(current
= head
; current
; current
= current
->next
){
14853 if(current
->skip_it
&& !current
->print
) continue;
14854 secObj
= Tcl_NewListObj(0, NULL
);
14855 if(Tcl_ListObjAppendElement(interp
, secObj
,
14856 Tcl_NewStringObj(current
->strvalue
,-1)) != TCL_OK
)
14858 resObj
= Tcl_NewListObj(0, NULL
);
14859 /* append the address information */
14860 if(current
->addr
&& !current
->print
){
14861 if(Tcl_ListObjAppendElement(interp
, resObj
,
14862 Tcl_NewStringObj(current
->addr
->personal
14863 ? current
->addr
->personal
14864 : "", -1)) != TCL_OK
)
14866 if(Tcl_ListObjAppendElement(interp
, resObj
,
14867 Tcl_NewStringObj(current
->addr
->mailbox
14868 ? current
->addr
->mailbox
14869 : "", -1)) != TCL_OK
)
14871 if(Tcl_ListObjAppendElement(interp
, resObj
,
14872 Tcl_NewStringObj(current
->addr
->host
14873 ? current
->addr
->host
14874 : "", -1)) != TCL_OK
)
14877 if(Tcl_ListObjAppendElement(interp
, secObj
,
14880 resObj
= Tcl_NewListObj(0, NULL
);
14881 /* append the suggested possible entries */
14883 && (current
->nickname
|| current
->fullname
14884 || current
->fcc
|| current
->comment
)){
14885 if(Tcl_ListObjAppendElement(interp
, resObj
,
14886 Tcl_NewStringObj(current
->nickname
14887 ? current
->nickname
14888 : "", -1)) != TCL_OK
)
14890 if(Tcl_ListObjAppendElement(interp
, resObj
,
14891 Tcl_NewStringObj(current
->fullname
14892 ? current
->fullname
14893 : "", -1)) != TCL_OK
)
14895 if(Tcl_ListObjAppendElement(interp
, resObj
,
14896 Tcl_NewStringObj(current
->fcc
14898 : "", -1)) != TCL_OK
)
14900 if(Tcl_ListObjAppendElement(interp
, resObj
,
14901 Tcl_NewStringObj(current
->comment
14903 : "", -1)) != TCL_OK
)
14906 if(Tcl_ListObjAppendElement(interp
, secObj
, resObj
) != TCL_OK
)
14908 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
14913 free_talines(&talist
);
14919 * peTakeFrom - Take only From Address
14922 peTakeFrom(Tcl_Interp
*interp
, imapuid_t uid
, int objc
, Tcl_Obj
**objv
)
14931 * Return value will be of the form:
14933 * { "line to print",
14934 * {"personal", "mailbox", "host"} # addr
14935 * {"nick", "fullname", "fcc", "comment"} # suggested
14940 * The two list items will be empty if that line is
14941 * just informational.
14945 if((env
= pine_mail_fetchstructure(ps_global
->mail_stream
,
14946 rawno
= peSequenceNumber(uid
),
14948 /* append the address information */
14949 for(ap
= env
->from
; ap
; ap
= ap
->next
){
14950 objItem
= Tcl_NewListObj(0, NULL
);
14951 /* append EMPTY "line to print" */
14952 if(Tcl_ListObjAppendElement(interp
, objItem
, Tcl_NewStringObj("",-1)) != TCL_OK
)
14955 /* append address info */
14956 peAppListF(interp
, objItem
, "%s%s%s",
14957 ap
->personal
? (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
, SIZEOF_20KBUF
, ap
->personal
) : "",
14958 ap
->mailbox
? ap
->mailbox
: "",
14959 ap
->host
? ap
->host
: "");
14961 /* append suggested info */
14962 peAddSuggestedContactInfo(interp
, objItem
, ap
);
14964 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
), objItem
) != TCL_OK
)
14971 err
= ps_global
->last_error
;
14974 err
= "Invalid UID";
14981 peAddSuggestedContactInfo(Tcl_Interp
*interp
, Tcl_Obj
*lobjp
, ADDRESS
*addr
)
14983 char *nick
= NULL
, *full
= NULL
, *fcc
= NULL
, *comment
= NULL
;
14985 get_contactinfo_from_addr(addr
, &nick
, &full
, &fcc
, &comment
);
14987 peAppListF(interp
, lobjp
, "%s%s%s%s",
14991 comment
? comment
: "");
14994 fs_give((void **) &nick
);
14997 fs_give((void **) &full
);
15000 fs_give((void **) &fcc
);
15003 fs_give((void **) &comment
);
15009 /* * * * * * * * * Status message ring management * * * * * * * * * * * * */
15012 sml_newmsg(int priority
, char *text
)
15014 static long id
= 1;
15017 smp
= (STATMSG_S
*) fs_get(sizeof(STATMSG_S
));
15018 memset(smp
, 0, sizeof(STATMSG_S
));
15020 smp
->posted
= time(0);
15021 smp
->type
= priority
;
15022 smp
->text
= cpystr(text
);
15028 sml_addmsg(int priority
, char *text
)
15030 STATMSG_S
*smp
= sml_newmsg(priority
, text
);
15033 smp
->next
= peStatList
;
15046 char **retstrs
= NULL
, **tmpstrs
;
15048 for(n
= 0, smp
= peStatList
; smp
&& !smp
->seen
; n
++, smp
= smp
->next
)
15051 if(n
== 0) return NULL
;
15052 retstrs
= (char **)fs_get((n
+1)*sizeof(char *));
15053 for(tmpstrs
= retstrs
, smp
= peStatList
; smp
&& !smp
->seen
; smp
= smp
->next
){
15054 *tmpstrs
= smp
->text
;
15066 return(peStatList
? peStatList
->text
: "");
15074 for(smp
= peStatList
; smp
; smp
= smp
->next
)
15080 /* * * * * * * * * LDAP Support Routines * * * * * * * * * * * */
15084 * PELdapCmd - LDAP TCL interface
15087 PELdapCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
15089 #ifndef ENABLE_LDAP
15090 char *err
= "Call to PELdap when LDAP not enabled";
15092 char *err
= "Unknown PELdap request";
15095 dprint((2, "PELdapCmd"));
15098 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15099 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15102 s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
15106 if(!strcmp(s1
, "directories")){
15112 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15113 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15116 if(ps_global
->VAR_LDAP_SERVERS
){
15117 for(i
= 0; ps_global
->VAR_LDAP_SERVERS
[i
] &&
15118 ps_global
->VAR_LDAP_SERVERS
[i
][0]; i
++){
15119 info
= break_up_ldap_server(ps_global
->VAR_LDAP_SERVERS
[i
]);
15120 secObj
= Tcl_NewListObj(0, NULL
);
15121 if(Tcl_ListObjAppendElement(interp
, secObj
,
15122 Tcl_NewStringObj(info
->nick
? info
->nick
15123 : "", -1)) != TCL_OK
)
15125 if(Tcl_ListObjAppendElement(interp
, secObj
,
15126 Tcl_NewStringObj(info
->serv
? info
->serv
15127 : "", -1)) != TCL_OK
)
15131 free_ldap_server_info(&info
);
15132 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15138 Tcl_SetResult(interp
, "", TCL_STATIC
);
15142 else if(!strcmp(s1
, "query")){
15144 char *srchstr
, *filtstr
;
15145 LDAP_CHOOSE_S
*winning_e
= NULL
;
15146 LDAP_SERV_RES_S
*results
= NULL
;
15148 CUSTOM_FILT_S
*filter
= NULL
;
15151 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15152 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15155 if(Tcl_GetIntFromObj(interp
, objv
[2], &dir
) == TCL_ERROR
){
15156 Tcl_SetResult(interp
,
15157 "PELdap results malformed: first arg must be int",
15161 wpldap_global
->query_no
++;
15162 if(wpldap_global
->ldap_search_list
){
15163 wpldap_global
->ldap_search_list
=
15164 free_wpldapres(wpldap_global
->ldap_search_list
);
15166 srchstr
= Tcl_GetStringFromObj(objv
[3], NULL
);
15167 filtstr
= Tcl_GetStringFromObj(objv
[4], NULL
);
15168 if(!srchstr
) return(TCL_ERROR
);
15169 if(!filtstr
) return(TCL_ERROR
);
15171 filter
= (CUSTOM_FILT_S
*)fs_get(sizeof(CUSTOM_FILT_S
));
15172 filter
->filt
= cpystr(filtstr
);
15173 filter
->combine
= 0;
15175 memset(&wp_err
, 0, sizeof(wp_err
));
15176 ldap_lookup_all(srchstr
, dir
, 0, AlwaysDisplay
, filter
, &winning_e
,
15177 &wp_err
, &results
);
15179 fs_give((void **)&filter
->filt
);
15180 fs_give((void **)&filter
);
15182 Tcl_SetResult(interp
, int2string(wpldap_global
->ldap_search_list
15183 ? wpldap_global
->query_no
: 0),
15188 * First argument has always got to be the query number for now.
15189 * Might need to rething that when setting up queries.
15192 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
15193 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15196 if(Tcl_GetIntFromObj(interp
, objv
[2], &qn
) == TCL_ERROR
){
15197 Tcl_SetResult(interp
,
15198 "PELdap results malformed: first arg must be int",
15202 if(qn
!= wpldap_global
->query_no
){
15203 Tcl_SetResult(interp
,
15204 "Query is no longer valid", TCL_VOLATILE
);
15208 if(!strcmp(s1
, "results")){
15209 return(peLdapQueryResults(interp
));
15212 else if(objc
== 4){
15213 if(!strcmp(s1
, "ldapext")){
15215 * Returns a list of the form:
15216 * {"dn" {{attrib {val, ...}}, ...}}
15218 char *whichrec
= Tcl_GetStringFromObj(objv
[3], NULL
);
15219 char *tmpstr
, *tmp
, *tmp2
, *a
;
15220 struct berval
**vals
;
15221 WPLDAPRES_S
*curres
;
15222 LDAP_CHOOSE_S
*winning_e
= NULL
;
15223 LDAP_SERV_RES_S
*trl
;
15224 Tcl_Obj
*secObj
= NULL
, *resObj
= NULL
, *itemObj
;
15227 int i
, j
, whichi
, whichj
;
15229 if(whichrec
== NULL
){
15230 Tcl_SetResult(interp
, "Ldap ldapext error 1", TCL_VOLATILE
);
15233 tmpstr
= cpystr(whichrec
);
15235 for(tmp2
= tmp
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15237 Tcl_SetResult(interp
, "Ldap ldapext error 2", TCL_VOLATILE
);
15241 whichi
= atoi(tmp
);
15244 for(tmp
= tmp2
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15246 Tcl_SetResult(interp
, "Ldap ldapext error 3", TCL_VOLATILE
);
15249 whichj
= atoi(tmp
);
15250 fs_give((void **)&tmpstr
);
15251 for(curres
= wpldap_global
->ldap_search_list
, i
= 0;
15252 i
< whichi
&& curres
; i
++, curres
= curres
->next
);
15254 Tcl_SetResult(interp
, "Ldap ldapext error 4", TCL_VOLATILE
);
15257 for(trl
= curres
->reslist
, j
= 0; trl
; trl
= trl
->next
){
15258 for(e
= ldap_first_entry(trl
->ld
, trl
->res
);
15259 e
!= NULL
&& j
< whichj
;
15260 e
= ldap_next_entry(trl
->ld
, e
), j
++);
15261 if(e
!= NULL
&& j
== whichj
)
15264 if(e
== NULL
|| trl
== NULL
){
15265 Tcl_SetResult(interp
, "Ldap ldapext error 5", TCL_VOLATILE
);
15268 winning_e
= (LDAP_CHOOSE_S
*)fs_get(sizeof(LDAP_CHOOSE_S
));
15269 winning_e
->ld
= trl
->ld
;
15270 winning_e
->selected_entry
= e
;
15271 winning_e
->info_used
= trl
->info_used
;
15272 winning_e
->serv
= trl
->serv
;
15273 a
= ldap_get_dn(winning_e
->ld
, winning_e
->selected_entry
);
15274 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15275 Tcl_NewStringObj(a
? a
: "", -1)) != TCL_OK
)
15278 our_ldap_dn_memfree(a
);
15280 itemObj
= Tcl_NewListObj(0, NULL
);
15281 for(a
= ldap_first_attribute(winning_e
->ld
, winning_e
->selected_entry
, &ber
);
15283 a
= ldap_next_attribute(winning_e
->ld
, winning_e
->selected_entry
, ber
)){
15285 secObj
= Tcl_NewListObj(0, NULL
);
15286 if(Tcl_ListObjAppendElement(interp
, secObj
,
15287 Tcl_NewStringObj(ldap_translate(a
,
15288 winning_e
->info_used
), -1)) != TCL_OK
)
15290 resObj
= Tcl_NewListObj(0, NULL
);
15291 vals
= ldap_get_values_len(winning_e
->ld
, winning_e
->selected_entry
, a
);
15293 for(i
= 0; vals
[i
]; i
++){
15294 if(Tcl_ListObjAppendElement(interp
, resObj
,
15295 Tcl_NewStringObj(vals
[i
]->bv_val
, -1)) != TCL_OK
)
15298 ldap_value_free_len(vals
);
15299 if(Tcl_ListObjAppendElement(interp
, secObj
, resObj
) != TCL_OK
)
15302 if(!strcmp(a
,"objectclass")){
15303 if(Tcl_ListObjAppendElement(interp
, secObj
,
15304 Tcl_NewStringObj("objectclass", -1)) != TCL_OK
)
15307 if(Tcl_ListObjAppendElement(interp
, itemObj
, secObj
) != TCL_OK
)
15310 our_ldap_memfree(a
);
15313 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15314 itemObj
) != TCL_OK
)
15317 fs_give((void **)&winning_e
);
15321 else if(objc
== 6){
15322 if(!strcmp(s1
, "setaddrs")){
15323 char *listset
= Tcl_GetStringFromObj(objv
[3], NULL
);
15324 char *addrstr
= Tcl_GetStringFromObj(objv
[4], NULL
);
15325 char *tmp
, *tmp2
, *tmplistset
, was_char
, *ret_to
,
15327 int **lset
, noreplace
= 0;
15328 ADDRESS
*adr
= NULL
, *curadr
, *prevadr
, *newadr
,
15329 *curnewadr
, *newadrs
;
15330 int curi
, i
, j
, numsrchs
, numset
, setit
;
15331 LDAP_CHOOSE_S
*tres
;
15332 LDAP_SERV_RES_S
*trl
;
15333 WPLDAPRES_S
*curres
;
15338 if(Tcl_GetIntFromObj(interp
, objv
[5], &noreplace
) == TCL_ERROR
){
15339 Tcl_SetResult(interp
,
15340 "PELdap results malformed: first arg must be int",
15344 if(listset
== NULL
|| addrstr
== NULL
) return TCL_ERROR
;
15345 tmpaddrstr
= cpystr(addrstr
);
15348 mail_parameters(NIL
, SET_PARSEPHRASE
, (void *)massage_phrase_addr
);
15349 rfc822_parse_adrlist(&adr
, tmpaddrstr
, "@");
15350 mail_parameters(NIL
, SET_PARSEPHRASE
, NULL
);
15353 tmplistset
= cpystr(listset
);
15354 for(curres
= wpldap_global
->ldap_search_list
, numsrchs
= 0;
15355 curres
; curres
= curres
->next
, numsrchs
++);
15356 lset
= (int **)fs_get((numsrchs
+1)*sizeof(int *));
15357 for(i
= 0; i
< numsrchs
; i
++){
15358 for(tmp
= tmplistset
, numset
= 0; *tmp
;){
15359 for(tmp2
= tmp
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15361 Tcl_SetResult(interp
, "Ldap error 1", TCL_VOLATILE
);
15364 if(atoi(tmp
) == i
) numset
++;
15366 for(tmp
= tmp2
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15367 if(*tmp2
!= ',' && *tmp2
!= '\0'){
15368 Tcl_SetResult(interp
, "Ldap error 2", TCL_VOLATILE
);
15374 lset
[i
] = (int *)fs_get((numset
+1)*sizeof(int));
15375 for(tmp
= tmplistset
, j
= 0; *tmp
&& j
< numset
;){
15377 for(tmp2
= tmp
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15379 Tcl_SetResult(interp
, "Ldap error 3", TCL_VOLATILE
);
15383 if(atoi(tmp
) == i
) setit
++;
15386 for(tmp
= tmp2
; *tmp2
>= '0' && *tmp2
<= '9'; tmp2
++);
15387 if(*tmp2
!= ',' && *tmp2
!= '\0'){
15388 Tcl_SetResult(interp
, "Ldap error 4", TCL_VOLATILE
);
15394 lset
[i
][j
++] = atoi(tmp
);
15403 for(i
= 0, curres
= wpldap_global
->ldap_search_list
;
15404 i
< numsrchs
&& curres
; i
++, curres
= curres
->next
){
15406 for(curadr
= adr
; curadr
; curadr
= curadr
->next
){
15407 if(strcmp(curadr
->mailbox
, curres
->str
) == 0
15408 && curadr
->host
&& *curadr
->host
== '@')
15412 if(!curadr
&& !noreplace
){
15413 Tcl_SetResult(interp
, "Ldap error 5", TCL_VOLATILE
);
15416 newadrs
= newadr
= curnewadr
= NULL
;
15417 for(trl
= curres
->reslist
, j
= 0, curi
= 0; trl
; trl
= trl
->next
){
15418 for(e
= ldap_first_entry(trl
->ld
, trl
->res
);
15419 e
!= NULL
&& lset
[i
][curi
] != -1;
15420 e
= ldap_next_entry(trl
->ld
, e
), j
++){
15421 if(j
== lset
[i
][curi
]){
15422 tres
= (LDAP_CHOOSE_S
*)fs_get(sizeof(LDAP_CHOOSE_S
));
15423 tres
->ld
= trl
->ld
;
15424 tres
->selected_entry
= e
;
15425 tres
->info_used
= trl
->info_used
;
15426 tres
->serv
= trl
->serv
;
15427 newadr
= address_from_ldap(tres
);
15428 fs_give((void **)&tres
);
15430 if(newadrs
== NULL
){
15431 newadrs
= curnewadr
= newadr
;
15434 curnewadr
->next
= newadr
;
15435 curnewadr
= newadr
;
15441 if(newadrs
== NULL
|| curnewadr
== NULL
){
15442 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "No Result Selected for \"%s\"", curadr
->mailbox
? curadr
->mailbox
: "noname");
15443 q_status_message(SM_ORDER
, 0, 3, tmp_20k_buf
);
15444 newadr
= copyaddr(curadr
);
15445 if(newadrs
== NULL
){
15446 newadrs
= curnewadr
= newadr
;
15449 curnewadr
->next
= newadr
;
15450 curnewadr
= newadr
;
15453 curnewadr
->next
= curadr
? curadr
->next
: NULL
;
15454 if(curadr
) curadr
->next
= NULL
;
15458 prevadr
->next
= newadrs
;
15460 mail_free_address(&curadr
);
15464 len
= est_size(adr
);
15465 ret_to
= (char *)fs_get(len
* sizeof(char));
15467 strip_personal_quotes(adr
);
15468 rbuf
.f
= dummy_soutr
;
15472 rbuf
.end
= ret_to
+len
-1;
15473 rfc822_output_address_list(&rbuf
, adr
, 0L, NULL
);
15475 Tcl_SetResult(interp
, ret_to
, TCL_VOLATILE
);
15476 fs_give((void **)&ret_to
);
15477 fs_give((void **)&tmpaddrstr
);
15478 fs_give((void **)&tmplistset
);
15479 for(i
= 0; lset
[i
]; i
++)
15480 fs_give((void **)&lset
[i
]);
15481 fs_give((void **)&lset
);
15483 mail_free_address(&adr
);
15489 #endif /* ENABLE_LDAP */
15490 Tcl_SetResult(interp
, err
, TCL_STATIC
);
15497 peLdapQueryResults(Tcl_Interp
*interp
)
15500 Tcl_Obj
*secObj
= NULL
, *resObj
= NULL
, *itemObj
;
15502 LDAP_SERV_RES_S
*trl
;
15503 /* returned list will be of the form:
15507 * {name, {title, ...}, {unit, ...},
15508 * {org, ...}, {email, ...}},
15515 for(tsl
= wpldap_global
->ldap_search_list
;
15516 tsl
; tsl
= tsl
->next
){
15517 secObj
= Tcl_NewListObj(0, NULL
);
15518 if(Tcl_ListObjAppendElement(interp
, secObj
,
15519 Tcl_NewStringObj(tsl
->str
? tsl
->str
15520 : "", -1)) != TCL_OK
)
15522 resObj
= Tcl_NewListObj(0, NULL
);
15523 for(trl
= tsl
->reslist
; trl
; trl
= trl
->next
){
15524 for(e
= ldap_first_entry(trl
->ld
, trl
->res
);
15526 e
= ldap_next_entry(trl
->ld
, e
)){
15528 struct berval
**cn
, **org
, **unit
, **title
, **mail
, **sn
;
15531 cn
= org
= title
= unit
= mail
= sn
= NULL
;
15533 itemObj
= Tcl_NewListObj(0, NULL
);
15534 peLdapEntryParse(trl
, e
, &cn
, &org
, &unit
, &title
,
15537 if(Tcl_ListObjAppendElement(interp
, itemObj
,
15538 Tcl_NewStringObj(cn
[0]->bv_val
, -1)) != TCL_OK
)
15540 ldap_value_free_len(cn
);
15543 if(Tcl_ListObjAppendElement(interp
, itemObj
,
15544 Tcl_NewStringObj(sn
[0]->bv_val
, -1)) != TCL_OK
)
15546 ldap_value_free_len(sn
);
15549 dn
= ldap_get_dn(trl
->ld
, e
);
15552 our_ldap_dn_memfree(dn
);
15556 if(Tcl_ListObjAppendElement(interp
, itemObj
,
15557 Tcl_NewStringObj(dn
? dn
: "", -1)) != TCL_OK
)
15561 our_ldap_dn_memfree(dn
);
15563 if(peLdapStrlist(interp
, itemObj
, title
) == TCL_ERROR
)
15565 if(peLdapStrlist(interp
, itemObj
, unit
) == TCL_ERROR
)
15567 if(peLdapStrlist(interp
, itemObj
, org
) == TCL_ERROR
)
15569 if(peLdapStrlist(interp
, itemObj
, mail
) == TCL_ERROR
)
15571 if(Tcl_ListObjAppendElement(interp
, resObj
, itemObj
) != TCL_OK
)
15574 ldap_value_free_len(title
);
15576 ldap_value_free_len(unit
);
15578 ldap_value_free_len(org
);
15580 ldap_value_free_len(mail
);
15583 if(Tcl_ListObjAppendElement(interp
, secObj
, resObj
) != TCL_OK
)
15585 if(Tcl_ListObjAppendElement(interp
, Tcl_GetObjResult(interp
),
15593 peLdapStrlist(Tcl_Interp
*interp
, Tcl_Obj
*itemObj
, struct berval
**strl
)
15598 strlObj
= Tcl_NewListObj(0, NULL
);
15600 for(i
= 0; ALPINE_LDAP_usable(strl
, i
); i
++){
15601 if(Tcl_ListObjAppendElement(interp
, strlObj
,
15602 Tcl_NewStringObj(strl
[i
]->bv_val
, -1)) != TCL_OK
)
15606 if(Tcl_ListObjAppendElement(interp
, itemObj
, strlObj
) != TCL_OK
)
15613 init_ldap_pname(struct pine
*ps
)
15615 if(!ps_global
->VAR_PERSONAL_NAME
15616 || ps_global
->VAR_PERSONAL_NAME
[0] == '\0'){
15618 struct variable
*vtmp
;
15620 if(ps
->maildomain
&& *ps
->maildomain
15621 && ps
->VAR_USER_ID
&& *ps
->VAR_USER_ID
){
15622 pname
= peLdapPname(ps
->VAR_USER_ID
, ps
->maildomain
);
15624 vtmp
= &ps
->vars
[V_PERSONAL_NAME
];
15625 if((vtmp
->fixed_val
.p
&& vtmp
->fixed_val
.p
[0] == '\0')
15626 || (vtmp
->is_fixed
&& !vtmp
->fixed_val
.p
)){
15627 if(vtmp
->fixed_val
.p
)
15628 fs_give((void **)&vtmp
->fixed_val
.p
);
15629 vtmp
->fixed_val
.p
= cpystr(pname
);
15632 if(vtmp
->global_val
.p
)
15633 fs_give((void **)&vtmp
->global_val
.p
);
15634 vtmp
->global_val
.p
= cpystr(pname
);
15636 fs_give((void **)&pname
);
15637 set_current_val(vtmp
, FALSE
, FALSE
);
15643 #endif /* ENABLE_LDAP */
15646 * Note: this is taken straight out of pico/composer.c
15648 * strqchr - returns pointer to first non-quote-enclosed occurance of ch in
15649 * the given string. otherwise NULL.
15651 * ch -- the character we're looking for
15652 * q -- q tells us if we start out inside quotes on entry and is set
15653 * correctly on exit.
15654 * m -- max characters we'll check for ch (set to -1 for no check)
15657 strqchr(char *s
, int ch
, int *q
, int m
)
15659 int quoted
= (q
) ? *q
: 0;
15661 for(; s
&& *s
&& m
!= 0; s
++, m
--){
15668 if(!quoted
&& *s
== ch
)
15677 wp_prune_folders(CONTEXT_S
*ctxt
,
15684 Tcl_Interp
*interp
)
15686 Tcl_Obj
*resObj
= NULL
, *secObj
= NULL
;
15687 char path2
[MAXPATH
+1], tmp
[21];
15688 int exists
, month_to_use
;
15689 struct sm_folder
*mail_list
, *sm
;
15691 mail_list
= get_mail_list(ctxt
, fcc
);
15693 for(sm
= mail_list
; sm
!= NULL
&& sm
->name
!= NULL
; sm
++)
15694 if(sm
->month_num
== cur_month
- 1)
15695 break; /* matched a month */
15697 month_to_use
= (sm
== NULL
|| sm
->name
== NULL
) ? cur_month
- 1 : 0;
15699 if(!(month_to_use
== 0 || pr
== PRUNE_NO_AND_ASK
|| pr
== PRUNE_NO_AND_NO
)){
15700 strncpy(path2
, fcc
, sizeof(path2
)-1);
15701 path2
[sizeof(path2
)-1] = '\0';
15702 strncpy(tmp
, month_abbrev((month_to_use
% 12)+1), sizeof(tmp
)-1);
15703 tmp
[sizeof(tmp
)-1] = '\0';
15704 lcase((unsigned char *) tmp
);
15705 snprintf(path2
+ strlen(path2
), sizeof(path2
)-strlen(path2
), "-%.20s-%d", tmp
, month_to_use
/12);
15707 if((exists
= folder_exists(ctxt
, fcc
)) == FEX_ERROR
){
15711 else if(exists
& FEX_ISFILE
){
15712 if(pr
== PRUNE_YES_AND_ASK
|| (pr
== PRUNE_YES_AND_NO
&& !moved_fldrs
)){
15713 prune_move_folder(fcc
, path2
, ctxt
);
15715 resObj
= Tcl_NewListObj(0, NULL
);
15716 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewStringObj(type
, -1));
15717 secObj
= Tcl_NewListObj(0, NULL
);
15718 Tcl_ListObjAppendElement(interp
, secObj
, Tcl_NewStringObj(fcc
, -1));
15719 Tcl_ListObjAppendElement(interp
, secObj
, Tcl_NewStringObj(path2
, -1));
15720 Tcl_ListObjAppendElement(interp
, resObj
, secObj
);
15724 if(pr
== PRUNE_ASK_AND_ASK
|| pr
== PRUNE_YES_AND_ASK
15725 || pr
== PRUNE_NO_AND_ASK
){
15727 if(!resObj
&& sm
&& sm
->name
&& sm
->name
[0] != '\0'){
15728 resObj
= Tcl_NewListObj(0, NULL
);
15729 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewStringObj(type
, -1));
15730 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewListObj(0, NULL
));
15733 secObj
= Tcl_NewListObj(0, NULL
);
15734 for(sm
= mail_list
; sm
!= NULL
&& sm
->name
!= NULL
; sm
++){
15735 if(sm
->name
[0] == '\0') /* can't happen */
15737 Tcl_ListObjAppendElement(interp
, secObj
, Tcl_NewStringObj(sm
->name
, -1));
15740 Tcl_ListObjAppendElement(interp
, resObj
, secObj
);
15742 Tcl_ListObjAppendElement(interp
, resObj
, Tcl_NewListObj(0, NULL
));
15744 free_folder_list(ctxt
);
15746 if((sm
= mail_list
) != NULL
){
15748 fs_give((void **)&(sm
->name
));
15752 fs_give((void **)&mail_list
);
15760 hex_colorstr(char *hexcolor
, char *str
)
15762 char *tstr
, *p
, *p2
, tbuf
[256];
15765 strcpy(hexcolor
, "000000");
15766 tstr
= color_to_asciirgb(str
);
15768 p2
= strindex(p
, ',');
15769 if(p2
== NULL
) return 0;
15770 strncpy(tbuf
, p
, min(50, p2
-p
));
15772 sprintf(hexcolor
, "%2.2x", i
);
15774 p2
= strindex(p
, ',');
15775 if(p2
== NULL
) return 0;
15776 strncpy(tbuf
, p
, min(50, p2
-p
));
15778 sprintf(hexcolor
+2, "%2.2x", i
);
15780 strncpy(tbuf
, p
, 50);
15782 sprintf(hexcolor
+4, "%2.2x", i
);
15790 if(ch
>= '0' && ch
<= '9')
15792 else if (ch
>= 'A' && ch
<= 'F')
15793 return (10 + (ch
- 'A'));
15794 else if (ch
>= 'a' && ch
<= 'f')
15795 return (10 + (ch
- 'a'));
15800 ascii_colorstr(char *acolor
, char *hexcolor
)
15804 if(strlen(hexcolor
) > 6) return 1;
15806 if((hv
= hexval(hexcolor
[0])) == -1) return 1;
15808 if((hv
= hexval(hexcolor
[1])) == -1) return 1;
15810 sprintf(acolor
, "%3.3d,", i
);
15812 if((hv
= hexval(hexcolor
[2])) == -1) return 1;
15814 if((hv
= hexval(hexcolor
[3])) == -1) return 1;
15816 sprintf(acolor
+4, "%3.3d,", i
);
15818 if((hv
= hexval(hexcolor
[4])) == -1) return 1;
15820 if((hv
= hexval(hexcolor
[5])) == -1) return 1;
15822 sprintf(acolor
+8, "%3.3d", i
);
15829 peRandomString(char *b
, int l
, int f
)
15831 static char *kb
= "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
15838 for(j
= 0; j
< ((sizeof(long) * 8) / 5); j
++){
15845 case PRS_LOWER_CASE
:
15846 *s
++ = (char) tolower((unsigned char) kb
[(n
& 0x1F)]);
15849 case PRS_MIXED_CASE
:
15851 *s
++ = (char) tolower((unsigned char) kb
[(n
& 0x1F)]);
15856 *s
++ = kb
[(n
& 0x1F)];
15867 peAppendMsg(MAILSTREAM
*stream
, void *data
, char **flags
, char **date
, STRING
**message
)
15869 char *t
,*t1
,tmp
[MAILTMPLEN
];
15872 APPEND_PKG
*ap
= (APPEND_PKG
*) data
;
15873 *flags
= *date
= NIL
; /* assume no flags or date */
15874 if (ap
->flags
) fs_give ((void **) &ap
->flags
);
15875 if (ap
->date
) fs_give ((void **) &ap
->date
);
15876 mail_gc (ap
->stream
,GC_TEXTS
);
15877 if (++ap
->msgno
<= ap
->msgmax
) {
15878 /* initialize flag string */
15879 memset (t
= tmp
,0,MAILTMPLEN
);
15880 /* output system flags */
15881 if ((elt
= mail_elt (ap
->stream
,ap
->msgno
))->seen
) {strncat (t
," \\Seen", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15882 if (elt
->deleted
) {strncat (t
," \\Deleted", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15883 if (elt
->flagged
) {strncat (t
," \\Flagged", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15884 if (elt
->answered
) {strncat (t
," \\Answered", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15885 if (elt
->draft
) {strncat (t
," \\Draft", sizeof(tmp
)-(t
-tmp
)-1); tmp
[sizeof(tmp
)-1] = '\0';}
15886 if ((u
= elt
->user_flags
) != 0L) do /* any user flags? */
15887 if ((MAILTMPLEN
- ((t
+= strlen (t
)) - tmp
)) > (long)
15889 (t1
= ap
->stream
->user_flags
[find_rightmost_bit (&u
)]))) {
15890 if(t
-tmp
< sizeof(tmp
))
15891 *t
++ = ' '; /* space delimiter */
15892 strncpy (t
,t1
,sizeof(tmp
)-(t
-tmp
)); /* copy the user flag */
15894 while (u
); /* until no more user flags */
15895 tmp
[sizeof(tmp
)-1] = '\0';
15896 *flags
= ap
->flags
= cpystr (tmp
+ 1);
15897 *date
= ap
->date
= cpystr (mail_date (tmp
,elt
));
15898 *message
= ap
->message
; /* message stringstruct */
15899 INIT (ap
->message
,mstring
,(void *) ap
,elt
->rfc822_size
);
15901 else *message
= NIL
; /* all done */
15906 /* Initialize file string structure for file stringstruct
15907 * Accepts: string structure
15908 * pointer to message data structure
15913 ms_init(STRING
*s
, void *data
, unsigned long size
)
15915 APPEND_PKG
*md
= (APPEND_PKG
*) data
;
15916 s
->data
= data
; /* note stream/msgno and header length */
15917 mail_fetchheader_full (md
->stream
,md
->msgno
,NIL
,&s
->data1
,FT_PREFETCHTEXT
);
15918 mail_fetchtext_full (md
->stream
,md
->msgno
,&s
->size
,NIL
);
15919 s
->size
+= s
->data1
; /* header + body size */
15924 /* Get next character from file stringstruct
15925 * Accepts: string structure
15926 * Returns: character, string structure chunk refreshed
15931 char c
= *s
->curpos
++; /* get next byte */
15932 SETPOS (s
,GETPOS (s
)); /* move to next chunk */
15933 return c
; /* return the byte */
15937 /* Set string pointer position for file stringstruct
15938 * Accepts: string structure
15942 ms_setpos(STRING
*s
, unsigned long i
)
15944 APPEND_PKG
*md
= (APPEND_PKG
*) s
->data
;
15945 if (i
< s
->data1
) { /* want header? */
15946 s
->chunk
= mail_fetchheader (md
->stream
,md
->msgno
);
15947 s
->chunksize
= s
->data1
; /* header length */
15948 s
->offset
= 0; /* offset is start of message */
15950 else if (i
< s
->size
) { /* want body */
15951 s
->chunk
= mail_fetchtext (md
->stream
,md
->msgno
);
15952 s
->chunksize
= s
->size
- s
->data1
;
15953 s
->offset
= s
->data1
; /* offset is end of header */
15955 else { /* off end of message */
15956 s
->chunk
= NIL
; /* make sure that we crack on this then */
15957 s
->chunksize
= 1; /* make sure SNX cracks the right way... */
15960 /* initial position and size */
15961 s
->curpos
= s
->chunk
+ (i
-= s
->offset
);
15962 s
->cursize
= s
->chunksize
- i
;
15967 remote_pinerc_failure(void)
15969 snprintf(ps_global
->last_error
, sizeof(ps_global
->last_error
), "%s",
15970 ps_global
->c_client_error
[0]
15971 ? ps_global
->c_client_error
15972 : _("Unable to read remote configuration"));
15978 peWebAlpinePrefix(void)
15984 void peNewMailAnnounce(MAILSTREAM
*stream
, long n
, long t_nm_count
){
15985 char subject
[MAILTMPLEN
+1], subjtext
[MAILTMPLEN
+1], from
[MAILTMPLEN
+1],
15986 *folder
= NULL
, intro
[MAILTMPLEN
+1];
15988 ENVELOPE
*e
= NULL
;
15991 if(n
&& (resObj
= Tcl_NewListObj(0, NULL
)) != NULL
){
15993 Tcl_ListObjAppendElement(peED
.interp
, resObj
, Tcl_NewLongObj(number
= sp_mail_since_cmd(stream
)));
15994 Tcl_ListObjAppendElement(peED
.interp
, resObj
, Tcl_NewLongObj(mail_uid(stream
, n
)));
15997 e
= pine_mail_fetchstructure(stream
, n
, NULL
);
15999 if(sp_flagged(stream
, SP_INBOX
))
16002 folder
= STREAMNAME(stream
);
16003 if(folder
[0] == '?' && folder
[1] == '\0')
16008 format_new_mail_msg(folder
, number
, e
, intro
, from
, subject
, subjtext
, sizeof(intro
));
16010 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
16011 "%s%s%s%.80s%.80s", intro
,
16012 from
? ((number
> 1L) ? " Most recent f" : " F") : "",
16013 from
? "rom " : "",
16017 Tcl_ListObjAppendElement(peED
.interp
, resObj
, Tcl_NewStringObj(tmp_20k_buf
,-1));
16019 Tcl_ListObjAppendElement(peED
.interp
, Tcl_GetObjResult(peED
.interp
), resObj
);
16024 /* * * * * * * * * RSS 2.0 Support Routines * * * * * * * * * * * */
16027 * PERssCmd - RSS TCL interface
16030 PERssCmd(ClientData clientData
, Tcl_Interp
*interp
, int objc
, Tcl_Obj
*CONST objv
[])
16034 dprint((2, "PERssCmd"));
16037 Tcl_WrongNumArgs(interp
, 1, objv
, "cmd ?args?");
16040 s1
= Tcl_GetStringFromObj(objv
[1], NULL
);
16043 if(!strcmp(s1
, "news")){
16044 return(peRssReturnFeed(interp
, "news", ps_global
->VAR_RSS_NEWS
));
16046 else if(!strcmp(s1
, "weather")){
16047 return(peRssReturnFeed(interp
, "weather", ps_global
->VAR_RSS_WEATHER
));
16051 Tcl_SetResult(interp
, "Unknown PERss command", TCL_STATIC
);
16056 * peRssReturnFeed - fetch feed contents and package Tcl response
16059 peRssReturnFeed(Tcl_Interp
*interp
, char *type
, char *link
)
16062 char *errstr
= "UNKNOWN";
16065 ps_global
->c_client_error
[0] = '\0';
16067 if((feed
= peRssFeed(interp
, type
, link
)) != NULL
)
16068 return(peRssPackageFeed(interp
, feed
));
16070 if(ps_global
->mm_log_error
)
16071 errstr
= ps_global
->c_client_error
;
16074 errstr
= "missing setting";
16076 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s feed fail: %s", type
, errstr
);
16077 Tcl_SetResult(interp
, tmp_20k_buf
, TCL_VOLATILE
);
16082 * peRssPackageFeed - build a list of feed item elements
16084 * LIST ORDER: {title} {link} {description} {image}
16087 peRssPackageFeed(Tcl_Interp
*interp
, RSS_FEED_S
*feed
)
16091 for(item
= feed
->items
; item
; item
= item
->next
)
16092 if(peAppListF(interp
, Tcl_GetObjResult(interp
), "%s %s %s %s",
16093 (item
->title
&& *item
->title
)? item
->title
: "Feed Provided No Title",
16094 item
->link
? item
->link
: "",
16095 item
->description
? item
->description
: "",
16096 feed
->image
? feed
->image
: "") != TCL_OK
)
16104 * peRssFeed - return cached feed struct or fetch a new one
16107 peRssFeed(Tcl_Interp
*interp
, char *type
, char *link
)
16109 int i
, cache_l
, cp_ref
;
16110 time_t now
= time(0);
16111 RSS_FEED_S
*feed
= NULL
;
16112 RSS_CACHE_S
*cache
, *cp
;
16113 static RSS_CACHE_S news_cache
[RSS_NEWS_CACHE_SIZE
], weather_cache
[RSS_WEATHER_CACHE_SIZE
];
16115 if(!strucmp(type
,"news")){
16116 cache
= &news_cache
[0];
16117 cache_l
= RSS_NEWS_CACHE_SIZE
;
16120 cache
= &weather_cache
[0];
16121 cache_l
= RSS_WEATHER_CACHE_SIZE
;
16124 /* search/purge cache */
16125 for(i
= 0; i
< cache_l
; i
++)
16127 if(now
> cache
[i
].stale
){
16128 peRssClearCacheEntry(&cache
[i
]);
16130 else if(!strcmp(link
, cache
[i
].link
)){
16131 cache
[i
].referenced
++;
16132 return(cache
[i
].feed
); /* HIT! */
16136 if((feed
= peRssFetch(interp
, link
)) != NULL
){
16137 /* find cache slot, and insert feed into cache */
16138 for(i
= 0, cp_ref
= 0; i
< cache_l
; i
++)
16139 if(!cache
[i
].feed
){
16143 else if(cache
[i
].referenced
>= cp_ref
)
16147 cp
= &cache
[0]; /* failsafe */
16149 peRssClearCacheEntry(cp
); /* make sure */
16151 cp
->link
= cpystr(link
);
16153 cp
->referenced
= 0;
16154 cp
->stale
= now
+ (((feed
->ttl
> 0) ? feed
->ttl
: 60) * 60);
16161 * peRssFetch - follow the provided link an return the resulting struct
16164 peRssFetch(Tcl_Interp
*interp
, char *link
)
16166 char *scheme
= NULL
, *loc
= NULL
, *path
= NULL
, *parms
= NULL
, *query
= NULL
, *frag
= NULL
;
16167 char *buffer
= NULL
, *bp
, *p
, *q
;
16169 unsigned long port
= 0L, buffer_len
= 0L;
16170 time_t theirdate
= 0;
16171 STORE_S
*feed_so
= NULL
;
16172 TCPSTREAM
*tcp_stream
;
16176 rfc1808_tokens(link
, &scheme
, &loc
, &path
, &parms
, &query
, &frag
);
16177 if(scheme
&& loc
&& path
){
16178 if((p
= strchr(loc
,':')) != NULL
){
16180 while(*p
&& isdigit((unsigned char) *p
))
16181 port
= ((port
* 10) + (*p
++ - '0'));
16184 Tcl_SetResult(interp
, "Bad RSS port number", TCL_STATIC
);
16185 peRssComponentFree(&scheme
,&loc
,&path
,&parms
,&query
,&frag
);
16190 if(scheme
&& !strucmp(scheme
, "feed")){
16191 fs_give((void **) &scheme
);
16192 scheme
= cpystr("http");
16195 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long) 5);
16196 tcp_stream
= tcp_open (loc
, scheme
, port
| NET_NOOPENTIMEOUT
);
16197 mail_parameters(NULL
, SET_OPENTIMEOUT
, (void *)(long) 30);
16199 if(tcp_stream
!= NULL
){
16202 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "GET /%s%s%s%s%s HTTP/1.1\r\nHost: %s\r\nAccept: application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nUser-Agent: Web-Alpine/%s (%s %s)\r\n\r\n",
16203 path
, parms
? ":" : "", parms
? parms
: "",
16204 query
? "?" : "", query
? query
: "", loc
,
16205 ALPINE_VERSION
, SYSTYPE
, get_alpine_revision_string(rev
, sizeof(rev
)));
16207 mail_parameters(NULL
, SET_WRITETIMEOUT
, (void *)(long) 5);
16208 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long) 5);
16210 if(tcp_sout(tcp_stream
, tmp_20k_buf
, strlen(tmp_20k_buf
))){
16211 int ok
= 0, chunked
= FALSE
;
16213 while((p
= tcp_getline(tcp_stream
)) != NULL
){
16216 if(strucmp(p
,"HTTP/1.1 200 OK")){
16217 fs_give((void **) &p
);
16221 else if(*p
== '\0'){ /* first blank line, start of body */
16222 if(buffer
|| feed_so
){
16223 fs_give((void **) &p
);
16228 buffer
= fs_get(buffer_len
+ 16);
16229 if(!tcp_getbuffer(tcp_stream
, buffer_len
, buffer
))
16230 fs_give((void **) &buffer
);
16232 fs_give((void **) &p
);
16235 else if((feed_so
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) == NULL
){
16236 fs_give((void **) &p
);
16240 else if(feed_so
){ /* collect body */
16242 int chunk_len
= 0, gotbuf
;
16244 /* first line is chunk size in hex */
16245 for(q
= p
; *q
&& isxdigit((unsigned char) *q
); q
++)
16246 chunk_len
= (chunk_len
* 16) + XDIGIT2C(*q
);
16248 if(chunk_len
> 0){ /* collect chunk */
16249 char *tbuf
= fs_get(chunk_len
+ 16);
16250 gotbuf
= tcp_getbuffer(tcp_stream
, chunk_len
, tbuf
);
16252 so_nputs(feed_so
, tbuf
, chunk_len
);
16254 fs_give((void **) &tbuf
);
16257 fs_give((void **) &p
);
16262 /* collect trailing CRLF */
16263 gotbuf
= ((q
= tcp_getline(tcp_stream
)) != NULL
&& *q
== '\0');
16265 fs_give((void **) &q
);
16267 if(chunk_len
== 0 || !gotbuf
){
16268 fs_give((void **) &p
);
16273 so_puts(feed_so
, p
);
16275 else{ /* in header, grok fields */
16276 if((q
= strchr(p
,':')) != NULL
){
16280 while(isspace((unsigned char ) *q
))
16283 /* content-length */
16284 if(l
== 4 && !strucmp(p
, "date")){
16285 theirdate
= date_to_local_time_t(q
);
16287 else if(l
== 7 && !strucmp(p
, "expires")){
16288 time_t expires
= date_to_local_time_t(q
) - ((theirdate
> 0) ? theirdate
: time(0));
16290 if(expires
> 0 && expires
< (8 * 60 * 60))
16293 else if(l
== 12 && !strucmp(p
, "content-type")
16294 && struncmp(q
,"text/xml", 8)
16295 && struncmp(q
,"application/xhtml+xml", 21)
16296 && struncmp(q
,"application/rss+xml", 19)
16297 && struncmp(q
,"application/xml", 15)){
16298 fs_give((void **) &p
);
16301 else if(l
== 13 && !strucmp(p
, "cache-control")){
16302 if(!struncmp(q
,"max-age=",8)){
16305 for(q
+= 8; *q
&& isdigit((unsigned char) *q
); q
++)
16306 secs
= ((secs
* 10) + (*q
- '0'));
16312 else if(l
== 14 && !strucmp(p
,"content-length")){
16313 while(*q
&& isdigit((unsigned char) *q
))
16314 buffer_len
= ((buffer_len
* 10) + (*q
++ - '0'));
16317 fs_give((void **) &p
);
16321 else if(l
== 17 && !strucmp(p
, "transfer-encoding")){
16322 if(!struncmp(q
,"chunked", 7)){
16325 else{ /* unknown encoding */
16326 fs_give((void **) &p
);
16333 fs_give((void **) &p
);
16337 Tcl_SetResult(interp
, "RSS send failure", TCL_STATIC
);
16338 peRssComponentFree(&scheme
,&loc
,&path
,&parms
,&query
,&frag
);
16341 tcp_close(tcp_stream
);
16342 mail_parameters(NULL
, SET_READTIMEOUT
, (void *)(long) 60);
16343 mail_parameters(NULL
, SET_WRITETIMEOUT
, (void *)(long) 60);
16344 peRssComponentFree(&scheme
,&loc
,&path
,&parms
,&query
,&frag
);
16347 buffer
= (char *) so_text(feed_so
);
16348 buffer_len
= (int) so_tell(feed_so
);
16351 if(buffer
&& buffer_len
){
16357 /* grok response */
16358 bucket
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
16359 gf_set_readc(&gc
, buffer
, buffer_len
, CharStar
, 0);
16360 gf_set_so_writec(&pc
, bucket
);
16362 gf_link_filter(gf_html2plain
, gf_html2plain_rss_opt(&feed
,0));
16363 if((err
= gf_pipe(gc
, pc
)) != NULL
){
16364 gf_html2plain_rss_free(&feed
);
16365 Tcl_SetResult(interp
, "RSS connection failure", TCL_STATIC
);
16373 fs_give((void **) &buffer
);
16378 Tcl_SetResult(interp
, "RSS response error", TCL_STATIC
);
16381 Tcl_SetResult(interp
, "RSS connection failure", TCL_STATIC
);
16384 Tcl_SetResult(interp
, "RSS feed missing scheme", TCL_STATIC
);
16387 Tcl_SetResult(interp
, "No RSS Feed Defined", TCL_STATIC
);
16394 peRssComponentFree(char **scheme
,char **loc
,char **path
,char **parms
,char **query
,char **frag
)
16396 if(scheme
) fs_give((void **) scheme
);
16397 if(loc
) fs_give((void **) loc
);
16398 if(path
) fs_give((void **) path
);
16399 if(parms
) fs_give((void **) parms
);
16400 if(query
) fs_give((void **) query
);
16401 if(frag
) fs_give((void **) frag
);
16405 peRssClearCacheEntry(RSS_CACHE_S
*entry
)
16409 fs_give((void **) &entry
->link
);
16411 gf_html2plain_rss_free(&entry
->feed
);
16412 memset(entry
, 0, sizeof(RSS_CACHE_S
));