* clear out some warnings by gcc 9.3.1.
[alpine.git] / web / src / alpined.d / alpined.c
blob7865863fc15770ccd80bf3c1cedde43495da63a2
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: alpined.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $";
3 #endif
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
20 UNIX domain socket.
21 ======================================================================== */
24 #include <system.h>
25 #include <general.h>
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"
86 #include "alpined.h"
87 #include "color.h"
88 #include "imap.h"
89 #include "ldap.h"
90 #include "debug.h"
91 #include "stubs.h"
93 #include <tcl.h>
97 * Fake screen dimension for word wrap and such
99 #define FAKE_SCREEN_WIDTH 80
100 #define FAKE_SCREEN_LENGTH 24
103 * Arbitrary minimum display width (in characters)
105 #define MIN_SCREEN_COLS 20
109 * Maximum number of lines allowed in signatures
111 #define SIG_MAX_LINES 24
112 #define SIG_MAX_COLS 1024
116 * Number of seconds we'll wait before we assume the client has wondered
117 * on to more interesting content
119 #define PE_INPUT_TIMEOUT 1800
123 * Posting error length max
125 #define WP_MAX_POST_ERROR 128
129 * AUTH Response Tokens
131 #define AUTH_EMPTY_STRING "NOPASSWD"
132 #define AUTH_FAILURE_STRING "BADPASSWD"
135 * CERT Response Tokens
137 #define CERT_QUERY_STRING "CERTQUERY"
138 #define CERT_FAILURE_STRING "CERTFAIL"
142 * Charset used within alpined and to communicate with alpined
143 * Note: posting-charset still respected
145 #define WP_INTERNAL_CHARSET "UTF-8"
149 * Globals referenced throughout pine...
151 struct pine *wps_global; /* THE global variable! */
155 * More global state
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];
170 char *peSocketName;
172 char **peTSig;
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 {
188 time_t posted;
189 unsigned type:3;
190 unsigned seen:1;
191 long id;
192 char *text;
193 struct _status_msg *next;
194 } STATMSG_S;
196 static STATMSG_S *peStatList;
198 typedef struct _composer_attachment {
199 unsigned file:1;
200 unsigned body:1;
201 char *id;
202 union {
203 struct {
204 char *local;
205 char *remote;
206 char *type;
207 char *subtype;
208 char *description;
209 long size;
210 } f;
211 struct {
212 BODY *body;
213 } b;
214 struct {
215 long msgno;
216 char *part;
217 } msg;
218 } l;
219 struct _composer_attachment *next;
220 } COMPATT_S;
222 static COMPATT_S *peCompAttach;
225 * Holds data passed
227 typedef struct _msg_data {
228 ENVELOPE *outgoing;
229 METAENV *metaenv;
230 PINEFIELD *custom;
231 STORE_S *msgtext;
232 STRLIST_S *attach;
233 char *fcc;
234 int fcc_colid;
235 int postop_fcc_no_attach;
236 char *charset;
237 char *priority;
238 int (*postfunc)(METAENV *, BODY *, char *, CONTEXT_S **, char *);
239 unsigned flowed:1;
240 unsigned html:1;
241 unsigned qualified_addrs:1;
242 } MSG_COL_S;
246 * locally global structure to keep track of various bits of state
247 * needed to collect filtered output
249 static struct _embedded_data {
250 Tcl_Interp *interp;
251 Tcl_Obj *obj;
252 STORE_S *store;
253 long uid;
254 HANDLE_S *handles;
255 char inhandle;
256 ENVELOPE *env;
257 BODY *body;
258 struct {
259 char fg[7];
260 char bg[7];
261 char fgdef[7];
262 char bgdef[7];
263 } color;
264 } peED;
268 * RSS stream cache
270 typedef struct _rss_cache_s {
271 char *link;
272 time_t stale;
273 int referenced;
274 RSS_FEED_S *feed;
275 } RSS_CACHE_S;
277 #define RSS_NEWS_CACHE_SIZE 1
278 #define RSS_WEATHER_CACHE_SIZE 1
281 #ifdef ENABLE_LDAP
282 WPLDAP_S *wpldap_global;
283 #endif
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...
330 ----*/
331 char wtmp_20k_buf[20480];
336 /* Internal prototypes */
337 void peReturn(int, char *, const char *);
338 int peWrite(int, char *);
339 char *peCreateUserContext(Tcl_Interp *, char *, char *, char *);
340 void peDestroyUserContext(struct pine **);
341 char *peLoadConfig(struct pine *);
342 int peCreateStream(Tcl_Interp *, CONTEXT_S *, char *, int);
343 void peDestroyStream(struct pine *);
344 void pePrepareForAuthException(void);
345 char *peAuthException(void);
346 void peInitVars(struct pine *);
347 int peSelect(Tcl_Interp *, int, Tcl_Obj **, int);
348 int peSelectNumber(Tcl_Interp *, int, Tcl_Obj **, int);
349 int peSelectDate(Tcl_Interp *, int, Tcl_Obj **, int);
350 int peSelectText(Tcl_Interp *, int, Tcl_Obj **, int);
351 int peSelectStatus(Tcl_Interp *, int, Tcl_Obj **, int);
352 char *peSelValTense(Tcl_Obj *);
353 char *peSelValYear(Tcl_Obj *);
354 char *peSelValMonth(Tcl_Obj *);
355 char *peSelValDay(Tcl_Obj *);
356 int peSelValCase(Tcl_Obj *);
357 int peSelValField(Tcl_Obj *);
358 int peSelValFlag(Tcl_Obj *);
359 int peSelected(Tcl_Interp *, int, Tcl_Obj **, int);
360 int peSelectError(Tcl_Interp *, char *);
361 int peApply(Tcl_Interp *, int, Tcl_Obj **);
362 char *peApplyFlag(MAILSTREAM *, MSGNO_S *, char, int, long *);
363 int peApplyError(Tcl_Interp *, char *);
364 int peIndexFormat(Tcl_Interp *);
365 int peAppendIndexParts(Tcl_Interp *, imapuid_t, Tcl_Obj *, int *);
366 int peAppendIndexColor(Tcl_Interp *, imapuid_t, Tcl_Obj *, int *);
367 int peMessageStatusBits(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
368 char *peMsgStatBitString(struct pine *, MAILSTREAM *, MSGNO_S *, long, long, long, int *);
369 Tcl_Obj *peMsgStatNameList(Tcl_Interp *, struct pine *, MAILSTREAM *, MSGNO_S *, long, long, long, int *);
370 int peNewMailResult(Tcl_Interp *);
371 int peMessageSize(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
372 int peMessageDate(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
373 int peMessageSubject(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
374 int peMessageFromAddr(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
375 int peMessageToAddr(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
376 int peMessageCcAddr(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
377 int peMessageField(Tcl_Interp *, imapuid_t, char *);
378 int peMessageStatus(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
379 int peMessageCharset(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
380 int peMessageBounce(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
381 int peMessageSpamNotice(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
382 char *peSendSpamReport(long, char *, char *, char *);
383 int peMsgnoFromUID(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
384 int peMessageText(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
385 int peMessageHeader(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
386 void peFormatEnvelope(MAILSTREAM *, long, char *, ENVELOPE *, gf_io_t, long, char *, int);
387 void peFormatEnvelopeAddress(MAILSTREAM *, long, char *, char *, ADDRESS *, int, char *, gf_io_t);
388 void peFormatEnvelopeNewsgroups(char *, char *, int, gf_io_t);
389 void peFormatEnvelopeText(char *, char *);
390 int peMessageAttachments(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
391 int peMessageBody(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
392 int peMessagePartFromCID(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
393 int peLocateBodyByCID(char *, char *, BODY *);
394 char *peColorStr(char *, char *);
395 int peInterpWritec(int);
396 int peInterpFlush(void);
397 int peNullWritec(int);
398 void peGetMimeTyping(BODY *, Tcl_Obj **, Tcl_Obj **, Tcl_Obj **, Tcl_Obj **);
399 int peGetFlag(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
400 int peIsFlagged(MAILSTREAM *, imapuid_t, char *);
401 int peSetFlag(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
402 int peMsgSelect(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
403 int peReplyHeaders(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
404 int peAppListF(Tcl_Interp *, Tcl_Obj *, char *, ...);
405 void pePatAppendID(Tcl_Interp *, Tcl_Obj *, PAT_S *);
406 void pePatAppendPattern(Tcl_Interp *, Tcl_Obj *, PAT_S *);
407 char *pePatStatStr(int);
408 int peReplyText(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
409 int peSoStrToList(Tcl_Interp *, Tcl_Obj *, STORE_S *);
410 int peForwardHeaders(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
411 int peForwardText(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
412 int peDetach(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
413 int peAttachInfo(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
414 int peSaveDefault(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
415 int peSaveWork(Tcl_Interp *, imapuid_t, int, Tcl_Obj **, long);
416 int peSave(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
417 int peCopy(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
418 int peMove(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
419 int peGotoDefault(Tcl_Interp *, imapuid_t, Tcl_Obj **);
420 int peTakeaddr(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
421 int peTakeFrom(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
422 int peAddSuggestedContactInfo(Tcl_Interp *, Tcl_Obj *, ADDRESS *);
423 int peReplyQuote(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
424 long peMessageNumber(imapuid_t);
425 long peSequenceNumber(imapuid_t);
426 int peMsgCollector(Tcl_Interp *, int, Tcl_Obj **,
427 int (*)(METAENV *, BODY *, char *, CONTEXT_S **, char *), long);
428 int peMsgCollected(Tcl_Interp *, MSG_COL_S *, char *, long);
429 void peMsgSetParm(PARAMETER **, char *, char *);
430 Tcl_Obj *peMsgAttachCollector(Tcl_Interp *, BODY *);
431 int peFccAppend(Tcl_Interp *, Tcl_Obj *, char *, int);
432 int peDoPost(METAENV *, BODY *, char *, CONTEXT_S **, char *);
433 int peDoPostpone(METAENV *, BODY *, char *, CONTEXT_S **, char *);
434 int peWriteSig (Tcl_Interp *, char *, Tcl_Obj **);
435 int peInitAddrbooks(Tcl_Interp *, int);
436 int peRuleStatVal(char *, int *);
437 int peRuleSet(Tcl_Interp *, Tcl_Obj **);
438 int peAppendCurrentSort(Tcl_Interp *interp);
439 int peAppendDefaultSort(Tcl_Interp *interp);
440 #if 0
441 ADDRESS *peAEToAddress(AdrBk_Entry *);
442 char *peAEFcc(AdrBk_Entry *);
443 #endif
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);
450 void sml_seen(void);
451 #ifdef ENABLE_LDAP
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 *);
460 int hexval(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[]);
518 /* Append package */
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 */
526 } APPEND_PKG;
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
543 ----*/
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;
551 Tcl_Interp *interp;
552 #if PUBCOOKIE
553 extern AUTHENTICATOR auth_gss_proxy;
554 #endif
556 srandom(getpid() + time(0));
558 /*----------------------------------------------------------------------
559 Initialize c-client
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
566 * the debug level
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 */
573 #if PUBCOOKIE
574 auth_link (&auth_gss_proxy); /* pubcoookie proxy authenticator */
575 #endif
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 */
579 ssl_onceonlyinit ();
580 mail_parameters (NIL,SET_DISABLEPLAINTEXT,(void *) 2);
582 #if PUBCOOKIE
583 /* if REMOTE_USER set, use it as username */
584 if(buf = getenv("REMOTE_USER"))
585 env_init(buf, "/tmp");
586 #endif
588 if(!mail_parameters(NULL, DISABLE_DRIVER, "unix")){
589 fprintf(stderr, "Can't disable unix driver");
590 exit(1);
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 /*----------------------------------------------------------------------
615 Parse arguments
616 ----------------------------------------------------------------------*/
617 debug = 0;
618 for(argerr = 0; !argerr && ((n = getopt(argc,argv,"d")) != -1); ) {
619 switch(n) {
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]);
628 exit(1);
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')
639 sname[l] = '\0';
641 if((s = socket(AF_UNIX, SOCK_STREAM, 0)) != -1){
643 name.sun_family = AF_UNIX;
644 strcpy(name.sun_path, peSocketName = sname);
645 l = sizeof(name);
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.
655 if(debug < 10){
656 switch(fork()){
657 case -1 : /* error */
658 perror("fork");
659 exit(1);
661 case 0 : /* child */
662 close(0); /* disassociate */
663 close(1);
664 close(2);
665 setpgrp(0, 0);
666 break;
668 default : /* parent */
669 exit(0);
673 debug_init();
674 dprint((SYSDBG_INFO, "started"));
676 interp = Tcl_CreateInterp();
678 PEInit(interp, sname);
680 while(1){
681 struct timeval tv;
682 fd_set rfd;
684 FD_ZERO(&rfd);
685 FD_SET(s, &rfd);
686 tv.tv_sec = (gPEAbandonTimeout) ? gPEAbandonTimeout : gPeInputTimeout;
687 tv.tv_usec = 0;
688 if((n = select(s+1, &rfd, 0, 0, &tv)) > 0){
689 socklen_t ll = l;
691 gPEAbandonTimeout = 0;
693 if((cs = accept(s, (struct sockaddr *) &name, &ll)) == -1){
694 dprint((SYSDBG_ERR, "accept failure: %s",
695 error_description(errno)));
696 break;
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.
707 o = co = 0;
708 while((n = read(cs, buf + o, bl - o - 1)) > 0){
709 o += n;
710 if(!co){
711 int i, x = 0;
713 for(i = 0; i < o; i++)
714 if(buf[i] == '\n'){
715 co = ++i;
716 l = x + co;
717 if(bl < l + 1){
718 bl = l + 1;
719 fs_resize((void **) &buf, bl * sizeof(char));
722 break;
724 else
725 x = (x * 10) + (buf[i] - '0');
728 if(o && o == l)
729 break;
732 if(n == 0){
733 dprint((SYSDBG_ERR, "read EOF"));
735 else if(n < 0){
736 dprint((SYSDBG_ERR, "read failure: %s", error_description(errno)));
738 else{
739 buf[o] = '\0';
741 /* Log every Eval if somebody *really* wants to see it. */
742 if(debug > 6){
743 char dbuf[5120];
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 */
749 if(dbuf[9] == 'P'
750 && dbuf[10] == 'E'
751 && dbuf[11] == 'S'
752 && !strncmp(dbuf + 12, "ession creds ", 13)){
753 char *p;
755 for(p = &dbuf[25]; *p; p++)
756 *p = 'X';
759 dprint((1, dbuf));
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;
771 close(cs);
773 else if(errno != EINTR){
774 if(n < 0){
775 dprint((SYSDBG_ALERT, "select failure: %s", error_description(errno)));
777 else{
778 dprint((SYSDBG_INFO, "timeout after %d seconds", tv.tv_sec));
781 Tcl_Exit(0);
783 /* Tcl_Exit should never return. Getting here is an error. */
784 dprint((SYSDBG_ERR, "Tcl_Exit failure"));
788 else
789 perror("listen");
791 else
792 perror("bind");
794 close(s);
795 unlink(sname);
797 else
798 perror("socket");
800 else
801 fprintf(stderr, "Can't read socket name\n");
803 exit(ev);
808 * peReturn - common routine to return TCL result
810 void
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)
824 int i, n;
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)));
829 return(0);
832 return(1);
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) {
844 return(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);
891 #ifdef ENABLE_LDAP
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 */
897 return(TCL_OK);
901 void
902 PEExitCleanup(ClientData clientData)
904 dprint((4, "PEExitCleanup"));
906 if(wps_global){
907 /* destroy any open stream */
908 peDestroyStream(wps_global);
910 /* destroy user context */
911 peDestroyUserContext(&wps_global);
914 #ifdef ENABLE_LDAP
915 if(wpldap_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"));
941 if(objc == 1){
942 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
944 else{
945 char *s1 = Tcl_GetStringFromObj(objv[1], NULL);
947 if(s1){
948 if(!strcmp(s1, "colorset")){
949 char *varname, *fghex, *bghex;
950 char tvname[256], asciicolor[256];
951 struct variable *vtmp;
952 Tcl_Obj **cObj;
953 int cObjc;
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);
958 return(TCL_ERROR);
961 if(!strcmp(varname, "viewer-hdr-colors")){
962 char *newhdr = NULL, *newpat = NULL, *utype;
963 int hindex, i;
965 if(objc < 5){
966 Tcl_SetResult(interp, "colorset: too few view-hdr args", TCL_STATIC);
967 return(TCL_ERROR);
970 hcolors = spec_colors_from_varlist(wps_global->VAR_VIEW_HDR_COLORS, 0);
971 if(!(utype = Tcl_GetStringFromObj(objv[3], NULL))){
972 Tcl_SetResult(interp, "colorset: can't read operation", TCL_STATIC);
973 return(TCL_ERROR);
976 if(!strcmp(utype, "delete")){
977 if(!hcolors){
978 Tcl_SetResult(interp, "colorset: no viewer-hdrs to delete", TCL_STATIC);
979 return(TCL_ERROR);
982 if(Tcl_GetIntFromObj(interp, objv[4], &hindex) == TCL_ERROR){
983 Tcl_SetResult(interp, "colorset: can't read index", TCL_STATIC);
984 return(TCL_ERROR);
987 if(hindex == 0){
988 thc = hcolors;
989 hcolors = hcolors->next;
990 thc->next = NULL;
991 free_spec_colors(&thc);
993 else{
994 /* zero based */
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;
1002 thc2->next = NULL;
1003 free_spec_colors(&thc2);
1005 else{
1006 Tcl_SetResult(interp, "colorset: invalid index", TCL_STATIC);
1007 return(TCL_ERROR);
1011 else if(!strcmp(utype, "add")){
1012 if(objc != 6){
1013 Tcl_SetResult(interp, "colorset: wrong number of view-hdr add args", TCL_STATIC);
1014 return(TCL_ERROR);
1017 if(Tcl_ListObjGetElements(interp, objv[4], &cObjc, &cObj) != TCL_OK)
1018 return (TCL_ERROR);
1020 if(cObjc != 2){
1021 Tcl_SetResult(interp, "colorset: wrong number of hdrs for view-hdr add", TCL_STATIC);
1022 return(TCL_ERROR);
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)
1028 return (TCL_ERROR);
1030 if(cObjc != 2){
1031 Tcl_SetResult(interp, "colorset: wrong number of colors for view-hdr add", TCL_STATIC);
1032 return(TCL_ERROR);
1035 fghex = Tcl_GetStringFromObj(cObj[0], NULL);
1036 bghex = Tcl_GetStringFromObj(cObj[1], NULL);
1037 if(newhdr && newpat && fghex && bghex){
1038 SPEC_COLOR_S **hcp;
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);
1051 else
1052 (*hcp)->val = NULL;
1054 (*hcp)->next = NULL;
1056 else{
1057 Tcl_SetResult(interp, "colorset: invalid args for view-hdr add", TCL_STATIC);
1058 return(TCL_ERROR);
1061 else if(!strcmp(utype, "update")){
1062 if(objc != 6){
1063 Tcl_SetResult(interp, "colorset: wrong number of view-hdr update args", TCL_STATIC);
1064 return(TCL_ERROR);
1067 if(!(Tcl_ListObjGetElements(interp, objv[4], &cObjc, &cObj) == TCL_OK
1068 && cObjc == 3
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);
1073 return (TCL_ERROR);
1076 if(!(Tcl_ListObjGetElements(interp, objv[5], &cObjc, &cObj) == TCL_OK
1077 && cObjc == 2
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);
1081 return (TCL_ERROR);
1084 for(thc = hcolors, i = 0; thc && i < hindex; thc = thc->next, i++)
1087 if(!thc){
1088 Tcl_SetResult(interp, "colorset: view-hdr update invalid index", TCL_STATIC);
1089 return (TCL_ERROR);
1092 if(thc->spec)
1093 fs_give((void **)&thc->spec);
1095 thc->spec = cpystr(newhdr);
1096 if(ascii_colorstr(asciicolor, fghex) == 0) {
1097 if(thc->fg)
1098 fs_give((void **)&thc->fg);
1100 thc->fg = cpystr(asciicolor);
1102 else{
1103 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid foreground color value %.100s", fghex);
1104 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
1105 return(TCL_ERROR);
1108 if(ascii_colorstr(asciicolor, bghex) == 0) {
1109 if(thc->bg)
1110 fs_give((void **)&thc->bg);
1112 thc->bg = cpystr(asciicolor);
1114 else{
1115 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background color value %.100s", bghex);
1116 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
1117 return(TCL_ERROR);
1120 if(thc->val)
1121 fs_give((void **)&thc->val);
1123 if(newpat && *newpat){
1124 thc->val = string_to_pattern(newpat);
1127 else{
1128 Tcl_SetResult(interp, "colorset: unknown operation", TCL_STATIC);
1129 return(TCL_ERROR);
1132 vtmp = &wps_global->vars[V_VIEW_HDR_COLORS];
1133 for(i = 0; vtmp->main_user_val.l && vtmp->main_user_val.l[i]; i++)
1134 fs_give((void **)&vtmp->main_user_val.l[i]);
1136 if(vtmp->main_user_val.l)
1137 fs_give((void **)&vtmp->main_user_val.l);
1139 vtmp->main_user_val.l = varlist_from_spec_colors(hcolors);
1140 set_current_val(vtmp, FALSE, FALSE);
1141 free_spec_colors(&hcolors);
1142 return(TCL_OK);
1144 else {
1145 if(objc != 4){
1146 Tcl_SetResult(interp, "colorset: Wrong number of args", TCL_STATIC);
1147 return(TCL_ERROR);
1150 if(!(Tcl_ListObjGetElements(interp, objv[3], &cObjc, &cObj) == TCL_OK
1151 && cObjc == 2
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);
1155 return (TCL_ERROR);
1158 snprintf(tvname, sizeof(tvname), "%.200s-foreground-color", varname);
1159 for(vtmp = &wps_global->vars[V_NORM_FORE_COLOR];
1160 vtmp->name && strucmp(vtmp->name, tvname);
1161 vtmp++)
1164 if(!vtmp->name || vtmp->is_list){
1165 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background var %.100s", varname);
1166 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
1167 return(TCL_ERROR);
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);
1179 else{
1180 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid color value %.100s", fghex);
1181 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
1182 return(TCL_ERROR);
1185 snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-background-color");
1186 vtmp++;
1187 if((vtmp->name && strucmp(vtmp->name, tvname)) || !vtmp->name)
1188 for(vtmp = &wps_global->vars[V_NORM_FORE_COLOR];
1189 vtmp->name && strucmp(vtmp->name, tvname);
1190 vtmp++)
1193 if(!vtmp->name || vtmp->is_list){
1194 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background var %.100s", varname);
1195 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
1196 return(TCL_ERROR);
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);
1208 else{
1209 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background color value %.100s", bghex);
1210 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
1211 return(TCL_ERROR);
1214 Tcl_SetResult(interp, "1", TCL_STATIC);
1215 return(TCL_OK);
1218 else if(!strcmp(s1, "lappend")){
1219 if(objc >= 4){
1220 Tcl_Obj *dObj;
1221 int i;
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)
1226 return(TCL_ERROR);
1228 if(i == objc){
1229 return(TCL_OK);
1232 else
1233 err = "PEInfo lappend: Unknown list name";
1235 else
1236 err = "PEInfo lappend: Too few args";
1238 else if(objc == 2){
1239 if(!strcmp(s1, "version")){
1240 char buf[256];
1243 * CMD: version
1245 * Returns: string representing Pine version
1246 * engine built on
1248 Tcl_SetResult(interp, ALPINE_VERSION, TCL_STATIC);
1249 return(TCL_OK);
1251 else if(!strcmp(s1, "revision")){
1252 char buf[16];
1255 * CMD: revision
1257 * Returns: string representing Pine SVN revision
1258 * engine built on
1261 Tcl_SetResult(interp, get_alpine_revision_number(buf, sizeof(buf)), TCL_VOLATILE);
1262 return(TCL_OK);
1264 else if(!strcmp(s1, "key")){
1265 static char key[64];
1267 if(!key[0])
1268 peRandomString(key,32,PRS_UPPER_CASE);
1270 Tcl_SetResult(interp, key, TCL_STATIC);
1271 return(TCL_OK);
1273 else if(!strcmp(s1, "indexheight")){
1274 Tcl_SetResult(interp, wps_global->VAR_WP_INDEXHEIGHT ?
1275 wps_global->VAR_WP_INDEXHEIGHT : "", TCL_VOLATILE);
1276 return(TCL_OK);
1278 else if(!strcmp(s1, "indexlines")){
1279 Tcl_SetResult(interp, wps_global->VAR_WP_INDEXLINES ?
1280 wps_global->VAR_WP_INDEXLINES : "0", TCL_VOLATILE);
1281 return(TCL_OK);
1283 else if(!strcmp(s1, "aggtabstate")){
1284 Tcl_SetResult(interp, wps_global->VAR_WP_AGGSTATE ?
1285 wps_global->VAR_WP_AGGSTATE : "0", TCL_VOLATILE);
1286 return(TCL_OK);
1288 else if(!strcmp(s1, "alpinestate")){
1289 char *wps, *p, *q;
1291 if((wps = wps_global->VAR_WP_STATE) != NULL){
1292 wps = p = q = cpystr(wps);
1294 if(*q == '\\' && *(q+1) == '$')
1295 q++;
1296 while((*p++ = *q++) != '\0');
1299 Tcl_SetResult(interp, wps ? wps : "", TCL_VOLATILE);
1301 if(wps)
1302 fs_give((void **) &wps);
1304 return(TCL_OK);
1306 else if(!strcmp(s1, "foreground")){
1307 char *color;
1309 if(!((color = pico_get_last_fg_color())
1310 && (color = color_to_asciirgb(color))
1311 && (color = peColorStr(color,wtmp_20k_buf))))
1312 color = "000000";
1314 Tcl_SetResult(interp, color, TCL_VOLATILE);
1315 return(TCL_OK);
1317 else if(!strcmp(s1, "background")){
1318 char *color;
1320 if(!((color = pico_get_last_bg_color())
1321 && (color = color_to_asciirgb(color))
1322 && (color = peColorStr(color,wtmp_20k_buf))))
1323 color = "FFFFFF";
1325 Tcl_SetResult(interp, color, TCL_VOLATILE);
1326 return(TCL_OK);
1328 else if(!strcmp(s1, "flaglist")){
1329 int i;
1330 char *p;
1331 Tcl_Obj *itemObj;
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
1342 * CMD: flaglist
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),
1350 itemObj) != TCL_OK)
1354 return(TCL_OK);
1356 else if(!strcmp(s1, "featurelist")){
1357 int i;
1358 char *curfeature, *s;
1359 FEATURE_S *feature;
1360 Tcl_Obj *itemObj, *secObj = NULL, *resObj = NULL;
1363 * CMD: featurelist
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)){
1370 if(resObj) {
1371 Tcl_ListObjAppendElement(interp,
1372 secObj,
1373 resObj);
1374 Tcl_ListObjAppendElement(interp,
1375 Tcl_GetObjResult(interp),
1376 secObj);
1379 secObj = Tcl_NewListObj(0, NULL);
1380 resObj = Tcl_NewListObj(0, NULL);
1381 if(Tcl_ListObjAppendElement(interp,
1382 secObj,
1383 Tcl_NewStringObj(s,-1)) != TCL_OK)
1386 curfeature = s;
1389 if((itemObj = Tcl_NewStringObj(feature->name, -1)) != NULL){
1390 if(Tcl_ListObjAppendElement(interp,
1391 resObj,
1392 itemObj) != TCL_OK)
1397 if(resObj){
1398 Tcl_ListObjAppendElement(interp, secObj, resObj);
1399 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), secObj);
1402 return(TCL_OK);
1404 else if(!strcmp(s1, "featuresettings")){
1405 int i;
1406 FEATURE_S *feature;
1407 Tcl_Obj *itemObj;
1410 * CMD: featuresettings
1412 * Returns: list of FEATURES currently SET
1414 for(i = 0; (feature = feature_list(i)); i++)
1415 if(feature_list_section(feature)){
1416 if(F_ON(feature->id, wps_global)){
1417 if((itemObj = Tcl_NewStringObj(feature->name, -1)) != NULL){
1418 if(Tcl_ListObjAppendElement(interp,
1419 Tcl_GetObjResult(interp),
1420 itemObj) != TCL_OK)
1426 return(TCL_OK);
1428 else if(!strcmp(s1, "signature")){
1429 char *sig;
1431 if((wps_global->VAR_LITERAL_SIG
1432 || (wps_global->VAR_SIGNATURE_FILE
1433 && IS_REMOTE(wps_global->VAR_SIGNATURE_FILE)))
1434 && (sig = detoken(NULL, NULL, 2, 0, 1, NULL, NULL))){
1435 char *p, *q;
1437 for(p = sig; (q = strindex(p, '\n')); p = q + 1)
1438 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
1439 Tcl_NewStringObj(p, q - p));
1441 if(*p)
1442 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
1443 Tcl_NewStringObj(p, -1));
1445 fs_give((void **) &sig);
1447 else
1448 Tcl_SetResult(interp, "", TCL_STATIC);
1450 return(TCL_OK);
1452 else if(!strcmp(s1, "rawsig")){
1453 char *err = NULL, *sig = NULL, *p, *q;
1455 if(wps_global->VAR_LITERAL_SIG){
1456 char *err = NULL;
1457 char **apval;
1459 if(wps_global->restricted){
1460 err = "Alpine demo can't change config file";
1462 else{
1463 /* BUG: no "exceptions file" support */
1464 if((apval = APVAL(&wps_global->vars[V_LITERAL_SIG], Main)) != NULL){
1465 sig = (char *) fs_get((strlen(*apval ? *apval : "") + 1) * sizeof(char));
1466 sig[0] = '\0';
1467 cstring_to_string(*apval, sig);
1469 else
1470 err = "Problem accessing configuration";
1473 else if(!IS_REMOTE(wps_global->VAR_SIGNATURE_FILE))
1474 snprintf(err = wtmp_20k_buf, SIZEOF_20KBUF, "Non-Remote signature file: %s",
1475 wps_global->VAR_SIGNATURE_FILE ? wps_global->VAR_SIGNATURE_FILE : "<null>");
1476 else if(!(sig = simple_read_remote_file(wps_global->VAR_SIGNATURE_FILE, REMOTE_SIG_SUBTYPE)))
1477 err = "Can't read remote pinerc";
1479 if(err){
1480 Tcl_SetResult(interp, err, TCL_VOLATILE);
1481 return(TCL_ERROR);
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);
1491 return(TCL_OK);
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);
1498 return(TCL_OK);
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);
1511 return(TCL_OK);
1513 else if(!strcmp(s1, "saveconf")){
1514 write_pinerc(wps_global, Main, WRP_NOUSER);
1515 return(TCL_OK);
1517 else if(!strucmp(s1, "sort")){
1518 return(peAppendDefaultSort(interp));
1520 else if(!strcmp(s1, "ldapenabled")){
1522 * CMD: ldapenabled
1524 * Returns: 1 if enabled 0 if not
1526 #ifdef ENABLE_LDAP
1527 Tcl_SetResult(interp, "1", TCL_VOLATILE);
1528 #else
1529 Tcl_SetResult(interp, "0", TCL_VOLATILE);
1530 #endif
1532 return(TCL_OK);
1534 else if(!strcmp(s1, "prunecheck")){
1535 time_t now;
1536 struct tm *tm_now;
1537 char tmp[50];
1539 if(!check_prune_time(&now, &tm_now)){
1540 Tcl_SetResult(interp, "0", TCL_VOLATILE);
1541 return(TCL_OK);
1542 } else {
1544 * We're going to reset the last-time-pruned variable
1545 * so that it asks a maximum of 1 time per month.
1546 * PROs: Annoying-factor is at its lowest
1547 * Can go ahead and move folders right away if
1548 * pruning-rule is automatically set to do so
1549 * CONs: Annoying-factor is at its lowest, if it's set
1550 * later then we can ensure that the questions
1551 * actually get answered or it will keep asking
1553 wps_global->last_expire_year = tm_now->tm_year;
1554 wps_global->last_expire_month = tm_now->tm_mon;
1555 snprintf(tmp, sizeof(tmp), "%d.%d", wps_global->last_expire_year,
1556 wps_global->last_expire_month + 1);
1557 set_variable(V_LAST_TIME_PRUNE_QUESTION, tmp, 0, 1, Main);
1559 Tcl_SetResult(interp, "1", TCL_VOLATILE);
1561 return(TCL_OK);
1563 else if(!strcmp(s1, "prunetime")){
1564 time_t now;
1565 struct tm *tm_now;
1566 CONTEXT_S *prune_cntxt;
1567 Tcl_Obj *retObj = NULL;
1568 int cur_month, ok = 1;
1569 char **p;
1570 static int moved_fldrs = 0;
1572 now = time((time_t *)0);
1573 tm_now = localtime(&now);
1574 cur_month = (1900 + tm_now->tm_year) * 12 + tm_now->tm_mon;
1576 if(!(prune_cntxt = default_save_context(wps_global->context_list)))
1577 prune_cntxt = wps_global->context_list;
1579 if(prune_cntxt){
1580 if(wps_global->VAR_DEFAULT_FCC && *wps_global->VAR_DEFAULT_FCC
1581 && context_isambig(wps_global->VAR_DEFAULT_FCC))
1582 if((retObj = wp_prune_folders(prune_cntxt,
1583 wps_global->VAR_DEFAULT_FCC,
1584 cur_month, "sent",
1585 wps_global->pruning_rule, &ok,
1586 moved_fldrs, interp)) != NULL)
1587 Tcl_ListObjAppendElement(interp,
1588 Tcl_GetObjResult(interp),
1589 retObj);
1591 if(ok && wps_global->VAR_READ_MESSAGE_FOLDER
1592 && *wps_global->VAR_READ_MESSAGE_FOLDER
1593 && context_isambig(wps_global->VAR_READ_MESSAGE_FOLDER))
1594 if((retObj = wp_prune_folders(prune_cntxt,
1595 wps_global->VAR_READ_MESSAGE_FOLDER,
1596 cur_month, "read",
1597 wps_global->pruning_rule, &ok,
1598 moved_fldrs, interp)) != NULL)
1599 Tcl_ListObjAppendElement(interp,
1600 Tcl_GetObjResult(interp),
1601 retObj);
1602 if(ok && (p = wps_global->VAR_PRUNED_FOLDERS)){
1603 for(; ok && *p; p++)
1604 if(**p && context_isambig(*p))
1605 if((retObj = wp_prune_folders(prune_cntxt,
1606 *p, cur_month, "",
1607 wps_global->pruning_rule, &ok,
1608 moved_fldrs, interp)) != NULL)
1609 Tcl_ListObjAppendElement(interp,
1610 Tcl_GetObjResult(interp),
1611 retObj);
1614 moved_fldrs = 1;
1615 return(TCL_OK);
1617 else if(!strcmp(s1, "authrequestor")){
1618 Tcl_SetResult(interp, peCredentialRequestor, TCL_STATIC);
1619 return(TCL_OK);
1621 else if(!strcmp(s1, "noop")){
1622 /* tickle the imap server too */
1623 if(wps_global->mail_stream)
1624 pine_mail_ping(wps_global->mail_stream);
1626 Tcl_SetResult(interp, "NOOP", TCL_STATIC);
1627 return(TCL_OK);
1629 else if(!strcmp(s1, "inputtimeout")){
1630 Tcl_SetResult(interp, int2string(get_input_timeout()), TCL_VOLATILE);
1631 return(TCL_OK);
1634 else if(objc == 3){
1635 if(!strcmp(s1, "feature")){
1636 char *featurename;
1637 int i, isset = 0;
1638 FEATURE_S *feature;
1641 * CMD: feature
1643 * ARGS: featurename -
1645 * Returns: 1 if named feature set, 0 otherwise
1648 if((featurename = Tcl_GetStringFromObj(objv[2], NULL)) != NULL)
1649 for(i = 0; (feature = feature_list(i)); i++)
1650 if(!strucmp(featurename, feature->name)){
1651 isset = F_ON(feature->id, wps_global);
1652 break;
1655 Tcl_SetResult(interp, int2string(isset), TCL_VOLATILE);
1656 return(TCL_OK);
1658 else if(!strcmp(s1, "colorget")){
1659 char *varname;
1660 char tvname[256], hexcolor[256];
1661 struct variable *vtmp;
1662 if(!(varname = Tcl_GetStringFromObj(objv[2], NULL))){
1663 return(TCL_ERROR);
1665 if(strcmp("viewer-hdr-colors", varname) == 0){
1666 SPEC_COLOR_S *hcolors, *thc;
1667 Tcl_Obj *resObj;
1668 char hexcolor[256], *tstr = NULL;
1670 hcolors = spec_colors_from_varlist(wps_global->VAR_VIEW_HDR_COLORS, 0);
1671 for(thc = hcolors; thc; thc = thc->next){
1672 resObj = Tcl_NewListObj(0,NULL);
1673 Tcl_ListObjAppendElement(interp, resObj,
1674 Tcl_NewStringObj(thc->spec, -1));
1675 hex_colorstr(hexcolor, thc->fg);
1676 Tcl_ListObjAppendElement(interp, resObj,
1677 Tcl_NewStringObj(hexcolor, -1));
1678 hex_colorstr(hexcolor, thc->bg);
1679 Tcl_ListObjAppendElement(interp, resObj,
1680 Tcl_NewStringObj(hexcolor, -1));
1681 Tcl_ListObjAppendElement(interp, resObj,
1682 Tcl_NewStringObj(thc->val
1683 ? tstr = pattern_to_string(thc->val)
1684 : "", -1));
1685 if(tstr) fs_give((void **)&tstr);
1686 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
1687 resObj);
1689 fs_give((void **)&hcolors);
1690 return(TCL_OK);
1692 else {
1693 snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-foreground-color");
1694 for(vtmp = &wps_global->vars[V_NORM_FORE_COLOR];
1695 vtmp->name && strucmp(vtmp->name, tvname);
1696 vtmp++);
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));
1702 else{
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");
1708 vtmp++;
1709 if((vtmp->name && strucmp(vtmp->name, tvname)) || !vtmp->name)
1710 for(vtmp = &wps_global->vars[V_NORM_FORE_COLOR];
1711 vtmp->name && strucmp(vtmp->name, tvname);
1712 vtmp++)
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));
1720 else{
1721 hex_colorstr(hexcolor, vtmp->current_val.p);
1722 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
1723 Tcl_NewStringObj(hexcolor, -1));
1726 return(TCL_OK);
1728 else if(!strcmp(s1, "varget")){
1729 struct variable *vtmp;
1730 Tcl_Obj *itemObj, *resObj, *secObj;
1731 char *vallist, *varname, tmperrmsg[256];
1732 int i;
1733 NAMEVAL_S *tmpnv;
1736 * CMD: varget
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",
1750 TCL_VOLATILE);
1751 return(TCL_ERROR);
1754 for(vtmp = wps_global->vars;
1755 vtmp->name && strucmp(vtmp->name, varname);
1756 vtmp++)
1759 if(!vtmp->name){
1760 snprintf(tmperrmsg, sizeof(tmperrmsg), "Can't find variable named %s",
1761 strlen(varname) < 200 ? varname : "");
1762 Tcl_SetResult(interp, tmperrmsg, TCL_VOLATILE);
1763 return(TCL_ERROR);
1765 if((itemObj = Tcl_NewStringObj(vtmp->name, -1)) != NULL){
1766 Tcl_ListObjAppendElement(interp,
1767 Tcl_GetObjResult(interp),
1768 itemObj);
1769 resObj = Tcl_NewListObj(0, NULL);
1770 if(vtmp->is_list){
1771 for(i = 0 ; vtmp->current_val.l && vtmp->current_val.l[i]; i++){
1772 vallist = vtmp->current_val.l[i];
1773 if(*(vallist))
1774 itemObj = Tcl_NewStringObj(vallist, -1);
1775 else
1776 itemObj = Tcl_NewStringObj("", -1);
1777 Tcl_ListObjAppendElement(interp, resObj, itemObj);
1780 else{
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),
1787 resObj);
1788 secObj = Tcl_NewListObj(0, NULL);
1789 if(vtmp->is_list)
1790 itemObj = Tcl_NewStringObj("textarea", -1);
1791 else{
1792 NAMEVAL_S *(*tmpf)(int);
1793 switch(vtmp - wps_global->vars){
1794 case V_SAVED_MSG_NAME_RULE:
1795 tmpf = save_msg_rules;
1796 break;
1797 case V_FCC_RULE:
1798 tmpf = fcc_rules;
1799 break;
1800 case V_SORT_KEY:
1801 tmpf = sort_key_rules;
1802 break;
1803 case V_AB_SORT_RULE:
1804 tmpf = ab_sort_rules;
1805 break;
1806 case V_FLD_SORT_RULE:
1807 tmpf = fld_sort_rules;
1808 break;
1809 case V_GOTO_DEFAULT_RULE:
1810 tmpf = goto_rules;
1811 break;
1812 case V_INCOMING_STARTUP:
1813 tmpf = incoming_startup_rules;
1814 break;
1815 case V_PRUNING_RULE:
1816 tmpf = pruning_rules;
1817 break;
1818 case V_WP_INDEXHEIGHT:
1819 tmpf = wp_indexheight_rules;
1820 break;
1821 default:
1822 tmpf = NULL;
1823 break;
1825 if(tmpf){
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);
1837 else
1838 itemObj = Tcl_NewStringObj("text", -1);
1840 Tcl_ListObjAppendElement(interp,
1841 Tcl_GetObjResult(interp),
1842 itemObj);
1843 Tcl_ListObjAppendElement(interp,
1844 Tcl_GetObjResult(interp),
1845 secObj);
1847 return(TCL_OK);
1849 else if(!strcmp(s1, "rawsig")){
1851 if(wps_global->VAR_LITERAL_SIG){
1852 char *cstring_version, *sig, *line;
1853 int i, nSig;
1854 Tcl_Obj **objSig;
1856 wtmp_20k_buf[0] = '\0';
1857 Tcl_ListObjGetElements(interp, objv[2], &nSig, &objSig);
1858 for(i = 0; i < nSig && i < SIG_MAX_LINES; i++)
1859 if((line = Tcl_GetStringFromObj(objSig[i], NULL)) != NULL)
1860 snprintf(wtmp_20k_buf + strlen(wtmp_20k_buf), SIZEOF_20KBUF - strlen(wtmp_20k_buf), "%.*s\n", SIG_MAX_COLS, line);
1862 sig = cpystr(wtmp_20k_buf);
1864 if((cstring_version = string_to_cstring(sig)) != NULL){
1865 set_variable(V_LITERAL_SIG, cstring_version, 0, 0, Main);
1866 fs_give((void **)&cstring_version);
1869 fs_give((void **) &sig);
1870 return(TCL_OK);
1872 else
1873 return(peWriteSig(interp, wps_global->VAR_SIGNATURE_FILE,
1874 &((Tcl_Obj **)objv)[2]));
1876 else if(!strcmp(s1, "statmsg")){
1877 char *msg;
1880 * CMD: 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)
1889 sml_addmsg(0, msg);
1891 return(TCL_OK);
1893 else if(!strcmp(s1, "mode")){
1894 char *mode;
1895 int rv = 0;
1898 * CMD: mode
1900 * ARGS: <mode>
1902 * Returns: return value of given binary mode
1905 if((mode = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
1906 if(!strcmp(mode, "full-header-mode"))
1907 rv = wps_global->full_header;
1910 Tcl_SetResult(interp, int2string(rv), TCL_VOLATILE);
1911 return(TCL_OK);
1913 else if(!strcmp(s1, "indexlines")){
1914 int n;
1915 char *p;
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);
1921 return(TCL_OK);
1923 else if(!strcmp(s1, "aggtabstate")){
1924 int n;
1925 char *p;
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);
1931 return(TCL_OK);
1933 else if(!strcmp(s1, "alpinestate")){
1934 char *wps, *p, *q, *twps = NULL;
1935 int dollars = 0;
1937 if((wps = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
1938 for(p = wps; *p; p++)
1939 if(*p == '$')
1940 dollars++;
1942 if(dollars){
1943 twps = (char *) fs_get(((p - wps) + (dollars + 1)) * sizeof(char));
1944 p = wps;
1945 q = twps;
1947 if(*p == '$')
1948 *q++ = '\\';
1950 while((*q++ = *p++) != '\0');
1953 set_variable(V_WP_STATE, twps ? twps : wps, 0, 1, Main);
1954 Tcl_SetResult(interp, wps, TCL_VOLATILE);
1955 if(twps)
1956 fs_give((void **) &twps);
1959 return(TCL_OK);
1961 else if(!strcmp(s1, "set")){
1962 Tcl_Obj *rObj;
1964 if((rObj = Tcl_ObjGetVar2(interp, objv[2], NULL, TCL_LEAVE_ERR_MSG)) != NULL){
1965 Tcl_SetObjResult(interp, rObj);
1966 return(TCL_OK);
1968 else
1969 return(TCL_ERROR);
1971 else if(!strcmp(s1, "unset")){
1972 char *varname;
1974 return((varname = Tcl_GetStringFromObj(objv[2], NULL)) ? Tcl_UnsetVar2(interp, varname, NULL, TCL_LEAVE_ERR_MSG) : TCL_ERROR);
1977 else if(objc == 4){
1978 if(!strcmp(s1, "feature")){
1979 char *featurename;
1980 int i, set, wasset = 0;
1981 FEATURE_S *feature;
1984 * CMD: feature
1986 * ARGS: featurename -
1987 * value - new value to assign flag
1989 * Returns: 1 if named feature set, 0 otherwise
1992 if((featurename = Tcl_GetStringFromObj(objv[2], NULL))
1993 && Tcl_GetIntFromObj(interp, objv[3], &set) != TCL_ERROR)
1994 for(i = 0; (feature = feature_list(i)); i++)
1995 if(!strucmp(featurename, feature->name)){
1996 if(set != F_ON(feature->id, wps_global)){
1997 toggle_feature(wps_global,
1998 &wps_global->vars[V_FEATURE_LIST],
1999 feature, TRUE, Main);
2001 if(wps_global->prc)
2002 wps_global->prc->outstanding_pinerc_changes = 1;
2005 break;
2008 Tcl_SetResult(interp, int2string(wasset), TCL_VOLATILE);
2009 return(TCL_OK);
2011 else if(!strucmp(s1, "help")){
2012 HelpType text;
2013 int i;
2014 char **help_text, **ptext, *helpname, tmperrmsg[256],
2015 *function;
2016 Tcl_Obj *itemObj;
2017 struct variable *vtmp;
2018 FEATURE_S *ftmp;
2020 if(!(helpname = Tcl_GetStringFromObj(objv[2], NULL))){
2021 Tcl_SetResult(interp,
2022 "Can't Tcl_GetStringFromObj for helpname",
2023 TCL_VOLATILE);
2024 return(TCL_ERROR);
2026 if(!(function = Tcl_GetStringFromObj(objv[3], NULL))){
2027 Tcl_SetResult(interp,
2028 "Can't Tcl_GetStringFromObj for function",
2029 TCL_VOLATILE);
2030 return(TCL_ERROR);
2032 if(strucmp(function, "plain") == 0){
2033 if((text = help_name2section(helpname, strlen(helpname)))
2034 == NO_HELP)
2035 return(TCL_OK);
2037 else if(strucmp(function, "variable") == 0){
2038 for(vtmp = wps_global->vars;
2039 vtmp->name && strucmp(vtmp->name, helpname);
2040 vtmp++);
2041 if(!vtmp->name) {
2042 snprintf(tmperrmsg, sizeof(tmperrmsg), "Can't find variable named %s",
2043 strlen(helpname) < 200 ? helpname : "");
2044 Tcl_SetResult(interp, tmperrmsg, TCL_VOLATILE);
2045 return(TCL_ERROR);
2047 text = config_help(vtmp - wps_global->vars, 0);
2048 if(text == NO_HELP)
2049 return(TCL_OK);
2051 else if(strucmp(function, "feature") == 0){
2052 for(i = 0; (ftmp = feature_list(i)); i++){
2053 if(!strucmp(helpname, ftmp->name)){
2054 text = ftmp->help;
2055 break;
2058 if(!ftmp || text == NO_HELP){
2059 return(TCL_OK);
2062 else {
2063 snprintf(tmperrmsg, sizeof(tmperrmsg), "Invalid function: %s",
2064 strlen(helpname) < 200 ? function : "");
2065 Tcl_SetResult(interp, tmperrmsg, TCL_VOLATILE);
2066 return(TCL_ERROR);
2068 /* assumption here is that HelpType is char ** */
2069 help_text = text;
2070 for(ptext = help_text; *ptext; ptext++){
2071 itemObj = Tcl_NewStringObj(*ptext, -1);
2072 Tcl_ListObjAppendElement(interp,
2073 Tcl_GetObjResult(interp),
2074 itemObj);
2076 return(TCL_OK);
2078 else if(!strcmp(s1, "varset")){
2079 char *varname, **tmpstrlist, *line;
2080 struct variable *vtmp;
2081 Tcl_Obj **objVal;
2082 int i, numlistvals = 0, strlistpos;
2084 if((varname = Tcl_GetStringFromObj(objv[2], NULL))
2085 && (Tcl_ListObjGetElements(interp, objv[3], &numlistvals,
2086 &objVal) == TCL_OK)){
2087 for(vtmp = wps_global->vars;
2088 vtmp->name && strucmp(vtmp->name, varname);
2089 vtmp++);
2090 if(!vtmp->name){
2091 return(TCL_ERROR);
2093 else{
2094 /* found the variable */
2095 if(vtmp->is_list){
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);
2105 if(*line)
2106 tmpstrlist[strlistpos++] = cpystr(line);
2109 tmpstrlist[strlistpos] = NULL;
2110 vtmp->main_user_val.l = (char **)fs_get((strlistpos+1) *
2111 sizeof(char *));
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);
2117 return(TCL_OK);
2119 else{
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);
2125 if(*line)
2126 vtmp->main_user_val.p = cpystr(line);
2127 set_current_val(vtmp, FALSE, FALSE);
2128 return(TCL_OK);
2133 return(TCL_ERROR);
2135 else if(!strcmp(s1, "mode")){
2136 char *mode;
2137 int value, rv = 0;
2140 * CMD: mode
2142 * ARGS: <mode> <value>
2144 * Returns: old value of binary mode we were told to set
2147 if((mode = Tcl_GetStringFromObj(objv[2], NULL))
2148 && Tcl_GetIntFromObj(interp, objv[3], &value) != TCL_ERROR){
2149 if(!strcmp(mode, "full-header-mode")){
2150 rv = wps_global->full_header;
2151 wps_global->full_header = value;
2155 Tcl_SetResult(interp, int2string(rv), TCL_VOLATILE);
2156 return(TCL_OK);
2158 else if(!strcmp(s1, "set")){
2159 Tcl_Obj *rObj;
2161 if((rObj = Tcl_ObjSetVar2(interp, objv[2], NULL, objv[3], TCL_LEAVE_ERR_MSG)) != NULL){
2162 Tcl_SetObjResult(interp, rObj);
2163 return(TCL_OK);
2165 else
2166 return(TCL_ERROR);
2169 else
2170 err = "PEInfo: Too many arguments";
2174 Tcl_SetResult(interp, err, TCL_STATIC);
2175 return(TCL_ERROR);
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";
2189 char *s1;
2191 dprint((2, "PEConfigCmd"));
2193 if(objc == 1){
2194 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
2195 Tcl_SetResult(interp, err, TCL_STATIC);
2196 return(TCL_ERROR);
2198 s1 = Tcl_GetStringFromObj(objv[1], NULL);
2200 if(s1){
2201 if(!strcmp(s1, "colorset")){
2202 char *varname, *fghex, *bghex;
2203 char tvname[256], asciicolor[256];
2204 struct variable *vtmp;
2205 Tcl_Obj **cObj;
2206 int cObjc;
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);
2211 return(TCL_ERROR);
2214 if(!strcmp(varname, "viewer-hdr-colors")){
2215 char *newhdr = NULL, *newpat = NULL, *utype;
2216 int hindex, i;
2218 if(objc < 5){
2219 Tcl_SetResult(interp, "colorset: too few view-hdr args", TCL_STATIC);
2220 return(TCL_ERROR);
2223 if(wps_global->vars[V_VIEW_HDR_COLORS].is_changed_val)
2224 hcolors = spec_colors_from_varlist(wps_global->vars[V_VIEW_HDR_COLORS].changed_val.l, 0);
2225 else
2226 hcolors = spec_colors_from_varlist(wps_global->VAR_VIEW_HDR_COLORS, 0);
2227 if(!(utype = Tcl_GetStringFromObj(objv[3], NULL))){
2228 Tcl_SetResult(interp, "colorset: can't read operation", TCL_STATIC);
2229 return(TCL_ERROR);
2232 if(!strcmp(utype, "delete")){
2233 if(!hcolors){
2234 Tcl_SetResult(interp, "colorset: no viewer-hdrs to delete", TCL_STATIC);
2235 return(TCL_ERROR);
2238 if(Tcl_GetIntFromObj(interp, objv[4], &hindex) == TCL_ERROR){
2239 Tcl_SetResult(interp, "colorset: can't read index", TCL_STATIC);
2240 return(TCL_ERROR);
2243 if(hindex == 0){
2244 thc = hcolors;
2245 hcolors = hcolors->next;
2246 thc->next = NULL;
2247 free_spec_colors(&thc);
2249 else{
2250 /* zero based */
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;
2258 thc2->next = NULL;
2259 free_spec_colors(&thc2);
2261 else{
2262 Tcl_SetResult(interp, "colorset: invalid index", TCL_STATIC);
2263 return(TCL_ERROR);
2267 else if(!strcmp(utype, "add")){
2268 if(objc != 6){
2269 Tcl_SetResult(interp, "colorset: wrong number of view-hdr add args", TCL_STATIC);
2270 return(TCL_ERROR);
2273 if(Tcl_ListObjGetElements(interp, objv[4], &cObjc, &cObj) != TCL_OK)
2274 return (TCL_ERROR);
2276 if(cObjc != 2){
2277 Tcl_SetResult(interp, "colorset: wrong number of hdrs for view-hdr add", TCL_STATIC);
2278 return(TCL_ERROR);
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)
2284 return (TCL_ERROR);
2286 if(cObjc != 2){
2287 Tcl_SetResult(interp, "colorset: wrong number of colors for view-hdr add", TCL_STATIC);
2288 return(TCL_ERROR);
2291 fghex = Tcl_GetStringFromObj(cObj[0], NULL);
2292 bghex = Tcl_GetStringFromObj(cObj[1], NULL);
2293 if(newhdr && newpat && fghex && bghex){
2294 SPEC_COLOR_S **hcp;
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);
2307 else
2308 (*hcp)->val = NULL;
2310 (*hcp)->next = NULL;
2312 else{
2313 Tcl_SetResult(interp, "colorset: invalid args for view-hdr add", TCL_STATIC);
2314 return(TCL_ERROR);
2317 else if(!strcmp(utype, "update")){
2318 if(objc != 6){
2319 Tcl_SetResult(interp, "colorset: wrong number of view-hdr update args", TCL_STATIC);
2320 return(TCL_ERROR);
2323 if(!(Tcl_ListObjGetElements(interp, objv[4], &cObjc, &cObj) == TCL_OK
2324 && cObjc == 3
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);
2329 return (TCL_ERROR);
2332 if(!(Tcl_ListObjGetElements(interp, objv[5], &cObjc, &cObj) == TCL_OK
2333 && cObjc == 2
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);
2337 return (TCL_ERROR);
2340 for(thc = hcolors, i = 0; thc && i < hindex; thc = thc->next, i++)
2343 if(!thc){
2344 Tcl_SetResult(interp, "colorset: view-hdr update invalid index", TCL_STATIC);
2345 return (TCL_ERROR);
2348 if(thc->spec)
2349 fs_give((void **)&thc->spec);
2351 thc->spec = cpystr(newhdr);
2352 if(ascii_colorstr(asciicolor, fghex) == 0) {
2353 if(thc->fg)
2354 fs_give((void **)&thc->fg);
2356 thc->fg = cpystr(asciicolor);
2358 else{
2359 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid foreground color value %.100s", fghex);
2360 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
2361 return(TCL_ERROR);
2364 if(ascii_colorstr(asciicolor, bghex) == 0) {
2365 if(thc->bg)
2366 fs_give((void **)&thc->bg);
2368 thc->bg = cpystr(asciicolor);
2370 else{
2371 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background color value %.100s", bghex);
2372 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
2373 return(TCL_ERROR);
2376 if(thc->val)
2377 fs_give((void **)&thc->val);
2379 if(newpat && *newpat){
2380 thc->val = string_to_pattern(newpat);
2383 else{
2384 Tcl_SetResult(interp, "colorset: unknown operation", TCL_STATIC);
2385 return(TCL_ERROR);
2388 vtmp = &wps_global->vars[V_VIEW_HDR_COLORS];
2389 for(i = 0; vtmp->changed_val.l && vtmp->changed_val.l[i]; i++)
2390 fs_give((void **)&vtmp->changed_val.l[i]);
2392 if(vtmp->changed_val.l)
2393 fs_give((void **)&vtmp->changed_val.l);
2395 vtmp->changed_val.l = varlist_from_spec_colors(hcolors);
2396 vtmp->is_changed_val = 1;
2397 free_spec_colors(&hcolors);
2398 return(TCL_OK);
2400 else {
2401 if(objc != 4){
2402 Tcl_SetResult(interp, "colorset: Wrong number of args", TCL_STATIC);
2403 return(TCL_ERROR);
2406 if(!(Tcl_ListObjGetElements(interp, objv[3], &cObjc, &cObj) == TCL_OK
2407 && cObjc == 2
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);
2411 return (TCL_ERROR);
2414 snprintf(tvname, sizeof(tvname), "%.200s-foreground-color", varname);
2415 for(vtmp = &wps_global->vars[V_NORM_FORE_COLOR];
2416 vtmp->name && strucmp(vtmp->name, tvname);
2417 vtmp++)
2420 if(!vtmp->name || vtmp->is_list){
2421 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background var %.100s", varname);
2422 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
2423 return(TCL_ERROR);
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);
2438 else{
2439 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid color value %.100s", fghex);
2440 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
2441 return(TCL_ERROR);
2444 snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-background-color");
2445 vtmp++;
2446 if((vtmp->name && strucmp(vtmp->name, tvname)) || !vtmp->name)
2447 for(vtmp = &wps_global->vars[V_NORM_FORE_COLOR];
2448 vtmp->name && strucmp(vtmp->name, tvname);
2449 vtmp++)
2452 if(!vtmp->name || vtmp->is_list){
2453 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background var %.100s", varname);
2454 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
2455 return(TCL_ERROR);
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);
2469 else{
2470 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background color value %.100s", bghex);
2471 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
2472 return(TCL_ERROR);
2475 Tcl_SetResult(interp, "1", TCL_STATIC);
2476 return(TCL_OK);
2479 else if(!strcmp(s1, "ruleset")){
2480 return(peRuleSet(interp, &((Tcl_Obj **)objv)[2]));
2482 else if(objc == 2){
2483 if(!strcmp(s1, "featuresettings")){
2484 struct variable *vtmp;
2485 int i;
2486 FEATURE_S *feature;
2488 vtmp = &wps_global->vars[V_FEATURE_LIST];
2489 for(i = 0; (feature = feature_list(i)); i++)
2490 if(feature_list_section(feature)){
2491 if(vtmp->is_changed_val ? F_CH_ON(feature->id)
2492 : F_ON(feature->id, wps_global)){
2493 Tcl_ListObjAppendElement(interp,
2494 Tcl_GetObjResult(interp),
2495 Tcl_NewStringObj(feature->name, -1));
2498 return(TCL_OK);
2500 else if(!strcmp(s1, "rawsig")){
2501 char *err = NULL, *sig = NULL, *p, *q;
2502 int i;
2503 struct variable *vtmp;
2505 vtmp = &wps_global->vars[V_LITERAL_SIG];
2506 if(vtmp->is_changed_val ? vtmp->changed_val.p
2507 : wps_global->VAR_LITERAL_SIG){
2508 char *err = NULL;
2509 char **apval;
2511 if(wps_global->restricted){
2512 err = "Alpine demo can't change config file";
2514 else{
2515 /* BUG: no "exceptions file" support */
2516 apval = (vtmp->is_changed_val ? &vtmp->changed_val.p
2517 : APVAL(&wps_global->vars[V_LITERAL_SIG], Main));
2518 if(apval){
2519 sig = (char *) fs_get((strlen(*apval ? *apval : "") + 1) * sizeof(char));
2520 sig[0] = '\0';
2521 cstring_to_string(*apval, sig);
2523 else
2524 err = "Problem accessing configuration";
2527 else if((vtmp = &wps_global->vars[V_SIGNATURE_FILE])
2528 && !IS_REMOTE(vtmp->is_changed_val ? vtmp->changed_val.p
2529 : wps_global->VAR_SIGNATURE_FILE))
2530 snprintf(err = wtmp_20k_buf, SIZEOF_20KBUF, "Non-Remote signature file: %s",
2531 vtmp->is_changed_val ? (vtmp->changed_val.p
2532 ? vtmp->changed_val.p : "<null>")
2533 : (wps_global->VAR_SIGNATURE_FILE
2534 ? wps_global->VAR_SIGNATURE_FILE : "<null>"));
2535 else if(!(peTSig || (sig = simple_read_remote_file(vtmp->is_changed_val
2536 ? vtmp->changed_val.p
2537 : wps_global->VAR_SIGNATURE_FILE, REMOTE_SIG_SUBTYPE))))
2538 err = "Can't read remote pinerc";
2540 if(err){
2541 Tcl_SetResult(interp, err, TCL_VOLATILE);
2542 return(TCL_ERROR);
2545 if(peTSig){
2546 for(i = 0; peTSig[i]; i++)
2547 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
2548 Tcl_NewStringObj(peTSig[i],-1));
2550 else {
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);
2559 return(TCL_OK);
2561 else if(!strcmp(s1, "filters")){
2562 long rflags = ROLE_DO_FILTER | PAT_USE_CHANGED;
2563 PAT_STATE pstate;
2564 PAT_S *pat;
2566 close_every_pattern();
2567 if(any_patterns(rflags, &pstate)){
2568 for(pat = first_pattern(&pstate);
2569 pat;
2570 pat = next_pattern(&pstate)){
2571 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
2572 Tcl_NewStringObj(pat->patgrp->nick, -1));
2575 return(TCL_OK);
2577 else if(!strcmp(s1, "scores")){
2578 long rflags = ROLE_DO_SCORES | PAT_USE_CHANGED;
2579 PAT_STATE pstate;
2580 PAT_S *pat;
2582 close_every_pattern();
2583 if(any_patterns(rflags, &pstate)){
2584 for(pat = first_pattern(&pstate);
2585 pat;
2586 pat = next_pattern(&pstate)){
2587 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
2588 Tcl_NewStringObj(pat->patgrp->nick, -1));
2591 return(TCL_OK);
2593 else if(!strcmp(s1, "indexcolors")){
2594 long rflags = ROLE_DO_INCOLS | PAT_USE_CHANGED;
2595 PAT_STATE pstate;
2596 PAT_S *pat;
2598 close_every_pattern();
2599 if(any_patterns(rflags, &pstate)){
2600 for(pat = first_pattern(&pstate);
2601 pat;
2602 pat = next_pattern(&pstate)){
2603 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
2604 Tcl_NewStringObj(pat->patgrp->nick, -1));
2607 return(TCL_OK);
2609 else if(!strcmp(s1, "collections")){
2610 struct variable *vtmp;
2611 int i;
2612 CONTEXT_S *new_ctxt;
2614 vtmp = &wps_global->vars[V_FOLDER_SPEC];
2615 for(i = 0; (vtmp->is_changed_val
2616 ? vtmp->changed_val.l && vtmp->changed_val.l[i]
2617 : vtmp->current_val.l && vtmp->current_val.l[i]);
2618 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",
2623 new_ctxt->nickname
2624 ? new_ctxt->nickname
2625 : (new_ctxt->server
2626 ? new_ctxt->server
2627 : (new_ctxt->label
2628 ? new_ctxt->label
2629 : "Some Collection")),
2630 new_ctxt->label ? new_ctxt->label : "");
2631 free_context(&new_ctxt);
2633 vtmp = &wps_global->vars[V_NEWS_SPEC];
2634 for(i = 0; (vtmp->is_changed_val
2635 ? vtmp->changed_val.l && vtmp->changed_val.l[i]
2636 : vtmp->current_val.l && vtmp->current_val.l[i]);
2637 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",
2642 new_ctxt->nickname
2643 ? new_ctxt->nickname
2644 : (new_ctxt->server
2645 ? new_ctxt->server
2646 : (new_ctxt->label
2647 ? new_ctxt->label
2648 : "Some Collection")),
2649 new_ctxt->label ? new_ctxt->label : "");
2650 free_context(&new_ctxt);
2653 return(TCL_OK);
2655 else if(!strcmp(s1, "newconf")){
2656 struct variable *vtmp;
2657 int i;
2658 FEATURE_S *feature;
2660 for(vtmp = wps_global->vars; vtmp->name; vtmp++)
2661 vtmp->is_changed_val = 0;
2663 for(i = 0; (feature = feature_list(i)); i++)
2664 F_CH_SET(feature->id, F_ON(feature->id, wps_global));
2666 if(peTSig){
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);
2673 return(TCL_OK);
2675 else if(!strcmp(s1, "saveconf")){
2676 struct variable *vtmp;
2677 int i, did_change = 0, def_sort_rev;
2678 FEATURE_S *feature;
2680 if(wps_global->vars[V_FEATURE_LIST].is_changed_val){
2681 wps_global->vars[V_FEATURE_LIST].is_changed_val = 0;
2682 for(i = 0; (feature = feature_list(i)); i++)
2683 if(feature_list_section(feature)){
2684 if(F_CH_ON(feature->id) != F_ON(feature->id, wps_global)){
2685 did_change = 1;
2686 toggle_feature(wps_global,
2687 &wps_global->vars[V_FEATURE_LIST],
2688 feature, TRUE, Main);
2693 for(vtmp = wps_global->vars; vtmp->name; vtmp++){
2694 if(vtmp->is_changed_val
2695 && (vtmp - wps_global->vars != V_FEATURE_LIST)){
2696 if(vtmp->is_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;
2705 else {
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;
2713 did_change = 1;
2714 switch (vtmp - wps_global->vars) {
2715 case V_USER_DOMAIN:
2716 init_hostname(wps_global);
2717 case V_FOLDER_SPEC:
2718 case V_NEWS_SPEC:
2719 free_contexts(&wps_global->context_list);
2720 init_folders(wps_global);
2721 break;
2722 case V_NORM_FORE_COLOR:
2723 pico_set_fg_color(vtmp->current_val.p);
2724 break;
2725 case V_NORM_BACK_COLOR:
2726 pico_set_bg_color(vtmp->current_val.p);
2727 break;
2728 case V_ADDRESSBOOK:
2729 case V_GLOB_ADDRBOOK:
2730 #ifdef ENABLE_LDAP
2731 case V_LDAP_SERVERS:
2732 #endif
2733 case V_ABOOK_FORMATS:
2734 addrbook_reset();
2735 case V_INDEX_FORMAT:
2736 init_index_format(wps_global->VAR_INDEX_FORMAT,
2737 &wps_global->index_disp_format);
2738 clear_index_cache(sp_inbox_stream(), 0);
2739 break;
2740 case V_PAT_FILTS:
2741 close_patterns(ROLE_DO_FILTER | PAT_USE_CURRENT);
2742 role_process_filters();
2743 break;
2744 case V_PAT_INCOLS:
2745 close_patterns(ROLE_DO_INCOLS | PAT_USE_CURRENT);
2746 clear_index_cache(sp_inbox_stream(), 0);
2747 role_process_filters();
2748 break;
2749 case V_PAT_SCORES:
2750 close_patterns(ROLE_DO_SCORES | PAT_USE_CURRENT);
2751 role_process_filters();
2752 break;
2753 case V_DEFAULT_FCC:
2754 case V_DEFAULT_SAVE_FOLDER:
2755 init_save_defaults();
2756 break;
2757 case V_SORT_KEY:
2758 decode_sort(wps_global->VAR_SORT_KEY, &wps_global->def_sort, &def_sort_rev);
2759 break;
2760 case V_VIEW_HDR_COLORS :
2761 set_custom_spec_colors(wps_global);
2762 break;
2763 case V_POST_CHAR_SET :
2764 update_posting_charset(wps_global, 1);
2765 break;
2766 default:
2767 break;
2771 if(peTSig){
2772 peWriteSig(interp, wps_global->VAR_SIGNATURE_FILE, NULL);
2774 if(did_change){
2775 if(write_pinerc(wps_global, Main, WRP_NOUSER) == 0)
2776 q_status_message(SM_ORDER, 0, 3, "Configuration changes saved!");
2778 return(TCL_OK);
2780 else if(!strcmp(s1, "columns")){
2781 Tcl_SetResult(interp, int2string(wps_global->ttyo->screen_cols), TCL_VOLATILE);
2782 return(TCL_OK);
2784 else if(!strcmp(s1, "indextokens")){
2785 INDEX_PARSE_T *tok;
2786 int i;
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));
2793 return(TCL_OK);
2796 else if(objc == 3){
2797 if(!strcmp(s1, "varget")){
2798 char *varname = Tcl_GetStringFromObj(objv[2], NULL);
2799 struct variable *vtmp;
2800 Tcl_Obj *resObj, *secObj;
2801 char *input_type;
2802 int is_default, i;
2803 NAMEVAL_S *tmpnv;
2805 if(varname == NULL) return(TCL_ERROR);
2807 for(vtmp = wps_global->vars;
2808 vtmp->name && strucmp(vtmp->name, varname);
2809 vtmp++)
2812 if(!vtmp->name){
2813 Tcl_SetResult(interp, err, TCL_VOLATILE);
2814 return(TCL_ERROR);
2816 resObj = Tcl_NewListObj(0, NULL);
2817 if(vtmp->is_list){
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));
2824 else {
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));
2831 else {
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
2837 : "\"\"", -1));
2839 else {
2840 if(vtmp->current_val.p)
2841 Tcl_ListObjAppendElement(interp, resObj,
2842 Tcl_NewStringObj(vtmp->current_val.p[0]
2843 ? vtmp->current_val.p
2844 : "\"\"", -1));
2847 Tcl_ListObjAppendElement(interp,
2848 Tcl_GetObjResult(interp),
2849 resObj);
2850 secObj = Tcl_NewListObj(0, NULL);
2851 if(vtmp->is_list)
2852 input_type = cpystr("textarea");
2853 else{
2854 NAMEVAL_S *(*tmpf)(int);
2855 switch(vtmp - wps_global->vars){
2856 case V_SAVED_MSG_NAME_RULE:
2857 tmpf = save_msg_rules;
2858 break;
2859 case V_FCC_RULE:
2860 tmpf = fcc_rules;
2861 break;
2862 case V_SORT_KEY:
2863 tmpf = sort_key_rules;
2864 break;
2865 case V_AB_SORT_RULE:
2866 tmpf = ab_sort_rules;
2867 break;
2868 case V_FLD_SORT_RULE:
2869 tmpf = fld_sort_rules;
2870 break;
2871 case V_GOTO_DEFAULT_RULE:
2872 tmpf = goto_rules;
2873 break;
2874 case V_INCOMING_STARTUP:
2875 tmpf = incoming_startup_rules;
2876 break;
2877 case V_PRUNING_RULE:
2878 tmpf = pruning_rules;
2879 break;
2880 case V_WP_INDEXHEIGHT:
2881 tmpf = wp_indexheight_rules;
2882 break;
2883 default:
2884 tmpf = NULL;
2885 break;
2887 if(tmpf){
2888 for(i = 0; (tmpnv = (tmpf)(i)); i++){
2889 if(tmpnv->shortname)
2890 peAppListF(interp, secObj, "%s%s", tmpnv->name, tmpnv->shortname);
2891 else
2892 Tcl_ListObjAppendElement(interp, secObj,
2893 Tcl_NewStringObj(tmpnv->name, -1));
2895 input_type = cpystr("listbox");
2897 else
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),
2905 secObj);
2906 if(vtmp->is_list)
2907 is_default = !vtmp->is_changed_val && !vtmp->main_user_val.l;
2908 else
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));
2914 return(TCL_OK);
2916 else if(!strcmp(s1, "filtextended")){
2917 int fl, i;
2918 long rflags = ROLE_DO_FILTER | PAT_USE_CHANGED;
2919 PAT_STATE pstate;
2920 PAT_S *pat;
2921 Tcl_Obj *resObj = NULL, *tObj = NULL;
2923 if(Tcl_GetIntFromObj(interp, objv[2], &fl) == TCL_ERROR)
2924 return(TCL_ERROR);
2926 close_every_pattern();
2927 if(any_patterns(rflags, &pstate)){
2928 for(pat = first_pattern(&pstate), i = 0;
2929 pat && i != fl;
2930 pat = next_pattern(&pstate), i++);
2932 if(!pat)
2933 return(TCL_ERROR);
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);
2960 return(TCL_OK);
2962 else if(!strcmp(s1, "indexcolorextended")){
2963 int fl, i;
2964 long rflags = ROLE_DO_INCOLS | PAT_USE_CHANGED;
2965 PAT_STATE pstate;
2966 PAT_S *pat;
2967 Tcl_Obj *resObj = NULL, *tObj = NULL;
2969 if(Tcl_GetIntFromObj(interp, objv[2], &fl) == TCL_ERROR)
2970 return(TCL_ERROR);
2972 close_every_pattern();
2973 if(any_patterns(rflags, &pstate)){
2974 for(pat = first_pattern(&pstate), i = 0;
2975 pat && i != fl;
2976 pat = next_pattern(&pstate), i++);
2978 if(!pat)
2979 return(TCL_ERROR);
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){
2998 char *color;
2999 Tcl_Obj *colObj = Tcl_NewListObj(0, NULL);
3001 if(!(pat->action->incol
3002 && pat->action->incol->fg
3003 && pat->action->incol->fg[0]
3004 && (color = color_to_asciirgb(pat->action->incol->fg))
3005 && (color = peColorStr(color,wtmp_20k_buf))))
3006 color = "";
3008 Tcl_ListObjAppendElement(interp, colObj, Tcl_NewStringObj(color, -1));
3010 if(!(pat->action->incol
3011 && pat->action->incol->bg
3012 && pat->action->incol->bg[0]
3013 && (color = color_to_asciirgb(pat->action->incol->bg))
3014 && (color = peColorStr(color,wtmp_20k_buf))))
3015 color = "";
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);
3029 return(TCL_OK);
3031 else if(!strcmp(s1, "scoreextended")){
3032 int fl, i;
3033 long rflags = ROLE_DO_SCORES | PAT_USE_CHANGED;
3034 char *hdr = NULL;
3035 PAT_STATE pstate;
3036 PAT_S *pat;
3037 Tcl_Obj *resObj = NULL, *tObj = NULL;
3039 if(Tcl_GetIntFromObj(interp, objv[2], &fl) == TCL_ERROR)
3040 return(TCL_ERROR);
3042 close_every_pattern();
3043 if(any_patterns(rflags, &pstate)){
3044 for(pat = first_pattern(&pstate), i = 0;
3045 pat && i != fl;
3046 pat = next_pattern(&pstate), i++);
3048 if(!pat)
3049 return(TCL_ERROR);
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 : "");
3071 if(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);
3081 return(TCL_OK);
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;
3087 CONTEXT_S *ctxt;
3089 vtmp = &wps_global->vars[V_FOLDER_SPEC];
3090 if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR)
3091 return(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]))
3100 in_folder_spec = 1;
3101 else {
3102 vtmp = &wps_global->vars[V_NEWS_SPEC];
3103 for(j = 0; i + j < cl && (vtmp->is_changed_val
3104 ? (vtmp->changed_val.l
3105 && vtmp->changed_val.l[j])
3106 : (vtmp->current_val.l
3107 && vtmp->current_val.l[j])); j++);
3109 if(in_folder_spec || (i + j == cl && (vtmp->is_changed_val
3110 ? vtmp->changed_val.l && vtmp->changed_val.l[j]
3111 : vtmp->current_val.l && vtmp->current_val.l[j]))){
3112 ctxt = new_context(vtmp->is_changed_val ? vtmp->changed_val.l[in_folder_spec ? i : j]
3113 : vtmp->current_val.l[in_folder_spec ? i : j], NULL);
3114 Tcl_ListObjAppendElement(interp,
3115 Tcl_GetObjResult(interp),
3116 Tcl_NewStringObj(ctxt->nickname ? ctxt->nickname : "", -1));
3117 Tcl_ListObjAppendElement(interp,
3118 Tcl_GetObjResult(interp),
3119 Tcl_NewStringObj(ctxt->label ? ctxt->label : "", -1));
3120 Tcl_ListObjAppendElement(interp,
3121 Tcl_GetObjResult(interp),
3122 Tcl_NewStringObj(ctxt->server ? ctxt->server : "", -1));
3123 tpath[0] = '\0';
3124 if(ctxt->context){
3125 strncpy(tpath, (ctxt->context[0] == '{'
3126 && (p = strchr(ctxt->context, '}')))
3127 ? ++p
3128 : ctxt->context, sizeof(tpath));
3129 tpath[sizeof(tpath)-1] = '\0';
3130 if((p = strstr(tpath, "%s")) != NULL)
3131 *p = '\0';
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);
3142 return(TCL_OK);
3144 else
3145 return(TCL_ERROR);
3147 else if(!strcmp(s1, "rawsig")){
3148 struct variable *vtmp;
3149 char *cstring_version, *sig, *line;
3150 int i, nSig;
3151 Tcl_Obj **objSig;
3153 vtmp = &wps_global->vars[V_LITERAL_SIG];
3154 if(vtmp->is_changed_val ? vtmp->changed_val.p
3155 : wps_global->VAR_LITERAL_SIG){
3157 wtmp_20k_buf[0] = '\0';
3158 Tcl_ListObjGetElements(interp, objv[2], &nSig, &objSig);
3159 for(i = 0; i < nSig && i < SIG_MAX_LINES; i++)
3160 if((line = Tcl_GetStringFromObj(objSig[i], NULL)) != NULL)
3161 snprintf(wtmp_20k_buf + strlen(wtmp_20k_buf), SIZEOF_20KBUF - strlen(wtmp_20k_buf), "%.*s\n", SIG_MAX_COLS, line);
3163 sig = cpystr(wtmp_20k_buf);
3165 if((cstring_version = string_to_cstring(sig)) != NULL){
3166 if(vtmp->changed_val.p)
3167 fs_give((void **)&vtmp->changed_val.p);
3168 vtmp->is_changed_val = 1;
3169 vtmp->changed_val.p = cstring_version;
3172 fs_give((void **) &sig);
3173 return(TCL_OK);
3175 else {
3176 if(peTSig){
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 : "");
3187 peTSig[i] = NULL;
3188 return(TCL_OK);
3191 else if(!strcmp(s1, "colorget")){
3192 char *varname;
3193 char tvname[256], hexcolor[256];
3194 struct variable *vtmp;
3195 if(!(varname = Tcl_GetStringFromObj(objv[2], NULL))){
3196 return(TCL_ERROR);
3198 if(strcmp("viewer-hdr-colors", varname) == 0){
3199 SPEC_COLOR_S *hcolors, *thc;
3200 Tcl_Obj *resObj;
3201 char hexcolor[256], *tstr = NULL;
3203 if(wps_global->vars[V_VIEW_HDR_COLORS].is_changed_val)
3204 hcolors = spec_colors_from_varlist(wps_global->vars[V_VIEW_HDR_COLORS].changed_val.l, 0);
3205 else
3206 hcolors = spec_colors_from_varlist(wps_global->VAR_VIEW_HDR_COLORS, 0);
3207 for(thc = hcolors; thc; thc = thc->next){
3208 resObj = Tcl_NewListObj(0,NULL);
3209 Tcl_ListObjAppendElement(interp, resObj,
3210 Tcl_NewStringObj(thc->spec, -1));
3211 hex_colorstr(hexcolor, thc->fg);
3212 Tcl_ListObjAppendElement(interp, resObj,
3213 Tcl_NewStringObj(hexcolor, -1));
3214 hex_colorstr(hexcolor, thc->bg);
3215 Tcl_ListObjAppendElement(interp, resObj,
3216 Tcl_NewStringObj(hexcolor, -1));
3217 Tcl_ListObjAppendElement(interp, resObj,
3218 Tcl_NewStringObj(thc->val
3219 ? tstr = pattern_to_string(thc->val)
3220 : "", -1));
3221 if(tstr) fs_give((void **)&tstr);
3222 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
3223 resObj);
3225 fs_give((void **)&hcolors);
3226 return(TCL_OK);
3228 else {
3229 char *colorp;
3231 snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-foreground-color");
3233 for(vtmp = &wps_global->vars[V_NORM_FORE_COLOR];
3234 vtmp->name && strucmp(vtmp->name, tvname);
3235 vtmp++)
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;
3246 if(colorp){
3247 hex_colorstr(hexcolor, colorp);
3248 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
3249 Tcl_NewStringObj(hexcolor, -1));
3251 else
3252 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
3253 Tcl_NewStringObj("", -1));
3255 snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-background-color");
3256 vtmp++;
3257 if((vtmp->name && strucmp(vtmp->name, tvname)) || !vtmp->name)
3258 for(vtmp = &wps_global->vars[V_NORM_FORE_COLOR];
3259 vtmp->name && strucmp(vtmp->name, tvname);
3260 vtmp++)
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;
3271 if(colorp){
3272 hex_colorstr(hexcolor, colorp);
3273 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
3274 Tcl_NewStringObj(hexcolor, -1));
3276 else
3277 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
3278 Tcl_NewStringObj("", -1));
3280 return(TCL_OK);
3282 else if(!strcmp(s1, "cldel")){
3283 int cl, i, j, n;
3284 struct variable *vtmp;
3285 char **newl;
3287 if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR)
3288 return(TCL_ERROR);
3289 vtmp = &wps_global->vars[V_FOLDER_SPEC];
3290 for(i = 0; i < cl && (vtmp->is_changed_val
3291 ? (vtmp->changed_val.l && vtmp->changed_val.l[i])
3292 : (vtmp->current_val.l && vtmp->current_val.l[i])); i++);
3293 if(!(i == cl && (vtmp->is_changed_val
3294 ? (vtmp->changed_val.l && vtmp->changed_val.l[i])
3295 : (vtmp->current_val.l && vtmp->current_val.l[i])))){
3296 vtmp = &wps_global->vars[V_NEWS_SPEC];
3297 for(j = 0; i + j < cl && (vtmp->is_changed_val
3298 ? (vtmp->changed_val.l && vtmp->changed_val.l[j])
3299 : (vtmp->current_val.l && vtmp->current_val.l[j]));
3300 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])))
3304 return(TCL_ERROR);
3305 i = 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++){
3312 if(n < i)
3313 newl[n] = cpystr(vtmp->is_changed_val ? vtmp->changed_val.l[n]
3314 : vtmp->current_val.l[n]);
3315 else if(n > i)
3316 newl[n-1] = cpystr(vtmp->is_changed_val ? vtmp->changed_val.l[n]
3317 : vtmp->current_val.l[n]);
3319 newl[n-1] = NULL;
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;
3326 return(TCL_OK);
3328 else if(!strcmp(s1, "columns")){
3329 int n;
3330 char *p;
3332 if(Tcl_GetIntFromObj(interp, objv[2], &n) != TCL_ERROR
3333 && n >= MIN_SCREEN_COLS
3334 && n < (MAX_SCREEN_COLS - 1)
3335 && wps_global->ttyo->screen_cols != n){
3336 clear_index_cache(sp_inbox_stream(), 0);
3337 wps_global->ttyo->screen_cols = n;
3338 set_variable(V_WP_COLUMNS, p = int2string(n), 0, 0, Main);
3339 Tcl_SetResult(interp, p, TCL_VOLATILE);
3341 else
3342 Tcl_SetResult(interp, int2string(wps_global->ttyo->screen_cols), TCL_VOLATILE);
3344 return(TCL_OK);
3346 else if(!strcmp(s1, "reset")){
3347 char *p;
3349 if((p = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
3350 if(!strcmp(p,"pinerc")){
3351 struct variable *var;
3352 PINERC_S *prc;
3354 /* new pinerc structure, copy location pointers */
3355 prc = new_pinerc_s(wps_global->prc->name);
3356 prc->type = wps_global->prc->type;
3357 prc->rd = wps_global->prc->rd;
3358 prc->outstanding_pinerc_changes = 1;
3360 /* tie off original pinerc struct and free it */
3361 wps_global->prc->rd = NULL;
3362 wps_global->prc->outstanding_pinerc_changes = 0;
3363 free_pinerc_s(&wps_global->prc);
3365 /* set global->prc to new struct with no pinerc_lines
3366 * and fool write_pinerc into not writing changed vars
3368 wps_global->prc = prc;
3371 * write at least one var into nearly empty pinerc
3372 * and clear user's var settings. clear global cause
3373 * they'll get reset in peInitVars
3375 for(var = wps_global->vars; var->name != NULL; var++){
3376 var->been_written = ((var - wps_global->vars) != V_LAST_VERS_USED);
3377 if(var->is_list){
3378 free_list_array(&var->main_user_val.l);
3379 free_list_array(&var->global_val.l);
3381 else{
3382 fs_give((void **)&var->main_user_val.p);
3383 fs_give((void **)&var->global_val.p);
3387 write_pinerc(wps_global, Main, WRP_NOUSER | WRP_PRESERV_WRITTEN);
3389 peInitVars(wps_global);
3390 return(TCL_OK);
3395 else if(objc == 4){
3396 if(!strcmp(s1, "varset")){
3397 char *varname = Tcl_GetStringFromObj(objv[2], NULL);
3398 struct variable *vtmp;
3399 char **tstrlist = NULL, *line, *tline;
3400 Tcl_Obj **objVal;
3401 int i, strlistpos, numlistvals;
3403 if(varname == NULL) return(TCL_ERROR);
3404 for(vtmp = wps_global->vars;
3405 vtmp->name && strucmp(vtmp->name, varname);
3406 vtmp++)
3408 if(!vtmp->name){
3409 Tcl_SetResult(interp, err, TCL_VOLATILE);
3410 return(TCL_ERROR);
3412 if(Tcl_ListObjGetElements(interp, objv[3], &numlistvals,
3413 &objVal) != TCL_OK)
3414 return(TCL_ERROR);
3415 vtmp->is_changed_val = 1;
3416 if(vtmp->is_list){
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);
3422 if(numlistvals)
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);
3428 if(*tline)
3429 tstrlist[strlistpos++] = cpystr(tline);
3430 fs_give((void **) &tline);
3433 if(tstrlist)
3434 tstrlist[strlistpos] = NULL;
3435 vtmp->changed_val.l = tstrlist;
3437 else {
3438 if(vtmp->changed_val.p)
3439 fs_give((void **)&vtmp->changed_val.p);
3440 if(numlistvals){
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, "\"\"")){
3446 tline[0] = '\0';
3448 else if(tline[0] == '\0'){
3449 fs_give((void **)&tline);
3451 if(tline){
3452 vtmp->changed_val.p = cpystr(tline);
3453 fs_give((void **)&tline);
3456 else
3457 vtmp->changed_val.p = cpystr("");
3460 return(TCL_OK);
3462 else if(!strcmp(s1, "feature")){
3463 char *featurename;
3464 int i, set, wasset = 0;
3465 FEATURE_S *feature;
3468 * CMD: feature
3470 * ARGS: featurename -
3471 * value - new value to assign flag
3473 * Returns: 1 if named feature set, 0 otherwise
3476 if((featurename = Tcl_GetStringFromObj(objv[2], NULL))
3477 && Tcl_GetIntFromObj(interp, objv[3], &set) != TCL_ERROR)
3478 for(i = 0; (feature = feature_list(i)); i++)
3479 if(!strucmp(featurename, feature->name)){
3480 wps_global->vars[V_FEATURE_LIST].is_changed_val = 1;
3481 wasset = F_CH_ON(feature->id);
3482 F_CH_SET(feature->id, set);
3483 break;
3486 Tcl_SetResult(interp, int2string(wasset), TCL_VOLATILE);
3487 return(TCL_OK);
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)))
3495 return TCL_ERROR;
3496 if(Tcl_GetIntFromObj(interp, objv[3], &cl) == TCL_ERROR)
3497 return(TCL_ERROR);
3498 if(!strcmp(dir, "up"))
3499 up = 1;
3500 else if(!strcmp(dir, "down"))
3501 up = 0;
3502 else
3503 return(TCL_ERROR);
3504 fvar = &wps_global->vars[V_FOLDER_SPEC];
3505 nvar = &wps_global->vars[V_NEWS_SPEC];
3506 for(fvarn = 0; fvar->is_changed_val ? (fvar->changed_val.l && fvar->changed_val.l[fvarn])
3507 : (fvar->current_val.l && fvar->current_val.l[fvarn]); fvarn++);
3508 for(nvarn = 0; nvar->is_changed_val ? (nvar->changed_val.l && nvar->changed_val.l[nvarn])
3509 : (nvar->current_val.l && nvar->current_val.l[nvarn]); nvarn++);
3510 if(cl < fvarn){
3511 vtmp = fvar;
3512 icnt = cl;
3514 else if(cl >= fvarn && cl < nvarn + fvarn){
3515 vtmp = nvar;
3516 icnt = cl - fvarn;
3518 else
3519 return(TCL_ERROR);
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]);
3528 newl[i] = NULL;
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]);
3539 newl[i-1] = NULL;
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;
3545 vtmp = fvar;
3546 icnt = fvarn;
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]);
3554 newl[i] = NULL;
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 *));
3563 newl[0] = tstr;
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]);
3568 newl[i+1] = NULL;
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;
3574 vtmp = nvar;
3575 icnt = 0;
3577 else {
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]);
3583 newl[i] = NULL;
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;
3590 if(up){
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;
3595 else {
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;
3600 return(TCL_OK);
3603 else if(objc == 7){
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];
3607 char **newl;
3608 struct variable *vtmp;
3610 if(!strcmp(s1, "cladd")) add = 1;
3612 if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR)
3613 return(TCL_ERROR);
3614 if(!(nick = Tcl_GetStringFromObj(objv[3], NULL)))
3615 return TCL_ERROR;
3616 if(!(server = Tcl_GetStringFromObj(objv[4], NULL)))
3617 return TCL_ERROR;
3618 if(!(path = Tcl_GetStringFromObj(objv[5], NULL)))
3619 return TCL_ERROR;
3620 if(!(view = Tcl_GetStringFromObj(objv[6], NULL)))
3621 return TCL_ERROR;
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, ' '))
3627 quotes_needed = 1;
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);
3631 return TCL_ERROR;
3633 if(3 + strlen(nick) + strlen(server) + strlen(path) +
3634 strlen(view) > MAILTMPLEN + 4){
3635 Tcl_SetResult(interp, "collection fields too long", TCL_VOLATILE);
3636 return(TCL_OK);
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);
3642 if(add) {
3643 vtmp = &wps_global->vars[V_NEWS_SPEC];
3644 if(!(vtmp->is_changed_val ? (vtmp->changed_val.l && vtmp->changed_val.l[0])
3645 : (vtmp->current_val.l && vtmp->current_val.l[0])))
3646 vtmp = &wps_global->vars[V_FOLDER_SPEC];
3647 for(i = 0; vtmp->is_changed_val ? (vtmp->changed_val.l && vtmp->changed_val.l[i])
3648 : (vtmp->current_val.l && vtmp->current_val.l[i]); i++);
3649 newn = i + 1;
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);
3656 newl[i] = NULL;
3658 else {
3659 vtmp = &wps_global->vars[V_FOLDER_SPEC];
3660 for(i = 0; i < cl && (vtmp->is_changed_val
3661 ? (vtmp->changed_val.l && vtmp->changed_val.l[i])
3662 : (vtmp->current_val.l && vtmp->current_val.l[i])); i++);
3663 if(!(i == cl && (vtmp->is_changed_val
3664 ? (vtmp->changed_val.l && vtmp->changed_val.l[i])
3665 : (vtmp->current_val.l && vtmp->current_val.l[i])))){
3666 vtmp = &wps_global->vars[V_NEWS_SPEC];
3667 for(j = 0; i + j < cl && (vtmp->is_changed_val
3668 ? (vtmp->changed_val.l && vtmp->changed_val.l[j])
3669 : (vtmp->current_val.l && vtmp->current_val.l[j]));
3670 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])))
3674 return(TCL_ERROR);
3675 i = 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++){
3682 if(j == i)
3683 newl[j] = cpystr(context_buf);
3684 else
3685 newl[j] = cpystr(vtmp->is_changed_val ? vtmp->changed_val.l[j]
3686 : vtmp->current_val.l[j]);
3688 newl[j] = NULL;
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;
3695 return TCL_OK;
3698 else
3699 err = "PEInfo: Too many arguments";
3701 Tcl_SetResult(interp, err, TCL_STATIC);
3702 return(TCL_ERROR);
3707 peWriteSig(Tcl_Interp *interp, char *file, Tcl_Obj **objv)
3709 int try_cache, e, i, n, nSig;
3710 char datebuf[200], *sig, *line;
3711 FILE *fp;
3712 REMDATA_S *rd;
3713 Tcl_Obj **objSig;
3715 if(!(file && IS_REMOTE(file))){
3716 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Non-Remote signature file: %s",
3717 file ? file : "<null>");
3718 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
3719 return(TCL_ERROR);
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.");
3728 if(!rd){
3729 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Can't create stream for sig file: %s", file);
3730 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
3731 return(TCL_ERROR);
3734 try_cache = rd_read_metadata(rd);
3736 if(rd->access == MaybeRorW){
3737 if(rd->read_status == 'R')
3738 rd->access = ReadOnly;
3739 else
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;
3762 else{
3763 rd_close_remdata(&rd);
3764 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Readonly sig file: %s", file);
3765 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
3766 return(TCL_ERROR);
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.
3779 else{
3780 dprint((7, "%s: copied remote to local (%ld)",
3781 rd->rn, (long)rd->last_use));
3785 if(rd->access == ReadWrite)
3786 rd->flags |= DO_REMTRIM;
3789 /* If we couldn't get to remote folder, try using the cached copy */
3790 if(rd->access == NoExists || rd->flags & REM_OUTOFDATE){
3791 rd_close_remdata(&rd);
3792 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Unavailable sig file: %s", file);
3793 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
3794 return(TCL_ERROR);
3797 unlink(rd->lf);
3799 sig = NULL;
3800 wtmp_20k_buf[0] = '\0';
3801 if(objv){
3802 Tcl_ListObjGetElements(interp, objv[0], &nSig, &objSig);
3803 for(i = 0; i < nSig && i < SIG_MAX_LINES; i++){
3804 if((line = Tcl_GetStringFromObj(objSig[i], NULL)) != NULL)
3805 snprintf(wtmp_20k_buf + strlen(wtmp_20k_buf), SIZEOF_20KBUF - strlen(wtmp_20k_buf), "%.*s\n",
3806 SIG_MAX_COLS, line);
3809 else if(peTSig){
3810 for(i = 0; peTSig[i] && i < SIG_MAX_LINES; i++) {
3811 snprintf(wtmp_20k_buf + strlen(wtmp_20k_buf), SIZEOF_20KBUF - strlen(wtmp_20k_buf), "%.*s\n",
3812 SIG_MAX_COLS, peTSig[i]);
3814 for(i = 0; peTSig[i]; i++)
3815 fs_give((void **)&peTSig[i]);
3816 fs_give((void **)&peTSig);
3818 else
3819 return(TCL_ERROR);
3821 sig = cpystr(wtmp_20k_buf);
3823 if((fp = fopen(rd->lf, "w")) != NULL)
3824 n = fwrite(sig, strlen(sig), 1, fp);
3826 fs_give((void **) &sig);
3828 if(fp){
3829 if(n != 1){
3830 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Sig copy failure1: %s: %s",
3831 rd->lf, error_description(errno));
3832 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
3833 rd_close_remdata(&rd);
3836 fclose(fp);
3837 if(n != 1)
3838 return(TCL_ERROR);
3840 else {
3841 rd_close_remdata(&rd);
3842 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Sig copy open failure2: %s: %s",
3843 rd->lf, error_description(errno));
3844 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
3845 return(TCL_ERROR);
3848 datebuf[0] = '\0';
3850 if(!rd->t.i.stream){
3851 long retflags = 0;
3853 rd->t.i.stream = context_open(NULL, NULL, rd->rn, 0L, &retflags);
3856 if((e = rd_update_remote(rd, datebuf)) != 0){
3857 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Sig update failure: %s: %s",
3858 rd->lf, error_description(errno));
3859 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
3860 rd_close_remdata(&rd);
3861 return(TCL_ERROR);
3864 rd_update_metadata(rd, datebuf);
3865 rd->read_status = 'W';
3866 rd_close_remdata(&rd);
3867 return(TCL_OK);
3872 NAMEVAL_S *sort_key_rules(index)
3873 int index;
3875 static NAMEVAL_S is_rules[] = {
3876 {"Arrival", 0},
3877 {"Date", 0},
3878 {"Subject", 0},
3879 {"Cc", 0},
3880 {"From", 0},
3881 {"To", 0},
3882 {"size", 0},
3883 {"OrderedSubj", 0},
3884 {"tHread", 0},
3885 {"Arrival/Reverse", 0},
3886 {"Date/Reverse", 0},
3887 {"Subject/Reverse", 0},
3888 {"Cc/Reverse", 0},
3889 {"From/Reverse", 0},
3890 {"To/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)
3901 int 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[])
3922 char *s;
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")){
3929 if(objc == 2){
3930 int level;
3932 if(Tcl_GetIntFromObj(interp, objv[2], &level) != TCL_OK)
3933 return(TCL_ERROR);
3935 if(level > 0){
3936 if(level > 10)
3937 level = 10;
3939 debug = level;
3940 dprint((1, "Debug level %d", level));
3942 else{
3943 dprint((1, "PEDebug ending"));
3944 debug = 0;
3948 Tcl_SetResult(interp, int2string(debug), TCL_VOLATILE);
3949 return(TCL_OK);
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));
3961 return(TCL_OK);
3963 else if(!strucmp(s, "imap")){
3964 int level;
3966 if(Tcl_GetIntFromObj(interp, objv[2], &level) != TCL_OK)
3967 return(TCL_ERROR);
3969 if(level == 0){
3970 if(wps_global){
3971 wps_global->debug_imap = 0;
3972 if(wps_global->mail_stream)
3973 mail_nodebug(wps_global->mail_stream);
3976 else if(level > 0 && level < 5){
3977 if(wps_global){
3978 wps_global->debug_imap = level;
3979 if(wps_global->mail_stream)
3980 mail_debug(wps_global->mail_stream);
3984 return(TCL_OK);
3986 else
3987 Tcl_SetResult(interp, "Unknown PEDebug request", TCL_STATIC);
3990 return(TCL_ERROR);
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;
4002 int pe_alt, l;
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");
4020 return(TCL_ERROR);
4023 if(!(s = Tcl_GetStringFromObj(objv[2], &l))){
4024 Tcl_SetResult(interp, "Unknown User", TCL_STATIC);
4025 return(TCL_ERROR);
4027 else{
4028 int rv;
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);
4041 else
4042 snprintf(putenvbuf, PUTENV_MAX, "WPUSER=%s", pe_user);
4044 rv = putenv(putenvbuf);
4046 else
4047 rv = 1;
4049 #endif
4051 if(rv){
4052 fs_give((void **) &pe_user);
4053 Tcl_SetResult(interp, (errno == ENOMEM)
4054 ? "Insufficient Environment Space"
4055 : "Cannot set WPUSER in environment", TCL_STATIC);
4056 return(TCL_ERROR);
4060 if((pinerc = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){
4061 NETMBX mb;
4063 if(mail_valid_net_parse(pinerc, &mb)){
4064 pe_host = cpystr(mb.host);
4065 pe_alt = (mb.sslflag || mb.tlsflag);
4067 else {
4068 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Non-Remote Config: %s", pinerc);
4069 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
4070 return(TCL_ERROR);
4073 else {
4074 Tcl_SetResult(interp, "Unknown config location", TCL_STATIC);
4075 return(TCL_ERROR);
4078 if(objc == 5 && !(pineconf = Tcl_GetStringFromObj(objv[4], NULL))){
4079 Tcl_SetResult(interp, "Can't determine global config", TCL_STATIC);
4080 return(TCL_ERROR);
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 */
4089 if(wps_global){
4090 /* destroy open stream */
4091 peDestroyStream(wps_global);
4093 /* destroy old user context */
4094 peDestroyUserContext(&wps_global);
4097 /* Establish a user context */
4098 if((s = peCreateUserContext(interp, pe_user, pinerc, pineconf)) != NULL){
4099 Tcl_SetResult(interp, s, TCL_VOLATILE);
4100 return(TCL_ERROR);
4103 fs_give((void **) &pe_user);
4104 fs_give((void **) &pe_host);
4106 return(TCL_OK);
4108 else if(!strcmp(op, "close")){
4109 if(wps_global){
4110 /* destroy any open stream */
4111 peDestroyStream(wps_global);
4113 /* destroy user context */
4114 peDestroyUserContext(&wps_global);
4117 Tcl_SetResult(interp, "BYE", TCL_STATIC);
4118 return(TCL_OK);
4120 else if(!strcmp(op, "creds")){
4121 char *folder;
4122 int colid;
4124 if(objc < 4){
4125 err = "creds: insufficient args";
4127 else if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR
4128 && (folder = Tcl_GetStringFromObj(objv[3], NULL))){
4129 int i;
4130 CONTEXT_S *cp;
4133 * CMD: creds <collection-index> <folder> [user passwd]
4135 * Test for valid credentials to access given folder
4137 * Returns: 1 if so, 0 otherwise
4140 for(i = 0, cp = wps_global ? wps_global->context_list : NULL;
4141 i < 1 || cp != NULL ;
4142 i++, cp = cp->next)
4143 if(i == colid){
4144 int rv = 0;
4145 char tmp[MAILTMPLEN], *p;
4147 if(cp){
4148 if(folder[0] == '\0'){
4149 if(cp->use & CNTXT_INCMNG)
4150 rv = 1;
4151 else
4152 folder = "fake-fake";
4154 else if((cp->use & CNTXT_INCMNG)
4155 && (p = folder_is_nick(folder, FOLDERS(cp), FN_NONE)))
4156 folder = p;
4159 if(!rv && context_allowed(context_apply(tmp, cp, folder, sizeof(tmp)))){
4160 NETMBX mb;
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))))
4165 strcpy(mb.user, p);
4167 if(alpine_have_passwd(mb.user, mb.host, (mb.sslflag || mb.tlsflag)))
4168 rv = 1;
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";
4177 break;
4180 alpine_set_passwd(user, passwd, mb.host,
4181 mb.sslflag
4182 || mb.tlsflag
4183 || (wps_global ? F_ON(F_PREFER_ALT_AUTH, wps_global) : 0));
4184 rv = 1;
4186 else {
4187 err = "creds: unable to read credentials";
4188 break;
4191 else{
4192 err = "creds: invalid args";
4193 break;
4198 (void) Tcl_ListObjAppendElement(interp,
4199 Tcl_GetObjResult(interp),
4200 Tcl_NewIntObj(rv));
4201 return(TCL_OK);
4204 err = "creds: Unrecognized collection ID";
4206 else
4207 err = "creds: failure to acquire folder and collection ID";
4209 else if(!strcmp(op, "nocred")){
4210 char *folder;
4211 int colid;
4213 if(!wps_global){
4214 err = "No Session active";
4216 else if(objc != 4){
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))){
4221 int i;
4222 CONTEXT_S *cp;
4225 * CMD: nocred <collection-index> <folder>
4227 * Test for valid credentials to access given folder
4229 * Returns: 1 if so, 0 otherwise
4232 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
4233 if(i == colid){
4234 int rv = 0;
4235 char tmp[MAILTMPLEN], *p;
4237 if((cp->use & CNTXT_INCMNG)
4238 && (p = folder_is_nick(folder, FOLDERS(cp), FN_NONE)))
4239 folder = p;
4241 if(context_allowed(context_apply(tmp, cp, folder, sizeof(tmp)))){
4242 NETMBX mb;
4244 if(mail_valid_net_parse(tmp, &mb)){
4245 if(!*mb.user && (p = alpine_get_user(mb.host, (mb.sslflag || mb.tlsflag))))
4246 strcpy(mb.user, p);
4248 alpine_clear_passwd(mb.user, mb.host);
4252 (void) Tcl_ListObjAppendElement(interp,
4253 Tcl_GetObjResult(interp),
4254 Tcl_NewIntObj(rv));
4255 return(TCL_OK);
4258 err = "creds: Unrecognized collection ID";
4260 else
4261 err = "creds: failure to acquire folder and collection ID";
4263 else if(!strcmp(op, "acceptcert")){
4264 char *certhost;
4265 STRLIST_S **p;
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")){
4277 if(objc != 3){
4278 err = "PESession: random <length>";
4279 } else {
4280 char s[1025];
4281 int l;
4283 if(Tcl_GetIntFromObj(interp,objv[2],&l) != TCL_ERROR){
4284 if(l <= 1024){
4285 Tcl_SetResult(interp, peRandomString(s,l,PRS_MIXED_CASE), TCL_STATIC);
4286 return(TCL_OK);
4288 else
4289 err = "PESession: random length too long";
4291 else
4292 err = "PESession: can't get random length";
4295 else if(!strcmp(op, "authdriver")){
4296 if(objc != 4){
4297 err = "PESession: authdriver {add | remove} drivername";
4298 } else {
4299 char *cmd, *driver;
4301 if((cmd = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
4302 if((driver = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){
4303 if(!strcmp(cmd,"enable")){
4304 err = "PESession: authdriver enable disabled for the nonce";
4306 else if(!strcmp(cmd,"disable")){
4307 if(mail_parameters(NULL, DISABLE_AUTHENTICATOR, (void *) driver)){
4308 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Authentication driver %.30s disabled", driver);
4309 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
4310 return(TCL_OK);
4312 else{
4313 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "PESession: Can't disable %.30s", driver);
4314 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
4315 return(TCL_ERROR);
4318 else
4319 err = "PESession: unknown authdriver operation";
4321 else
4322 err = "PESession: Can't read driver name";
4324 else
4325 err = "PESesions: Can't read authdriver operation";
4328 else if(!strcmp(op, "abandon")){
4330 * CMD: abandon [timeout]
4332 * Returns: nothing
4335 if(objc != 3){
4336 err = "PESession: abandon [timeout]";
4337 } else {
4338 long t;
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;
4344 return(TCL_OK);
4346 else
4347 err = "unrecognized timeout";
4349 else
4350 err = "Can't read timeout";
4353 else if(!strcmp(op, "noexpunge")){
4355 * CMD: noexpunge <state>
4357 * Returns: nothing
4360 if(objc != 3){
4361 err = "PESession: noexpunge <state>";
4362 } else {
4363 int onoff;
4365 if(Tcl_GetIntFromObj(interp, objv[2], &onoff) == TCL_OK){
4366 if(onoff == 0 || onoff == 1){
4367 wps_global->noexpunge_on_close = onoff;
4368 return(TCL_OK);
4371 err = "unrecognized on/off state";
4373 else
4374 err = "Can't read on/off state";
4377 else if(!strcmp(op, "setpassphrase")){
4378 #ifdef SMIME
4379 char *passphrase;
4381 if(objc != 3){
4382 err = "PESession: setpassphrase <state>";
4384 else if((passphrase = Tcl_GetStringFromObj(objv[2], NULL))){
4385 if(wps_global && wps_global->smime){
4386 strncpy((char *) wps_global->smime->passphrase, passphrase,
4387 sizeof(wps_global->smime->passphrase));
4388 wps_global->smime->passphrase[sizeof(wps_global->smime->passphrase)-1] = '\0';
4389 wps_global->smime->entered_passphrase = 1;
4390 wps_global->smime->need_passphrase = 0;
4391 peED.uid = 0;
4392 return(TCL_OK);
4395 #else
4396 err = "S/MIME not configured for this server";
4397 #endif /* SMIME */
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}
4406 char *type;
4407 long delete_count;
4408 Tcl_Obj *resObj;
4410 if(objc != 3){
4411 err = "PESession: expungecheck <type>";
4413 else {
4414 type = Tcl_GetStringFromObj(objv[2], NULL);
4415 if(type && (strcmp(type, "current") == 0 || strcmp(type, "quit") == 0)){
4417 if(wps_global->mail_stream != sp_inbox_stream()
4418 || strcmp(type, "current") == 0){
4419 delete_count = count_flagged(wps_global->mail_stream, F_DEL);
4420 resObj = Tcl_NewListObj(0, NULL);
4421 Tcl_ListObjAppendElement(interp, resObj,
4422 Tcl_NewStringObj(pretty_fn(wps_global->cur_folder), -1));
4423 Tcl_ListObjAppendElement(interp, resObj,
4424 Tcl_NewIntObj(delete_count));
4425 Tcl_ListObjAppendElement(interp, resObj,
4426 Tcl_NewIntObj((wps_global->mail_stream
4427 == sp_inbox_stream())
4428 ? 1 : 0));
4429 Tcl_ListObjAppendElement(interp, resObj,
4430 Tcl_NewIntObj((wps_global->context_current->use & CNTXT_INCMNG)
4431 ? 1 : 0));
4432 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
4433 resObj);
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,
4443 Tcl_NewIntObj(1));
4444 Tcl_ListObjAppendElement(interp, resObj,
4445 Tcl_NewIntObj(1));
4446 Tcl_ListObjAppendElement(interp,
4447 Tcl_GetObjResult(interp), resObj);
4449 return(TCL_OK);
4451 else
4452 err = "PESession: expungecheck unknown type";
4455 else if(!strcmp(op, "mailcheck")) {
4457 * CMD: 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);
4471 if(objc <= 3){
4472 if(objc < 3 || Tcl_GetIntFromObj(interp, objv[2], &reload) == TCL_ERROR)
4473 reload = 0;
4475 /* minimum 10 second between IMAP pings */
4476 if(!time_of_last_input() || now - time_of_last_input() > 10){
4477 force = UFU_FORCE;
4478 if(!reload)
4479 peMarkInputTime();
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();
4491 return(TCL_OK);
4493 else
4494 err = "PESession: mailcheck <reload>";
4498 Tcl_SetResult(interp, err, TCL_STATIC);
4499 return(TCL_ERROR);
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[])
4514 int i;
4515 FDIR_S *fp;
4516 char *folder;
4518 for(i = 0; i < objc; i++) {
4519 folder = Tcl_GetStringFromObj(objv[i], NULL);
4520 if(!folder) {
4521 Tcl_SetResult(interp, "PEFolderChange: Can't read folder", TCL_VOLATILE);
4522 reset_context_folders(cp);
4523 return(TCL_ERROR);
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;
4529 fp->prev = cp->dir;
4530 fp->status |= CNTXT_SUBDIR;
4531 cp->dir = fp;
4534 return(TCL_OK);
4538 * PEMakeFolderString:
4541 PEMakeFolderString(Tcl_Interp *interp, CONTEXT_S *cp, int objc, Tcl_Obj *CONST objv[], char **ppath)
4543 int i;
4544 unsigned long size,len;
4545 char *portion,*path;
4547 size = 0;
4548 for(i = 0; i < objc; i++) {
4549 portion = Tcl_GetStringFromObj(objv[i], NULL);
4550 if(!portion) {
4551 Tcl_SetResult(interp, "PEMakeFolderString: Can't read folder",
4552 TCL_VOLATILE);
4553 return(TCL_ERROR);
4555 if(i) size++;
4556 size += strlen(portion);
4559 path = (char*) fs_get(size + 1);
4560 size = 0;
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);
4566 size += len;
4568 path[size] = '\0';
4569 if(ppath) *ppath = path; else fs_give((void**) &path);
4570 return(TCL_OK);
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"));
4584 if(objc == 1){
4585 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
4587 else if((op = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){
4588 if(wps_global){
4589 if(objc == 2){
4590 if(!strcmp(op, "current")){
4591 CONTEXT_S *cp;
4592 int i;
4595 * CMD: current
4597 * Returns: string representing the name of the
4598 * current mailbox
4601 for(i = 0, cp = wps_global->context_list; cp && cp != wps_global->context_current; i++, cp = cp->next)
4604 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewIntObj(cp ? i : 0)) == TCL_OK
4605 && Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(wps_global->cur_folder,-1)) == TCL_OK)
4606 return(TCL_OK);
4608 return(TCL_ERROR);
4610 else if(!strcmp(op, "collections")){
4611 CONTEXT_S *cp;
4612 int i;
4615 * CMD: collections
4617 * Returns: List of currently configured collections
4619 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next){
4620 Tcl_Obj *objv[3];
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));
4630 return(TCL_OK);
4632 else if(!strcmp(op, "defaultcollection")){
4633 int i;
4634 CONTEXT_S *cp;
4636 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
4637 if(cp->use & CNTXT_SAVEDFLT){
4638 Tcl_SetResult(interp, int2string(i), TCL_STATIC);
4639 return(TCL_OK);
4642 err = "PEFolder: isincoming: Invalid collection ID";
4644 else if(!strcmp(op, "clextended")){
4645 CONTEXT_S *cp;
4646 int i;
4647 char tpath[MAILTMPLEN], *p;
4650 * CMD: clextended
4652 * Returns: Extended list of current collections
4654 * Format:
4655 * 0) Collection Number
4656 * 1) Nickname
4657 * 2) Label
4658 * 3) Basically this is a flag to say if we can edit
4659 * 4) Server
4660 * 5) Path
4661 * 6) View
4664 * had to get rid of this cause the args are changed
4666 * if(strcmp("extended",
4667 * Tcl_GetStringFromObj(objv[2], NULL))){
4668 * Tcl_SetResult(interp, "invalid argument", TCL_VOLATILE);
4669 * return(TCL_ERROR);
4672 for(i = 0, cp = wps_global->context_list; cp ;
4673 i++, cp = cp->next){
4674 Tcl_Obj *objv[7];
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);
4684 tpath[0] = '\0';
4685 if(cp->context){
4686 strncpy(tpath, (cp->context[0] == '{'
4687 && (p = strchr(cp->context, '}')))
4688 ? ++p
4689 : cp->context, sizeof(tpath));
4690 tpath[sizeof(tpath)-1] = '\0';
4691 if((p = strstr(tpath, "%s")) != NULL)
4692 *p = '\0';
4694 objv[5] = Tcl_NewStringObj(tpath, -1);
4695 objv[6] = Tcl_NewStringObj(cp->dir &&
4696 cp->dir->view.user ?
4697 cp->dir->view.user :
4698 "", -1);
4699 Tcl_ListObjAppendElement(interp,
4700 Tcl_GetObjResult(interp),
4701 Tcl_NewListObj(7, objv));
4704 return(TCL_OK);
4707 else if(objc == 3 && !strcmp(op, "delimiter")){
4708 int colid, i;
4709 char delim[2] = {'\0', '\0'};
4710 CONTEXT_S *cp;
4712 if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){
4713 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
4714 if(i == colid){
4715 if(cp->dir && cp->dir->delim)
4716 delim[0] = cp->dir->delim;
4718 break;
4721 Tcl_SetResult(interp, delim[0] ? delim : "/", TCL_VOLATILE);
4722 return(TCL_OK);
4724 else
4725 err = "PEFolder: delimiter: Can't read collection ID";
4727 else if(objc == 3 && !strcmp(op, "isincoming")){
4728 int colid, i;
4729 CONTEXT_S *cp;
4731 if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){
4732 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
4733 if(i == colid){
4734 Tcl_SetResult(interp, int2string(((cp->use & CNTXT_INCMNG) != 0)), TCL_STATIC);
4735 return(TCL_OK);
4738 err = "PEFolder: isincoming: Invalid collection ID";
4740 else
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;
4746 CONTEXT_S *cp;
4747 long colid, i, count = 0, flags = (F_UNSEEN | F_UNDEL);
4748 int our_stream = 0;
4750 * CMD: unread
4752 * Returns: number of unread messages in given
4753 * folder
4755 if(Tcl_GetLongFromObj(interp,objv[2],&colid) != TCL_ERROR){
4756 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
4757 if(i == colid)
4758 break;
4760 if(cp){
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);
4766 else{
4768 * BUG: some sort of caching to prevent open() fore each call?
4769 * does stream cache offset this?
4771 if(!(context_allowed(context_apply(tmp, cp, folder, sizeof(tmp)))
4772 && (mstream = same_stream_and_mailbox(tmp, wps_global->mail_stream)))){
4773 long retflags = 0;
4775 wps_global->noshow_error = 1;
4776 our_stream = 1;
4777 mstream = context_open(cp, NULL, folder,
4778 SP_USEPOOL | SP_TEMPUSE| OP_READONLY | OP_SHORTCACHE,
4779 &retflags);
4780 wps_global->noshow_error = 0;
4783 count = count_flagged(mstream, flags);
4785 if(our_stream)
4786 pine_mail_close(mstream);
4789 Tcl_SetResult(interp, long2string(count), TCL_VOLATILE);
4790 return(TCL_OK);
4793 else
4794 err = "PEFolder: unread: Invalid collection ID";
4796 else
4797 err = "PEFolder: unread: Can't read collection ID";
4799 else if(objc == 5 && !strcmp(op, "empty")){
4801 * CMD: empty
4803 * Returns: number of expunge messages
4805 * Arguments: <colnum> <folder> <what>
4806 * where <what> is either <uid>, 'selected', or 'all'
4808 CONTEXT_S *cp;
4809 MAILSTREAM *stream = NULL;
4810 MESSAGECACHE *mc;
4811 MSGNO_S *msgmap;
4812 int colid, i, our_stream = 0;
4813 long uid, raw, count = 0L;
4814 char *errstr = NULL, *what, *folder, *p, tmp[MAILTMPLEN];
4816 if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){
4817 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
4818 if(i == colid) break;
4821 if(cp){
4822 if((folder = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){
4823 if((what = Tcl_GetStringFromObj(objv[4], NULL)) != NULL){
4824 /* need to open? */
4825 if(!((context_allowed(context_apply(tmp, cp, folder, sizeof(tmp)))
4826 && (stream = same_stream_and_mailbox(tmp, wps_global->mail_stream)))
4827 || (stream = same_stream_and_mailbox(tmp, sp_inbox_stream())))){
4828 long retflags = 0;
4830 our_stream = 1;
4831 stream = context_open(cp, NULL, folder, SP_USEPOOL | SP_TEMPUSE | OP_SHORTCACHE, &retflags);
4834 if(stream){
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);
4841 if(!errstr)
4842 (void) cmd_expunge_work(stream, msgmap, NULL);
4845 else{
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
4856 && mc->deleted){
4857 set_lflag(stream, msgmap, uid, MN_STMP, 1);
4858 mail_flag(stream, long2string(raw), "\\DELETED", 0L);
4860 else
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);
4869 else
4870 count = 0L;
4872 else{
4873 uid = 0;
4874 for(p = what; *p; p++)
4875 if(isdigit((unsigned char) *p)){
4876 uid = (uid * 10) + (*p - '0');
4878 else{
4879 errstr = "Invalid uid value";
4880 break;
4883 if(!errstr && uid){
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);
4887 count = 1L;
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);
4901 if(our_stream)
4902 pine_mail_close(stream);
4904 else
4905 errstr = "no stream";
4907 else
4908 errstr = "Cannot get which ";
4910 else
4911 errstr = "Cannot get folder";
4913 else
4914 errstr = "Invalid collection";
4916 if(errstr){
4917 Tcl_SetResult(interp, errstr, TCL_VOLATILE);
4918 return(TCL_ERROR);
4921 Tcl_SetResult(interp, long2string(count), TCL_VOLATILE);
4922 return(TCL_OK);
4924 else if(!strcmp(op, "export")){
4926 * CMD: export
4928 * Returns: success or failure after writing given
4929 * folder to given local file.
4931 * Format:
4932 * 0) Collection Number
4933 * 1) Folder
4934 * 2) Destination file
4936 if(objc == 5){
4937 CONTEXT_S *cp;
4938 MAILSTREAM *src;
4939 APPEND_PKG pkg;
4940 STRING msg;
4941 long colid, i;
4942 char *folder, *dfile, seq[64], tmp[MAILTMPLEN];
4943 int our_stream = 0;
4945 if(Tcl_GetLongFromObj(interp,objv[2],&colid) != TCL_ERROR){
4946 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
4947 if(i == colid)
4948 break;
4950 if(cp){
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.
4967 * comments:
4968 * - BUG: what about logins?
4971 if(!(context_allowed(context_apply(tmp, cp, folder, sizeof(tmp)))
4972 && (src = same_stream_and_mailbox(tmp, wps_global->mail_stream)))){
4973 long retflags = 0;
4975 our_stream = 1;
4976 src = context_open(cp, NULL, folder,
4977 SP_USEPOOL | SP_TEMPUSE | OP_READONLY | OP_SHORTCACHE,
4978 &retflags);
4981 if(src && src->nmsgs){
4982 /* Go to work...*/
4983 pkg.stream = src;
4984 pkg.msgno = 0;
4985 pkg.msgmax = src->nmsgs;
4986 pkg.flags = pkg.date = NIL;
4987 pkg.message = &msg;
4989 snprintf (seq,sizeof(seq),"1:%lu",src->nmsgs);
4990 mail_fetchfast (src, seq);
4992 wps_global->noshow_error = 1;
4993 if(!mail_append_multiple (NULL, dfile,
4994 peAppendMsg, (void *) &pkg)){
4995 snprintf(err = errbuf, sizeof(errbuf), "PEFolder: export: %.200s",
4996 wps_global->c_client_error);
4999 wps_global->noshow_error = 0;
5001 if(our_stream)
5002 pine_mail_close(src);
5004 else
5005 err = "PEFolder: export: can't open mail folder";
5007 if(!err)
5008 return(TCL_OK);
5010 else
5011 err = "PEFolder: export: can't create destination";
5013 if(!mail_parameters(NULL, DISABLE_DRIVER, "unix"))
5014 err = "PEFolder: export: can't disable driver";
5016 else
5017 err = "PEFolder: export: can't enable driver";
5019 else
5020 err = "PEFolder: export: can't read file name";
5022 else
5023 err = "PEFolder: export: can't read folder name";
5025 else
5026 err = "PEFolder: export: Invalid collection ID";
5028 else
5029 err = "PEFolder:export: Can't read collection ID";
5031 else
5032 err = "PEFolder: export <colid> <folder> <file>";
5034 else if(!strcmp(op, "import")){
5036 * CMD: import
5038 * Returns: success or failure after writing given
5039 * folder to given local file.
5041 * Format:
5042 * 0) source file
5043 * 1) destination collection number
5044 * 2) destination folder
5046 if(objc == 5){
5047 CONTEXT_S *cp;
5048 MAILSTREAM *src, *dst;
5049 APPEND_PKG pkg;
5050 STRING msg;
5051 long colid, i;
5052 char *folder, *sfile, seq[64];
5054 /* get source file with a little sanity check */
5055 if((sfile = Tcl_GetStringFromObj(objv[2], NULL))
5056 && *sfile == '/' && !strstr(sfile, "..")){
5057 if(mail_parameters(NULL, ENABLE_DRIVER, "unix")){
5059 wps_global->noshow_error = 1; /* don't queue error msg */
5060 err = NULL; /* reset error condition */
5062 /* make sure sfile contains valid mail */
5063 if((src = mail_open(NULL, sfile, 0L)) != NULL){
5065 if(Tcl_GetLongFromObj(interp,objv[3],&colid) != TCL_ERROR){
5066 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
5067 if(i == colid)
5068 break;
5070 if(cp){
5071 if((folder = Tcl_GetStringFromObj(objv[4], NULL)) != NULL){
5072 long retflags = 0;
5074 if(context_create(cp, NULL, folder)
5075 && (dst = context_open(cp, NULL, folder, SP_USEPOOL | SP_TEMPUSE, &retflags))){
5077 if(src->nmsgs){
5078 /* Go to work...*/
5079 pkg.stream = src;
5080 pkg.msgno = 0;
5081 pkg.msgmax = src->nmsgs;
5082 pkg.flags = pkg.date = NIL;
5083 pkg.message = &msg;
5085 snprintf (seq,sizeof(seq),"1:%lu",src->nmsgs);
5086 mail_fetchfast (src, seq);
5088 if(!context_append_multiple(cp, dst, folder,
5089 peAppendMsg, (void *) &pkg,
5090 wps_global->mail_stream)){
5091 snprintf(err = errbuf, sizeof(errbuf), "PEFolder: import: %.200s",
5092 wps_global->c_client_error);
5097 pine_mail_close(dst);
5099 else
5100 snprintf(err = errbuf, sizeof(errbuf), "PEFolder: import: %.200s",
5101 wps_global->c_client_error);
5103 else
5104 err = "PEFolder: import: can't read folder name";
5106 else
5107 err = "PEFolder:import: invalid collection id";
5109 else
5110 err = "PEFolder: import: can't read collection id";
5112 mail_close(src);
5115 else
5116 snprintf(err = errbuf, sizeof(errbuf), "PEFolder: import: %.200s",
5117 wps_global->c_client_error);
5119 wps_global->noshow_error = 0;
5121 if(!mail_parameters(NULL, DISABLE_DRIVER, "unix") && !err)
5122 err = "PEFolder: import: can't disable driver";
5124 if(!err)
5125 return(TCL_OK);
5127 else
5128 err = "PEFolder: import: can't enable driver";
5130 else
5131 err = "PEFolder: import: can't read file name";
5133 else
5134 err = "PEFolder: import <file> <colid> <folder>";
5136 else {
5137 int i, colid;
5138 char *aes, *colstr;
5139 CONTEXT_S *cp;
5142 * 3 or more arguments, 3rd is the collection ID, rest
5143 * are a folder name
5146 if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){
5147 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
5148 if(i == colid) break;
5150 else if((colstr = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
5151 if(!strcmp("default", colstr))
5152 cp = default_save_context(wps_global->context_list);
5153 else
5154 cp = NULL;
5156 else
5157 cp = NULL;
5159 if(cp){
5160 if(!strcmp(op, "list")){
5161 int i, fcount, bflags = BFL_NONE;
5163 if(PEFolderChange(interp, cp, objc - 3, objv + 3) == TCL_ERROR)
5164 return TCL_ERROR;
5166 if(cp->use & CNTXT_NEWS)
5167 bflags |= BFL_LSUB;
5169 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
5171 pePrepareForAuthException();
5173 build_folder_list(NULL, cp, "*", NULL, bflags);
5175 if((aes = peAuthException()) != NULL){
5176 Tcl_SetResult(interp, aes, TCL_VOLATILE);
5177 reset_context_folders(cp);
5178 return(TCL_ERROR);
5181 if((fcount = folder_total(FOLDERS(cp))) != 0){
5182 for(i = 0; i < fcount; i++){
5183 char type[3], *p;
5184 FOLDER_S *f = folder_entry(i, FOLDERS(cp));
5186 p = type;
5187 if(f->isdir){
5188 *p++ = 'D';
5190 if(f->hasnochildren && !f->haschildren)
5191 *p++ = 'E';
5194 if(f->isfolder
5195 || f->nickname
5196 || (cp->use & CNTXT_INCMNG))
5197 *p++ = 'F';
5199 *p = '\0';
5201 peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", type,
5202 f->nickname ? f->nickname : f->name);
5206 reset_context_folders(cp);
5207 return(TCL_OK);
5209 else if(!strucmp(op, "exists")){
5210 char *folder, *errstr = NULL;
5211 int rv;
5213 if(objc < 4) {
5214 Tcl_SetResult(interp, "PEFolder exists: No folder specified", TCL_VOLATILE);
5215 return(TCL_ERROR);
5217 folder = Tcl_GetStringFromObj(objv[objc - 1], NULL);
5218 if(!folder) {
5219 Tcl_SetResult(interp, "PEFolder exists: Can't read folder", TCL_VOLATILE);
5220 return(TCL_ERROR);
5223 if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR)
5224 return TCL_ERROR;
5226 wps_global->c_client_error[0] = '\0';
5227 pePrepareForAuthException();
5229 rv = folder_name_exists(cp, folder, NULL);
5231 if(rv & FEX_ERROR){
5232 if((errstr = peAuthException()) == NULL){
5233 if(wps_global->c_client_error[0])
5234 errstr = wps_global->c_client_error;
5235 else
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;
5246 if(objc < 4) {
5247 Tcl_SetResult(interp, "PEFolder fullname: No folder specified", TCL_VOLATILE);
5248 return(TCL_ERROR);
5250 folder = Tcl_GetStringFromObj(objv[objc - 1], NULL);
5251 if(!folder) {
5252 Tcl_SetResult(interp, "PEFolder fullname: Can't read folder", TCL_VOLATILE);
5253 return(TCL_ERROR);
5256 if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR)
5257 return TCL_ERROR;
5259 #if 0
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),
5264 obj);
5265 #else
5266 Tcl_SetResult(interp,
5267 (fullname = folder_is_nick(folder, FOLDERS(cp), FN_NONE)) ? fullname : folder,
5268 TCL_VOLATILE);
5269 #endif
5271 return(TCL_OK);
5273 else if(!strucmp(op, "create")){
5274 char *aes, *folder;
5276 folder = Tcl_GetStringFromObj(objv[objc - 1], NULL);
5277 if(!folder) {
5278 Tcl_SetResult(interp, "PEFolder create: Can't read folder", TCL_VOLATILE);
5279 return(TCL_ERROR);
5282 if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR)
5283 return TCL_ERROR;
5285 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
5286 pePrepareForAuthException();
5288 if(!context_create(cp, NULL, folder)){
5289 if((aes = peAuthException()) != NULL){
5290 Tcl_SetResult(interp, aes, TCL_VOLATILE);
5292 else{
5293 Tcl_SetResult(interp,
5294 (wps_global->last_error[0])
5295 ? wps_global->last_error
5296 : (wps_global->c_client_error[0])
5297 ? wps_global->c_client_error
5298 : "Unable to create folder",
5299 TCL_VOLATILE);
5302 reset_context_folders(cp);
5303 return(TCL_ERROR);
5306 Tcl_SetResult(interp, "OK", TCL_STATIC);
5307 reset_context_folders(cp);
5308 return(TCL_OK);
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;
5314 EditWhich ew;
5315 PINERC_S *prc = NULL;
5316 FOLDER_S *fp;
5318 folder = Tcl_GetStringFromObj(objv[objc - 1], NULL);
5319 if(!folder) {
5320 Tcl_SetResult(interp, "PEFolder delete: Can't read folder", TCL_VOLATILE);
5321 return(TCL_ERROR);
5324 if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR)
5325 return TCL_ERROR;
5327 /* so we can check for folder's various properties */
5328 build_folder_list(NULL, cp, folder, NULL, BFL_NONE);
5330 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
5332 pePrepareForAuthException();
5334 /* close open folder, then delete */
5336 if((fi = folder_index(folder, cp, FI_FOLDER)) < 0
5337 || (fp = folder_entry(fi, FOLDERS(cp))) == NULL){
5338 Tcl_SetResult(interp, "Cannot find folder to delete", TCL_STATIC);
5339 reset_context_folders(cp);
5340 return(TCL_ERROR);
5343 if(!((cp->use & CNTXT_INCMNG) && fp->name
5344 && check_for_move_mbox(fp->name, NULL, 0, &target))){
5345 target = NULL;
5348 dprint((4, "=== delete_folder(%s) ===\n", folder ? folder : "?"));
5350 ew = config_containing_inc_fldr(fp);
5351 if(wps_global->restricted)
5352 readonly = 1;
5353 else{
5354 switch(ew){
5355 case Main:
5356 prc = wps_global->prc;
5357 break;
5358 case Post:
5359 prc = wps_global->post_prc;
5360 break;
5361 case None:
5362 break;
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);
5371 return(TCL_ERROR);
5374 if(cp == wps_global->context_list
5375 && !(cp->dir && cp->dir->ref)
5376 && strucmp(folder, wps_global->inbox_name) == 0){
5377 Tcl_SetResult(interp, "Cannot delete special folder", TCL_STATIC);
5378 reset_context_folders(cp);
5379 return(TCL_ERROR);
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);
5384 return(TCL_ERROR);
5386 else if((fp->name
5387 && (strm=context_already_open_stream(cp,fp->name,AOS_NONE)))
5389 (target
5390 && (strm=context_already_open_stream(NULL,target,AOS_NONE)))){
5391 if(strm == wps_global->mail_stream)
5392 close_opened++;
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);
5396 int ret;
5398 if(fp->haschildren)
5399 ret = 1;
5400 else if(fp->hasnochildren)
5401 ret = 0;
5402 else{
5403 ret = folder_total(fdirp->folders) > 0;
5404 free_fdir(&fdirp, 1);
5407 if(ret){
5408 Tcl_SetResult(interp, "Cannot delete non-empty directory", TCL_STATIC);
5409 reset_context_folders(cp);
5410 return(TCL_ERROR);
5414 * Folder by the same name exist, so delete both...
5415 if(fp->isdual){
5416 Tcl_SetResult(interp, "Cannot delete: folder is also a directory", TCL_STATIC);
5417 reset_context_folders(cp);
5418 return(TCL_ERROR);
5423 if(cp->use & CNTXT_INCMNG){
5424 Tcl_SetResult(interp, "Cannot delete incoming folder", TCL_STATIC);
5425 reset_context_folders(cp);
5426 return(TCL_ERROR);
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 : "?"));
5433 if(strm){
5435 * Close it, NULL the pointer, and let do_broach_folder fixup
5436 * the rest...
5438 pine_mail_actually_close(strm);
5439 if(close_opened){
5440 do_broach_folder(wps_global->inbox_name,
5441 wps_global->context_list,
5442 NULL, DB_INBOXWOCNTXT);
5447 * Use fp->name since "folder" may be a nickname...
5449 if(wps_global->mail_stream
5450 && context_same_stream(cp, fp->name, wps_global->mail_stream))
5451 del_stream = wps_global->mail_stream;
5453 fnamep = fp->name;
5455 if(!context_delete(cp, del_stream, fnamep)){
5456 if((aes = peAuthException()) != NULL){
5457 Tcl_SetResult(interp, aes, TCL_VOLATILE);
5459 else{
5460 Tcl_SetResult(interp,
5461 (wps_global->last_error[0])
5462 ? wps_global->last_error
5463 : (wps_global->c_client_error[0])
5464 ? wps_global->c_client_error
5465 : "Unable to delete folder",
5466 TCL_VOLATILE);
5469 reset_context_folders(cp);
5470 return(TCL_ERROR);
5474 Tcl_SetResult(interp, "OK", TCL_STATIC);
5475 reset_context_folders(cp);
5476 return(TCL_OK);
5479 * must be at least 5 arguments for the next set of commands
5481 else if(objc < 5) {
5482 Tcl_SetResult(interp, "PEFolder: not enough arguments", TCL_VOLATILE);
5483 return(TCL_ERROR);
5485 else if(!strucmp(op, "rename")){
5486 char *folder,*newfolder, *aes;
5488 folder = Tcl_GetStringFromObj(objv[objc - 2], NULL);
5489 if(!folder) {
5490 Tcl_SetResult(interp, "PEFolder rename: Can't read folder", TCL_VOLATILE);
5491 return(TCL_ERROR);
5494 newfolder = Tcl_GetStringFromObj(objv[objc - 1], NULL);
5495 if(!newfolder) {
5496 Tcl_SetResult(interp, "PEFolder rename: Can't read folder", TCL_VOLATILE);
5497 return(TCL_ERROR);
5500 if(PEFolderChange(interp, cp, objc - 5, objv + 3) == TCL_ERROR)
5501 return TCL_ERROR;
5503 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
5504 pePrepareForAuthException();
5506 if(!context_rename(cp, NULL, folder, newfolder)){
5507 if((aes = peAuthException()) != NULL){
5508 Tcl_SetResult(interp, aes, TCL_VOLATILE);
5510 else{
5511 Tcl_SetResult(interp,
5512 (wps_global->last_error[0])
5513 ? wps_global->last_error
5514 : (wps_global->c_client_error[0])
5515 ? wps_global->c_client_error
5516 : "Unable to rename folder",
5517 TCL_VOLATILE);
5519 reset_context_folders(cp);
5520 return(TCL_ERROR);
5522 Tcl_SetResult(interp, "OK", TCL_STATIC);
5523 reset_context_folders(cp);
5524 return(TCL_OK);
5527 else
5528 err = "PEFolder: Unrecognized collection ID";
5531 else
5532 err = "No User Context Established";
5535 Tcl_SetResult(interp, err, TCL_VOLATILE);
5536 return(TCL_ERROR);
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"));
5550 if(objc == 1){
5551 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
5553 else if((op = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){
5554 if(!strucmp(op, "open")){
5555 int i, colid;
5556 char *folder;
5557 CONTEXT_S *cp;
5559 peED.uid = 0; /* forget cached embedded data */
5562 * CMD: open <context-index> <folder>
5566 if(objc == 2){
5567 Tcl_SetResult(interp, (!sp_dead_stream(wps_global->mail_stream)) ? "0" : "1", TCL_VOLATILE);
5568 return(TCL_OK);
5571 if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){
5572 if((folder = Tcl_GetStringFromObj(objv[objc - 1], NULL)) != NULL) {
5573 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
5574 if(i == colid) {
5575 if(PEMakeFolderString(interp, cp, objc - 3, objv + 3,
5576 &folder))
5577 return TCL_ERROR;
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";
5586 else
5587 err = "open: Can't read folder";
5589 else
5590 err = "open: Can't get collection ID";
5592 else if(!strcmp(op, "indexformat")){
5594 * CMD: indexformat
5596 * Returns: list of lists where:
5597 * * the first element is the name of the
5598 * field which may be "From", "Subject"
5599 * "Date" or the empty string.
5600 * * the second element which is either
5601 * the percentage width or empty string
5603 if(objc == 2)
5604 return(peIndexFormat(interp));
5606 else if(wps_global && wps_global->mail_stream){
5607 if(!strcmp(op, "select")){
5608 return(peSelect(interp, objc - 2, &((Tcl_Obj **) objv)[2], MN_SLCT));
5610 else if(!strcmp(op, "search")){
5611 return(peSelect(interp, objc - 2, &((Tcl_Obj **) objv)[2], MN_SRCH));
5613 else if(!strucmp(op, "apply")){
5614 return(peApply(interp, objc - 2, &((Tcl_Obj **) objv)[2]));
5616 else if(!strcmp(op, "expunge")){
5618 * CMD: expunge
5620 * Returns: OK after having removed deleted messages
5622 char *streamstr = NULL;
5623 MAILSTREAM *stream;
5624 MSGNO_S *msgmap;
5626 if(objc == 3) streamstr = Tcl_GetStringFromObj(objv[2], NULL);
5627 if(!streamstr
5628 || (streamstr && (strcmp(streamstr, "current") == 0))){
5629 stream = wps_global->mail_stream;
5630 msgmap = sp_msgmap(stream);
5632 else if(streamstr && (strcmp(streamstr, "inbox") == 0)){
5633 stream = sp_inbox_stream();
5634 msgmap = sp_msgmap(stream);
5636 else return(TCL_ERROR);
5637 wps_global->last_error[0] = '\0';
5638 if(IS_NEWS(stream)
5639 && stream->rdonly){
5640 msgno_exclude_deleted(stream, msgmap, NULL);
5641 clear_index_cache(sp_inbox_stream(), 0);
5644 * This is kind of surprising at first. For most sort
5645 * orders, if the whole set is sorted, then any subset
5646 * is also sorted. Not so for OrderedSubject sort.
5647 * If you exclude the first message of a subject group
5648 * then you change the date that group is to be sorted on.
5650 if(mn_get_sort(msgmap) == SortSubject2)
5651 refresh_sort(wps_global->mail_stream, msgmap, FALSE);
5653 else
5654 (void) cmd_expunge_work(stream, msgmap, NULL);
5656 Tcl_SetResult(interp, wps_global->last_error, TCL_VOLATILE);
5657 return(TCL_OK);
5659 else if(!strcmp(op, "trashdeleted")){
5661 * CMD: trashdeleted
5663 * Returns: OK after moving deleted messages to Trash and expunging
5665 MAILSTREAM *stream;
5666 MESSAGECACHE *mc;
5667 CONTEXT_S *cp;
5668 MSGNO_S *msgmap;
5669 char *streamstr = NULL, tmp[MAILTMPLEN];
5670 long n, tomove = 0L;
5672 if(objc == 3) streamstr = Tcl_GetStringFromObj(objv[2], NULL);
5673 if(!streamstr
5674 || (streamstr && (strcmp(streamstr, "current") == 0))){
5675 stream = wps_global->mail_stream;
5676 msgmap = sp_msgmap(stream);
5678 else if(streamstr && (strcmp(streamstr, "inbox") == 0)){
5679 stream = sp_inbox_stream();
5680 msgmap = sp_msgmap(stream);
5682 else return(TCL_ERROR);
5684 wps_global->last_error[0] = '\0';
5685 if(IS_NEWS(stream) && stream->rdonly){
5686 msgno_exclude_deleted(stream, msgmap, NULL);
5687 clear_index_cache(sp_inbox_stream(), 0);
5690 * This is kind of surprising at first. For most sort
5691 * orders, if the whole set is sorted, then any subset
5692 * is also sorted. Not so for OrderedSubject sort.
5693 * If you exclude the first message of a subject group
5694 * then you change the date that group is to be sorted on.
5696 if(mn_get_sort(msgmap) == SortSubject2)
5697 refresh_sort(wps_global->mail_stream, msgmap, FALSE);
5699 else{
5700 if(!(cp = default_save_context(wps_global->context_list)))
5701 cp = wps_global->context_list;
5703 /* copy to trash if we're not in trash */
5704 if(wps_global->VAR_TRASH_FOLDER
5705 && wps_global->VAR_TRASH_FOLDER[0]
5706 && context_allowed(context_apply(tmp, cp, wps_global->VAR_TRASH_FOLDER, sizeof(tmp)))
5707 && !same_stream_and_mailbox(tmp, stream)){
5709 /* save real selected set, and */
5710 for(n = 1L; n <= mn_get_total(msgmap); n++){
5711 set_lflag(stream, msgmap, n, MN_STMP, get_lflag(stream, msgmap, n, MN_SLCT));
5712 /* select deleted */
5713 if(!get_lflag(stream, msgmap, n, MN_EXLD)
5714 && (mc = mail_elt(stream, mn_m2raw(msgmap,n))) != NULL && mc->deleted){
5715 tomove++;
5716 set_lflag(stream, msgmap, n, MN_SLCT, 1);
5718 else
5719 set_lflag(stream, msgmap, n, MN_SLCT, 0);
5722 if(tomove && pseudo_selected(stream, msgmap)){
5724 /* save deleted to Trash */
5725 n = save(wps_global, stream,
5726 cp, wps_global->VAR_TRASH_FOLDER,
5727 msgmap, SV_FOR_FILT | SV_FIX_DELS);
5729 /* then remove them */
5730 if(n == tomove){
5731 (void) cmd_expunge_work(stream, msgmap, NULL);
5734 restore_selected(msgmap);
5737 /* restore selected set */
5738 for(n = 1L; n <= mn_get_total(msgmap); n++)
5739 set_lflag(stream, msgmap, n, MN_SLCT,
5740 get_lflag(stream, msgmap, n, MN_STMP));
5744 Tcl_SetResult(interp, wps_global->last_error, TCL_VOLATILE);
5745 return(TCL_OK);
5747 else if(!strcmp(op, "nextvector")){
5748 long msgno, count, countdown;
5749 int i, aObjN = 0;
5750 char *errstr = NULL, *s;
5751 Tcl_Obj *rvObj, *vObj, *avObj, **aObj;
5754 * CMD: nextvector
5756 * ARGS: msgno - message number "next" is relative to
5757 * count - how many msgno slots to return
5758 * attrib - (optional) attributes to be returned with each message in vector
5760 * Returns: vector containing next <count> messagenumbers (and optional attributes)
5762 if(objc == 4 || objc == 5){
5763 if(Tcl_GetLongFromObj(interp, objv[2], &msgno) == TCL_OK){
5764 if(Tcl_GetLongFromObj(interp, objv[3], &count) == TCL_OK){
5766 /* set index range for efficiency */
5767 if(msgno > 0L && msgno <= mn_get_total(sp_msgmap(wps_global->mail_stream))){
5768 gPeITop = msgno;
5769 gPeICount = count;
5772 if(objc == 4 || Tcl_ListObjGetElements(interp, objv[4], &aObjN, &aObj) == TCL_OK){
5774 if((rvObj = Tcl_NewListObj(0, NULL)) != NULL && count > 0
5775 && !(msgno < 1L || msgno > mn_get_total(sp_msgmap(wps_global->mail_stream)))){
5776 mn_set_cur(sp_msgmap(wps_global->mail_stream), msgno);
5778 for(countdown = count; countdown > 0; countdown--){
5779 imapuid_t uid = mail_uid(wps_global->mail_stream, mn_m2raw(sp_msgmap(wps_global->mail_stream), msgno));
5780 int fetched = 0;
5782 if((vObj = Tcl_NewListObj(0, NULL)) != NULL){
5783 Tcl_ListObjAppendElement(interp, vObj, Tcl_NewLongObj(msgno));
5784 peAppListF(interp, vObj, "%lu", uid);
5786 if(aObjN){
5787 if((avObj = Tcl_NewListObj(0, NULL)) != NULL){
5788 for(i = 0; i < aObjN; i++){
5789 if((s = Tcl_GetStringFromObj(aObj[i], NULL)) != NULL){
5790 if(!strcmp(s, "statusbits")){
5791 char *s = peMsgStatBitString(wps_global, wps_global->mail_stream,
5792 sp_msgmap(wps_global->mail_stream), peMessageNumber(uid),
5793 gPeITop, gPeICount, &fetched);
5794 Tcl_ListObjAppendElement(interp, avObj, Tcl_NewStringObj(s, -1));
5796 else if(!strcmp(s, "statuslist")){
5797 Tcl_Obj *nObj = peMsgStatNameList(interp, wps_global, wps_global->mail_stream,
5798 sp_msgmap(wps_global->mail_stream), peMessageNumber(uid),
5799 gPeITop, gPeICount, &fetched);
5800 Tcl_ListObjAppendElement(interp, avObj, nObj);
5802 else if(!strcmp(s, "status")){
5803 long raw;
5804 char stat[3];
5805 MESSAGECACHE *mc;
5807 raw = peSequenceNumber(uid);
5809 if(!((mc = mail_elt(wps_global->mail_stream, raw)) && mc->valid)){
5810 mail_fetch_flags(wps_global->mail_stream,
5811 ulong2string(uid), FT_UID);
5812 mc = mail_elt(wps_global->mail_stream, raw);
5815 stat[0] = mc->deleted ? '1' : '0';
5816 stat[1] = mc->recent ? '1' : '0';
5817 stat[2] = mc->seen ? '1' : '0';
5819 Tcl_ListObjAppendElement(interp, avObj, Tcl_NewStringObj(stat,3));
5821 else if(!strcmp(s, "indexparts")){
5822 Tcl_Obj *iObj;
5824 if((iObj = Tcl_NewListObj(0, NULL)) != NULL
5825 && peAppendIndexParts(interp, uid, iObj, &fetched) == TCL_OK
5826 && Tcl_ListObjAppendElement(interp, avObj, iObj) == TCL_OK){
5828 else
5829 return(TCL_ERROR);
5831 else if(!strucmp(s, "indexcolor")){
5832 if(peAppendIndexColor(interp, uid, avObj, &fetched) != TCL_OK)
5833 return(TCL_ERROR);
5836 else{
5837 errstr = "nextvector: can't read attributes";
5838 break;
5842 Tcl_ListObjAppendElement(interp, vObj, avObj);
5844 else{
5845 errstr = "nextvector: can't allocate attribute return vector";
5846 break;
5850 else{
5851 errstr = "nextvector: can't allocate new vector";
5852 break;
5855 Tcl_ListObjAppendElement(interp, rvObj, vObj);
5857 for(++msgno; msgno <= mn_get_total(sp_msgmap(wps_global->mail_stream)) && msgline_hidden(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), msgno, MN_NONE); msgno++)
5860 if(msgno > mn_get_total(sp_msgmap(wps_global->mail_stream)))
5861 break;
5865 if(!errstr){
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));
5871 return(TCL_OK);
5874 else
5875 errstr = "nextvector: can't read attribute list";
5877 else
5878 errstr = "nextvector: can't read count";
5880 else
5881 errstr = "nextvector: can't read message number";
5883 else
5884 errstr = "nextvector: Incorrect number of arguments";
5886 if(errstr)
5887 Tcl_SetResult(interp, errstr, TCL_STATIC);
5889 return(TCL_ERROR);
5891 else if(objc == 2){
5892 if(!strcmp(op, "messagecount")){
5894 * CMD: messagecount
5896 * Returns: count of messages in open mailbox
5898 Tcl_SetResult(interp,
5899 long2string(mn_get_total(sp_msgmap(wps_global->mail_stream))),
5900 TCL_VOLATILE);
5901 return(TCL_OK);
5903 else if(!strcmp(op, "firstinteresting")){
5905 * CMD: firstinteresting
5907 * Returns: message number associated with
5908 * "incoming-startup-rule" which had better
5909 * be the "current" message since it was set
5910 * in do_broach_folder and shouldn't have been
5911 * changed otherwise (expunged screw us?)
5913 Tcl_SetResult(interp,
5914 long2string(mn_get_cur(sp_msgmap(wps_global->mail_stream))),
5915 TCL_VOLATILE);
5916 return(TCL_OK);
5918 else if(!strcmp(op, "selected")){
5920 * CMD: selected
5922 * Returns: count of selected messages in open mailbox
5925 Tcl_SetResult(interp,
5926 long2string(any_lflagged(sp_msgmap(wps_global->mail_stream), MN_SLCT)),
5927 TCL_VOLATILE);
5928 return(TCL_OK);
5930 else if(!strcmp(op, "searched")){
5932 * CMD: searched
5934 * Returns: count of searched messages in open mailbox
5937 Tcl_SetResult(interp,
5938 long2string(any_lflagged(sp_msgmap(wps_global->mail_stream), MN_SRCH)),
5939 TCL_VOLATILE);
5940 return(TCL_OK);
5942 else if(!strcmp(op, "mailboxname")){
5944 * CMD: name
5946 * Returns: string representing the name of the
5947 * current mailbox
5949 Tcl_SetResult(interp, wps_global->cur_folder, TCL_VOLATILE);
5950 return(TCL_OK);
5952 else if(!strcmp(op, "close")){
5954 * CMD: close
5956 * Returns: with global mail_stream closed
5958 peDestroyStream(wps_global);
5959 return(TCL_OK);
5961 else if(!strcmp(op, "newmailreset")){
5962 sml_seen();
5963 zero_new_mail_count();
5964 sp_set_mail_box_changed(wps_global->mail_stream, 0);
5965 sp_set_expunge_count(wps_global->mail_stream, 0L);
5966 peMarkInputTime();
5967 return(TCL_OK);
5969 else if(!strcmp(op, "newmailstatmsg")){
5970 long newest, count;
5971 char subject[500], subjtxt[500], from[500], intro[500], *s = "";
5974 * CMD: newmailstatmsg
5976 * ARGS: none
5978 * Returns: text for new mail message
5982 if(sp_mail_box_changed(wps_global->mail_stream)
5983 && (count = sp_mail_since_cmd(wps_global->mail_stream))){
5985 for(newest = wps_global->mail_stream->nmsgs; newest > 1L; newest--)
5986 if(!get_lflag(wps_global->mail_stream, NULL, newest, MN_EXLD))
5987 break;
5989 if(newest){
5990 format_new_mail_msg(NULL, count,
5991 pine_mail_fetchstructure(wps_global->mail_stream,
5992 newest, NULL),
5993 intro, from, subject, subjtxt, sizeof(subject));
5995 snprintf(s = wtmp_20k_buf, SIZEOF_20KBUF, "%s %s %s", intro, from, subjtxt);
5999 Tcl_SetResult(interp, s, TCL_VOLATILE);
6000 return(TCL_OK);
6002 else if(!strcmp(op, "savedefault")){
6003 return(peSaveDefault(interp, 0L, 0, NULL));
6005 else if(!strcmp(op, "gotodefault")){
6006 return(peGotoDefault(interp, 0L, NULL));
6008 else if(!strcmp(op, "zoom")){
6009 Tcl_SetResult(interp,
6010 long2string((any_lflagged(sp_msgmap(wps_global->mail_stream), MN_HIDE) > 0L)
6011 ? any_lflagged(sp_msgmap(wps_global->mail_stream), MN_SLCT) : 0L),
6012 TCL_VOLATILE);
6013 return(TCL_OK);
6015 else if(!strcmp(op, "focus")){
6016 Tcl_SetResult(interp,
6017 long2string((any_lflagged(sp_msgmap(wps_global->mail_stream), MN_HIDE) > 0L)
6018 ? any_lflagged(sp_msgmap(wps_global->mail_stream), MN_SRCH) : 0L),
6019 TCL_VOLATILE);
6020 return(TCL_OK);
6022 else if(!strcmp(op, "first")){
6023 if(any_lflagged(sp_msgmap(wps_global->mail_stream), MN_HIDE)){
6024 long n;
6026 for(n = 1L; n <= mn_get_total(sp_msgmap(wps_global->mail_stream)); n++)
6027 if(!get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), n, MN_HIDE)){
6028 Tcl_SetResult(interp, long2string(n), TCL_VOLATILE);
6029 return(TCL_OK);
6032 unzoom_index(wps_global, wps_global->mail_stream, sp_msgmap(wps_global->mail_stream));
6036 Tcl_SetResult(interp, int2string(1), TCL_VOLATILE);
6037 return(TCL_OK);
6039 else if(!strucmp(op, "current")){
6040 long n = 0;
6041 unsigned long u = 0;
6044 * CMD: current
6046 * ARGS:
6048 * Returns: list of current msg {<sequence> <uid>}
6051 if(mn_total_cur(sp_msgmap(wps_global->mail_stream)) <= 0
6052 || ((n = mn_get_cur(sp_msgmap(wps_global->mail_stream))) > 0
6053 && (u = mail_uid(wps_global->mail_stream, mn_m2raw(sp_msgmap(wps_global->mail_stream), n))) > 0)){
6054 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(long2string(n), -1));
6055 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(ulong2string(u), -1));
6056 return(TCL_OK);
6058 else
6059 err = "Cannot get current";
6061 else if(!strcmp(op, "last")){
6062 if(any_lflagged(sp_msgmap(wps_global->mail_stream), MN_HIDE)){
6063 long n;
6065 for(n = mn_get_total(sp_msgmap(wps_global->mail_stream)); n > 0L; n--)
6066 if(!get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), n, MN_HIDE)){
6067 Tcl_SetResult(interp, long2string(n), TCL_VOLATILE);
6068 return(TCL_OK);
6071 else{
6072 Tcl_SetResult(interp, long2string(mn_get_total(sp_msgmap(wps_global->mail_stream))), TCL_VOLATILE);
6073 return(TCL_OK);
6076 Tcl_SetResult(interp, "Can't set last message number", TCL_STATIC);
6077 return(TCL_ERROR);
6079 else if(!strucmp(op, "sortstyles")){
6080 int i;
6082 * CMD: sortstyles
6084 * Returns: list of supported sort styles
6087 for(i = 0; wps_global->sort_types[i] != EndofList; i++)
6088 if(Tcl_ListObjAppendElement(interp,
6089 Tcl_GetObjResult(interp),
6090 Tcl_NewStringObj(sort_name(wps_global->sort_types[i]), -1)) != TCL_OK)
6091 return(TCL_ERROR);
6093 return(TCL_OK);
6095 else if(!strucmp(op, "sort")){
6096 return(peAppendCurrentSort(interp));
6098 else if(!strucmp(op, "state")){
6099 if(!wps_global->mail_stream || sp_dead_stream(wps_global->mail_stream))
6100 Tcl_SetResult(interp, "closed", TCL_STATIC);
6101 else if(wps_global->mail_stream->rdonly && !IS_NEWS(wps_global->mail_stream))
6102 Tcl_SetResult(interp, "readonly", TCL_STATIC);
6103 else
6104 Tcl_SetResult(interp, "ok", TCL_STATIC);
6106 return(TCL_OK);
6108 else if(!strucmp(op, "excludedeleted")){
6109 msgno_exclude_deleted(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), NULL);
6110 return(TCL_OK);
6113 else if(objc == 3){
6114 if(!strcmp(op, "uid")){
6115 long msgno, raw;
6118 * Return uid of given message number
6120 * CMD: uid <msgnumber>
6123 if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_OK)
6124 return(TCL_ERROR); /* conversion problem? */
6126 if((raw = mn_m2raw(sp_msgmap(wps_global->mail_stream), msgno)) > 0L){
6127 raw = mail_uid(wps_global->mail_stream, raw);
6128 Tcl_SetResult(interp, long2string(raw), TCL_VOLATILE);
6129 return(TCL_OK);
6132 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Invalid UID for message %ld", msgno);
6133 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
6134 return(TCL_ERROR);
6136 else if(!strcmp(op, "newmail")){
6137 int reload, force = UFU_NONE, rv;
6138 time_t now = time(0);
6141 * CMD: newmail
6143 * ARGS: reload -- "1" if we're reloading
6144 * (vs. just checking newmail as a side effect
6145 * of building a new page)
6147 * Returns: count -
6148 * mostrecent -
6150 if(Tcl_GetIntFromObj(interp, objv[2], &reload) == TCL_ERROR)
6151 reload = 0;
6153 /* minimum 10 second between IMAP pings */
6154 if(!time_of_last_input() || now - time_of_last_input() > 10){
6155 force = UFU_FORCE;
6156 peMarkInputTime();
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();
6167 return(rv);
6169 else if(!strcmp(op, "flagcount")){
6170 char *flag;
6171 long count = 0L;
6172 long flags = 0L;
6173 int objlc;
6174 Tcl_Obj **objlv;
6178 * CMD: flagcount
6180 * ARGS: flags -
6182 * Returns: count - number of message thusly flagged
6183 * mostrecent -
6185 if(Tcl_ListObjGetElements(interp, objv[2], &objlc, &objlv) == TCL_OK){
6186 while(objlc--)
6187 if((flag = Tcl_GetStringFromObj(*objlv++, NULL)) != NULL){
6188 if(!strucmp(flag, "deleted")){
6189 flags |= F_DEL;
6191 if(!strucmp(flag, "undeleted")){
6192 flags |= F_UNDEL;
6194 else if(!strucmp(flag, "seen")){
6195 flags |= F_SEEN;
6197 else if(!strucmp(flag, "unseen")){
6198 flags |= F_UNSEEN;
6200 else if(!strucmp(flag, "flagged")){
6201 flags |= F_FLAG;
6203 else if(!strucmp(flag, "unflagged")){
6204 flags |= F_UNFLAG;
6206 else if(!strucmp(flag, "answered")){
6207 flags |= F_ANS;
6209 else if(!strucmp(flag, "unanswered")){
6210 flags |= F_UNANS;
6212 else if(!strucmp(flag, "recent")){
6213 flags |= F_RECENT;
6215 else if(!strucmp(flag, "unrecent")){
6216 flags |= F_UNRECENT;
6220 if(flags)
6221 count = count_flagged(wps_global->mail_stream, flags);
6224 Tcl_SetResult(interp, long2string(count), TCL_VOLATILE);
6225 return(TCL_OK);
6227 else if(!strcmp(op, "zoom")){
6228 int newstate;
6229 long n, zoomed = 0L;
6232 * CMD: zoom
6234 * Set/clear HID bits of non SLCT messages as requested.
6235 * PEMailbox [first | last | next] are sensitive to these flags.
6237 * ARGS: newstate - 1 or 0
6239 * Returns: count of zoomed messages
6242 if(Tcl_GetIntFromObj(interp, objv[2], &newstate) != TCL_ERROR){
6243 if(newstate > 0){
6244 if(any_lflagged(sp_msgmap(wps_global->mail_stream), MN_HIDE) != (mn_get_total(sp_msgmap(wps_global->mail_stream)) - (n = any_lflagged(sp_msgmap(wps_global->mail_stream), MN_SLCT)))){
6245 zoom_index(wps_global, wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), MN_SLCT);
6246 zoomed = n;
6249 else{
6250 if(any_lflagged(sp_msgmap(wps_global->mail_stream), MN_HIDE))
6251 unzoom_index(wps_global, wps_global->mail_stream, sp_msgmap(wps_global->mail_stream));
6255 Tcl_SetResult(interp, long2string(zoomed), TCL_VOLATILE);
6256 return(TCL_OK);
6258 else if(!strcmp(op, "focus")){
6259 int newstate;
6260 long n, zoomed = 0L;
6263 * CMD: focus
6265 * Set/clear HID bits of non MN_SRCH messages as requested.
6266 * PEMailbox [first | last | next] are sensitive to MN_HIDE flag
6268 * ARGS: newstate - 1 or 0
6270 * Returns: count of zoomed messages
6273 if(Tcl_GetIntFromObj(interp, objv[2], &newstate) != TCL_ERROR){
6274 if(newstate > 0){
6275 if(any_lflagged(sp_msgmap(wps_global->mail_stream), MN_HIDE) != (mn_get_total(sp_msgmap(wps_global->mail_stream)) - (n = any_lflagged(sp_msgmap(wps_global->mail_stream), MN_SRCH))))
6276 zoom_index(wps_global, wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), MN_SRCH);
6278 zoomed = n;
6280 else{
6281 if(any_lflagged(sp_msgmap(wps_global->mail_stream), MN_HIDE))
6282 unzoom_index(wps_global, wps_global->mail_stream, sp_msgmap(wps_global->mail_stream));
6286 Tcl_SetResult(interp, long2string(zoomed), TCL_VOLATILE);
6287 return(TCL_OK);
6289 else if(!strcmp(op, "next")){
6290 long msgno;
6293 * CMD: next <msgno>
6295 * ARGS: msgno - message number "next" is relative to
6297 * Returns: previous state
6300 if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR){
6301 mn_set_cur(sp_msgmap(wps_global->mail_stream), msgno);
6302 mn_inc_cur(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), MH_NONE);
6303 Tcl_SetResult(interp, long2string(mn_get_cur(sp_msgmap(wps_global->mail_stream))), TCL_VOLATILE);
6304 return(TCL_OK);
6307 Tcl_SetResult(interp, "next can't read message number", TCL_STATIC);
6308 return(TCL_ERROR);
6311 else if(objc == 4){
6312 if(!strucmp(op, "sort")){
6313 int i, reversed = 0;
6314 char *sort;
6317 * CMD: sort sortstyle reversed
6319 * Returns: OK with the side-effect of message
6320 * numbers now reflecting the requested
6321 * sort order.
6324 if((sort = Tcl_GetStringFromObj(objv[2], NULL))
6325 && Tcl_GetIntFromObj(interp, objv[3], &reversed) != TCL_ERROR){
6326 /* convert sort string into */
6327 for(i = 0; wps_global->sort_types[i] != EndofList; i++)
6328 if(strucmp(sort_name(wps_global->sort_types[i]), sort) == 0){
6329 if(sp_unsorted_newmail(wps_global->mail_stream)
6330 || !(wps_global->sort_types[i] == mn_get_sort(sp_msgmap(wps_global->mail_stream))
6331 && mn_get_revsort(sp_msgmap(wps_global->mail_stream)) == reversed))
6332 sort_folder(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream),
6333 wps_global->sort_types[i],
6334 reversed, 0);
6336 break;
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")){
6349 long msgno, count;
6352 * CMD: next
6354 * ARGS: msgno - message number "next" is relative to
6355 * count - how many to increment it
6357 * Returns: previous state
6360 if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR
6361 && Tcl_GetLongFromObj(interp, objv[3], &count) != TCL_ERROR){
6362 mn_set_cur(sp_msgmap(wps_global->mail_stream), msgno);
6363 while(count)
6364 if(count > 0){
6365 mn_inc_cur(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), MH_NONE);
6366 count--;
6368 else{
6369 mn_dec_cur(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), MH_NONE);
6370 count++;
6373 Tcl_SetResult(interp, long2string(mn_get_cur(sp_msgmap(wps_global->mail_stream))), TCL_VOLATILE);
6374 return(TCL_OK);
6377 Tcl_SetResult(interp, "next can't read message number", TCL_STATIC);
6378 return(TCL_ERROR);
6380 else if(!strcmp(op, "x-nextvector")){
6381 long msgno, count;
6384 * CMD: nextvector
6386 * ARGS: msgno - message number "next" is relative to
6387 * count - how many msgno slots to return
6389 * Returns: vector containing next <count> messagenumbers
6392 if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR
6393 && Tcl_GetLongFromObj(interp, objv[3], &count) != TCL_ERROR){
6394 if(count > 0 && !(msgno < 1L || msgno > mn_get_total(sp_msgmap(wps_global->mail_stream)))){
6395 mn_set_cur(sp_msgmap(wps_global->mail_stream), msgno);
6397 while(count--){
6398 long n = mn_get_cur(sp_msgmap(wps_global->mail_stream));
6400 if(peAppListF(interp, Tcl_GetObjResult(interp),
6401 "%l%l", n, mail_uid(wps_global->mail_stream,
6402 mn_m2raw(sp_msgmap(wps_global->mail_stream), n))) != TCL_OK)
6403 return(TCL_ERROR);
6405 mn_inc_cur(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), MH_NONE);
6407 if(n == mn_get_cur(sp_msgmap(wps_global->mail_stream)))
6408 break;
6412 return(TCL_OK);
6415 Tcl_SetResult(interp, "next can't read message number", TCL_STATIC);
6416 return(TCL_ERROR);
6418 else if(!strcmp(op, "messagecount")){
6419 char *relative;
6420 long msgno, n, count = 0L;
6423 * CMD: messagecount
6425 * ARGS: [before | after] relative to
6426 * msgno
6428 * Returns: count of messages before or after given message number
6431 if((relative = Tcl_GetStringFromObj(objv[2], NULL))
6432 && Tcl_GetLongFromObj(interp, objv[3], &msgno) != TCL_ERROR){
6433 if(msgno < 1L || msgno > mn_get_total(sp_msgmap(wps_global->mail_stream))){
6434 Tcl_SetResult(interp, "relative msgno out of range", TCL_STATIC);
6435 return(TCL_ERROR);
6438 if(!strucmp(relative, "before")){
6439 for(n = msgno - 1; n > 0L; n--)
6440 if(!get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), n, MN_HIDE))
6441 count++;
6443 Tcl_SetResult(interp, long2string(count), TCL_VOLATILE);
6444 return(TCL_OK);
6446 else if(!strucmp(relative, "after")){
6447 for(n = msgno + 1; n <= mn_get_total(sp_msgmap(wps_global->mail_stream)); n++)
6448 if(!get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), n, MN_HIDE))
6449 count++;
6451 Tcl_SetResult(interp, long2string(count), TCL_VOLATILE);
6452 return(TCL_OK);
6456 Tcl_SetResult(interp, "can't read range for count", TCL_STATIC);
6457 return(TCL_ERROR);
6459 else if(!strcmp(op, "selectvector")){
6460 long msgno, count;
6463 * CMD: 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){
6473 if(msgno > 0L){
6474 mn_set_cur(sp_msgmap(wps_global->mail_stream), msgno);
6475 while(count--){
6476 msgno = mn_get_cur(sp_msgmap(wps_global->mail_stream));
6478 if(get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), msgno, MN_SLCT))
6479 if(Tcl_ListObjAppendElement(interp,
6480 Tcl_GetObjResult(interp),
6481 Tcl_NewLongObj((long) mail_uid(wps_global->mail_stream, msgno))) != TCL_OK)
6482 return(TCL_ERROR);
6484 mn_inc_cur(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), MH_NONE);
6486 if(msgno == mn_get_cur(sp_msgmap(wps_global->mail_stream)))
6487 break;
6491 return(TCL_OK);
6494 Tcl_SetResult(interp, "selectvector: no message number", TCL_STATIC);
6495 return(TCL_ERROR);
6497 else if(!strucmp(op, "current")){
6498 char *which;
6499 long x, n = 0, u = 0;
6502 * CMD: current
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")){
6511 u = x;
6512 n = peMessageNumber(u);
6514 else if(!strucmp(which,"number")){
6515 n = x;
6516 u = mail_uid(wps_global->mail_stream, mn_m2raw(sp_msgmap(wps_global->mail_stream), n));
6519 if(n && u){
6520 mn_set_cur(sp_msgmap(wps_global->mail_stream), n);
6521 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(long2string(n), -1));
6522 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(long2string(u), -1));
6523 return(TCL_OK);
6525 else
6526 err = "PEMailbox current: invalid number/uid";
6528 else
6529 err = "PEMailbox current: cannot get number";
6531 else
6532 err = "PEMailbox current: cannot get which";
6535 else
6536 err = "PEMailbox: Too many arguments";
6538 else if(!strucmp(op, "name") || !strcmp(op, "close")){
6539 Tcl_SetResult(interp, "", TCL_STATIC);
6540 return(TCL_OK);
6542 else
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);
6548 return(TCL_ERROR);
6553 peAppendCurrentSort(Tcl_Interp *interp)
6555 return((Tcl_ListObjAppendElement(interp,
6556 Tcl_GetObjResult(interp),
6557 Tcl_NewStringObj(sort_name(mn_get_sort(sp_msgmap(wps_global->mail_stream))), -1)) == TCL_OK
6558 && Tcl_ListObjAppendElement(interp,
6559 Tcl_GetObjResult(interp),
6560 Tcl_NewStringObj(mn_get_revsort(sp_msgmap(wps_global->mail_stream)) ? "1" : "0", 1)) == TCL_OK)
6561 ? TCL_OK : TCL_ERROR);
6566 peAppendDefaultSort(Tcl_Interp *interp)
6568 return((Tcl_ListObjAppendElement(interp,
6569 Tcl_GetObjResult(interp),
6570 Tcl_NewStringObj(sort_name(wps_global->def_sort), -1)) == TCL_OK
6571 && Tcl_ListObjAppendElement(interp,
6572 Tcl_GetObjResult(interp),
6573 Tcl_NewStringObj(wps_global->def_sort_rev ? "1" : "0", 1)) == TCL_OK)
6574 ? TCL_OK : TCL_ERROR);
6579 peSelect(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag)
6581 char *subcmd;
6582 long n, i, diff, msgno;
6583 int narrow, hidden;
6584 MESSAGECACHE *mc;
6585 extern MAILSTREAM *mm_search_stream;
6586 extern long mm_search_count;
6588 hidden = any_lflagged(sp_msgmap(wps_global->mail_stream), MN_HIDE) > 0L;
6589 mm_search_stream = wps_global->mail_stream;
6590 mm_search_count = 0L;
6592 for(n = 1L; n <= wps_global->mail_stream->nmsgs; n++)
6593 if((mc = mail_elt(wps_global->mail_stream, n)) != NULL){
6594 mc->searched = 0;
6595 mc->spare7 = 1;
6599 * CMD: select
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")){
6609 * Args: <none>
6611 if(matchflag & MN_SLCT){
6612 if(objc != 1)
6613 return(peSelectError(interp, subcmd));
6615 agg_select_all(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), NULL, 1);
6617 else if(matchflag & MN_SRCH){
6618 for(n = 1L; n <= wps_global->mail_stream->nmsgs; n++)
6619 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), n, matchflag, 1);
6622 Tcl_SetResult(interp, "All", TCL_VOLATILE);
6624 else if(!strucmp(subcmd, "none")){
6626 * Args: <none>
6628 n = 0L;
6630 if(matchflag & MN_SLCT){
6631 if(objc != 1)
6632 return(peSelectError(interp, subcmd));
6634 agg_select_all(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), &n, 0);
6636 else if(matchflag & MN_SRCH){
6637 for(n = 1L; n <= wps_global->mail_stream->nmsgs; n++)
6638 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), n, matchflag, 0);
6641 Tcl_SetResult(interp, long2string(n), TCL_VOLATILE);
6643 else if(!strucmp(subcmd, "searched")){
6645 * Args: <none>
6647 for(n = 1L, i = 0; n <= wps_global->mail_stream->nmsgs; n++)
6648 if(get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), n, MN_SRCH)){
6649 i++;
6650 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), n, MN_SLCT, 1);
6653 Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
6655 else if(!strucmp(subcmd, "unsearched")){
6657 * Args: <none>
6659 for(n = 1L, i = 0; n <= wps_global->mail_stream->nmsgs; n++)
6660 if(get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), n, MN_SRCH)){
6661 i++;
6662 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), n, MN_SLCT, 0);
6665 Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
6667 else{
6668 if(!strucmp(subcmd, "narrow"))
6669 narrow = 1;
6670 else if(!strucmp(subcmd, "broad"))
6671 narrow = 0;
6672 else
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)
6680 return(i);
6682 else if(!strucmp(subcmd, "date")){
6683 if((i = peSelectDate(interp, objc - 2, &objv[2], matchflag)) != TCL_OK)
6684 return(i);
6686 else if(!strucmp(subcmd, "text")){
6687 if((i = peSelectText(interp, objc - 2, &objv[2], matchflag)) != TCL_OK)
6688 return(i);
6690 else if(!strucmp(subcmd, "status")){
6691 if((i = peSelectStatus(interp, objc - 2, &objv[2], matchflag)) != TCL_OK)
6692 return(i);
6694 else if(!strucmp(subcmd, "compound")){
6695 char *s;
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)
6707 return(n);
6709 else if(!strucmp(s,"text")){
6710 if((n = peSelectText(interp, nSearch - 1, &oSearch[1], matchflag)) != TCL_OK)
6711 return(n);
6713 else if(!strucmp(s,"status")){
6714 if((n = peSelectStatus(interp, nSearch - 1, &oSearch[1], matchflag)) != TCL_OK)
6715 return(n);
6717 else
6718 return(peSelectError(interp, "unknown compound search"));
6720 /* logical AND the results */
6721 mm_search_count = 0L;
6722 for(n = 1L; n <= wps_global->mail_stream->nmsgs; n++)
6723 if((mc = mail_elt(wps_global->mail_stream, n)) != NULL){
6724 if(mc->searched && mc->spare7)
6725 mm_search_count++;
6726 else
6727 mc->searched = mc->spare7 = 0;
6730 else
6731 return(peSelectError(interp, "malformed compound search"));
6733 else
6734 return(peSelectError(interp, "malformed compound search"));
6737 else
6738 return(peSelectError(interp, "malformed compound search"));
6740 else
6741 return(peSelectError(interp, "cmd cmdargs"));
6744 * at this point all interesting messages should
6745 * have searched bit lit
6748 if(narrow) /* make sure something was selected */
6749 for(i = 1L; i <= mn_get_total(sp_msgmap(wps_global->mail_stream)); i++)
6750 if(mail_elt(wps_global->mail_stream,
6751 mn_m2raw(sp_msgmap(wps_global->mail_stream), i))->searched){
6752 if(get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), i, matchflag))
6753 break;
6754 else
6755 mm_search_count--;
6758 diff = 0L;
6759 if(mm_search_count){
6761 * loop thru all the messages, adjusting local flag bits
6762 * based on their "searched" bit...
6764 for(i = 1L, msgno = 0L; i <= mn_get_total(sp_msgmap(wps_global->mail_stream)); i++)
6765 if(narrow){
6766 /* turning OFF selectedness if the "searched" bit isn't lit. */
6767 if(get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), i, matchflag)){
6768 if(!mail_elt(wps_global->mail_stream,
6769 mn_m2raw(sp_msgmap(wps_global->mail_stream), i))->searched){
6770 diff--;
6771 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), i, matchflag, 0);
6772 if(hidden)
6773 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), i, MN_HIDE, 1);
6775 else if(msgno < mn_get_cur(sp_msgmap(wps_global->mail_stream)))
6776 msgno = i;
6779 else if(mail_elt(wps_global->mail_stream,mn_m2raw(sp_msgmap(wps_global->mail_stream),i))->searched){
6780 /* turn ON selectedness if "searched" bit is lit. */
6781 if(!get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), i, matchflag)){
6782 diff++;
6783 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), i, matchflag, 1);
6784 if(hidden)
6785 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), i, MN_HIDE, 0);
6789 /* if we're zoomed and the current message was unselected */
6790 if(narrow && msgno
6791 && get_lflag(wps_global->mail_stream,sp_msgmap(wps_global->mail_stream),mn_get_cur(sp_msgmap(wps_global->mail_stream)),MN_HIDE))
6792 mn_reset_cur(sp_msgmap(wps_global->mail_stream), msgno);
6795 Tcl_SetResult(interp, long2string(diff), TCL_VOLATILE);
6798 return(TCL_OK);
6801 Tcl_SetResult(interp, "Can't read select option", TCL_STATIC);
6802 return(TCL_ERROR);
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;
6814 if(objc == 2){
6815 if(Tcl_GetLongFromObj(interp, objv[0], &first) == TCL_OK
6816 && Tcl_GetLongFromObj(interp, objv[1], &last) == TCL_OK){
6817 if(last && last < first){
6818 n = last;
6819 last = first;
6820 first = n;
6823 if(first >= 1L && first <= mn_get_total(sp_msgmap(wps_global->mail_stream))){
6824 if(last){
6825 if(last >= 1L && last <= mn_get_total(sp_msgmap(wps_global->mail_stream))){
6826 for(n = first; n <= last; n++)
6827 mm_searched(wps_global->mail_stream,
6828 mn_m2raw(sp_msgmap(wps_global->mail_stream), n));
6830 else
6831 return(peSelectError(interp, "last out of range"));
6833 else{
6834 mm_searched(wps_global->mail_stream,
6835 mn_m2raw(sp_msgmap(wps_global->mail_stream), first));
6838 else
6839 return(peSelectError(interp, "first out of range"));
6841 else
6842 return(peSelectError(interp, "can't read first/last"));
6844 else
6845 return(peSelectError(interp, "num first last"));
6847 return(TCL_OK);
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"...
6858 * day - day number
6861 char *tense, *year, *month, *day, buf[256];
6863 if(objc == 4){
6864 if((tense = peSelValTense(objv[0])) != NULL){
6865 if((year = peSelValYear(objv[1])) != NULL){
6866 if((month = peSelValMonth(objv[2])) != NULL){
6867 if((day = peSelValDay(objv[3])) != NULL){
6868 snprintf(buf, sizeof(buf), "%s %s-%s-%s", tense, day, month, year);
6869 pine_mail_search_full(wps_global->mail_stream, NULL,
6870 mail_criteria(buf),
6871 SE_NOPREFETCH | SE_FREE);
6873 else
6874 return(peSelectError(interp, "<with valid day>"));
6876 else
6877 return(peSelectError(interp, "<with valid month>"));
6879 else
6880 return(peSelectError(interp, "<with valid year>"));
6882 else
6883 return(peSelectError(interp, "<with valid tense>"));
6885 else
6886 return(peSelectError(interp, "date tense year monthabbrev daynum"));
6888 return(TCL_OK);
6892 peSelectText(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag)
6895 * Args: [broad | narrow]
6896 * case - in not
6897 * field - to from cc recip partic subj any
6898 * text - free text search string
6900 int not;
6901 char field, *text;
6903 if(objc == 3){
6904 if((not = peSelValCase(objv[0])) >= 0){
6905 if((field = peSelValField(objv[1])) != '\0'){
6906 if((text = Tcl_GetStringFromObj(objv[2], NULL))
6907 && strlen(text) < 1024){
6908 /* BUG: fix charset not to be NULL below */
6909 if(agg_text_select(wps_global->mail_stream,
6910 sp_msgmap(wps_global->mail_stream),
6911 field, NULL, not, 0, text, NULL, NULL))
6912 /* BUG: plug in "charset" above? */
6913 return(peSelectError(interp, "programmer botch"));
6915 else
6916 return(peSelectError(interp, "<with search string < 1024>"));
6918 else
6919 return(peSelectError(interp, "<with valid field>"));
6921 else
6922 return(peSelectError(interp, "<with valid case>"));
6924 else
6925 return(peSelectError(interp, "text case field text"));
6927 return(TCL_OK);
6931 peSelectStatus(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag)
6934 * Args: [broad | narrow]
6935 * case - on not
6936 * status - imp new ans del
6938 int not;
6939 char flag;
6941 if(objc == 2){
6942 if((not = peSelValCase(objv[0])) >= 0){
6943 if((flag = peSelValFlag(objv[1])) != '\0'){
6944 if(agg_flag_select(wps_global->mail_stream, not, flag, NULL))
6945 return(peSelectError(interp, "programmer botch"));
6947 else
6948 return(peSelectError(interp, "<with valid flag>"));
6950 else
6951 return(peSelectError(interp, "<with valid case>"));
6953 else
6954 return(peSelectError(interp, "status focus case flag"));
6956 return(TCL_OK);
6959 char *
6960 peSelValTense(Tcl_Obj *objp)
6962 char *tense, **pp;
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))
6969 return(tense);
6972 return(NULL);
6976 char *
6977 peSelValYear(Tcl_Obj *objp)
6979 char *year;
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])
6986 ? year
6987 : NULL);
6991 char *
6992 peSelValMonth(Tcl_Obj *objp)
6994 char *month, **pp;
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))
7002 return(*pp);
7004 return(NULL);
7008 char *
7009 peSelValDay(Tcl_Obj *objp)
7011 char *day;
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])
7017 && day[2] == '\0')
7018 ? day
7019 : NULL);
7024 peSelValCase(Tcl_Obj *objp)
7026 char *not;
7028 if((not = Tcl_GetStringFromObj(objp, NULL)) != NULL){
7029 if(!strucmp(not, "ton"))
7030 return(0);
7031 else if(!strucmp(not, "not"))
7032 return(1);
7035 return(-1);
7040 peSelValField(Tcl_Obj *objp)
7042 char *field;
7043 int i;
7044 static struct {
7045 char *field;
7046 int type;
7047 } fields[] = {{"from", 'f'},
7048 {"to", 't'},
7049 {"cc", 'c'},
7050 {"subj", 's'},
7051 {"any", 'a'},
7052 {"recip", 'r'},
7053 {"partic", 'p'},
7054 {"body", 'b'},
7055 {NULL,0}};
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);
7062 return(0);
7067 peSelValFlag(Tcl_Obj *objp)
7069 char *flag;
7070 int i;
7071 static struct {
7072 char *flag;
7073 int type;
7074 } flags[] = {{"imp", '*'},
7075 {"new", 'n'},
7076 {"ans", 'a'},
7077 {"del", 'd'},
7078 {NULL,0}};
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);
7085 return(0);
7089 peSelected(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag)
7091 int rv = 0;
7092 long i, n;
7093 char *range;
7096 * CMD: searched [before | after] #
7098 * Returns: 1 if criteria is true, 0 otherwise
7101 if((range = Tcl_GetStringFromObj(objv[0], NULL))
7102 && Tcl_GetLongFromObj(interp, objv[1], &n) != TCL_ERROR){
7103 if(!strucmp(range, "before")){
7104 for(i = 1L; i < n && i <= mn_get_total(sp_msgmap(wps_global->mail_stream)); i++)
7105 if(get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), i, matchflag)){
7106 rv = 1;
7107 break;
7110 Tcl_SetResult(interp, int2string(rv), TCL_STATIC);
7111 return(TCL_OK);
7113 else if(!strucmp(range, "after")){
7114 for(i = n + 1L; i <= mn_get_total(sp_msgmap(wps_global->mail_stream)); i++)
7115 if(get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), i, matchflag)){
7116 rv = 1;
7117 break;
7120 Tcl_SetResult(interp, int2string(rv), TCL_STATIC);
7121 return(TCL_OK);
7125 Tcl_SetResult(interp, "searched test failed", TCL_STATIC);
7126 return(TCL_ERROR);
7131 peSelectError(Tcl_Interp *interp, char *usage)
7133 char buf[256];
7135 snprintf(buf, sizeof(buf), "should be select %.128s", usage);
7136 Tcl_SetResult(interp, buf, TCL_VOLATILE);
7137 return(TCL_ERROR);
7142 peApply(Tcl_Interp *interp, int objc, Tcl_Obj **objv)
7144 char *subcmd;
7145 long n;
7147 if(!(n = any_lflagged(sp_msgmap(wps_global->mail_stream), MN_SLCT))){
7148 Tcl_SetResult(interp, "No messages selected", TCL_STATIC);
7149 return(TCL_ERROR);
7151 else if((subcmd = Tcl_GetStringFromObj(objv[0], NULL)) != NULL){
7152 if(objc == 1){
7153 if(!strucmp(subcmd, "delete")){
7154 /* BUG: is CmdWhere arg always right? */
7155 (void) cmd_delete(wps_global, sp_msgmap(wps_global->mail_stream), MCMD_AGG | MCMD_SILENT, NULL);
7156 Tcl_SetResult(interp, long2string(n), TCL_STATIC);
7157 return(TCL_OK);
7159 else if(!strucmp(subcmd, "undelete")){
7160 (void) cmd_undelete(wps_global, sp_msgmap(wps_global->mail_stream), MCMD_AGG | MCMD_SILENT);
7161 Tcl_SetResult(interp, long2string(n), TCL_STATIC);
7162 return(TCL_OK);
7165 else if(objc == 2){
7166 if(!strucmp(subcmd, "count")){
7168 * Args: flag
7170 char *flagname;
7171 long n, rawno, count = 0;
7173 if((flagname = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){
7174 for(n = 1L; n <= mn_get_total(sp_msgmap(wps_global->mail_stream)); n++){
7175 rawno = mn_m2raw(sp_msgmap(wps_global->mail_stream), n);
7176 if(get_lflag(wps_global->mail_stream, NULL, rawno, MN_SLCT)
7177 && peIsFlagged(wps_global->mail_stream,
7178 mail_uid(wps_global->mail_stream, rawno),
7179 flagname)){
7180 count++;
7185 Tcl_SetResult(interp, long2string(count), TCL_VOLATILE);
7186 return(TCL_OK);
7189 else if(objc == 3){
7190 if(!strucmp(subcmd, "flag")){
7192 * Args: case - on not
7193 * flag - imp new ans del
7195 char flag, *result;
7196 int not;
7197 long flagged;
7199 if((not = peSelValCase(objv[1])) >= 0){
7200 if((flag = peSelValFlag(objv[2])) != '\0'){
7201 result = peApplyFlag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), flag, not, &flagged);
7202 if(!result){
7203 Tcl_SetResult(interp, int2string(flagged), TCL_VOLATILE);
7204 return(TCL_OK);
7206 else
7207 return(peApplyError(interp, result));
7209 else
7210 return(peApplyError(interp, "invalid flag"));
7212 else
7213 return(peApplyError(interp, "invalid case"));
7215 else if(!strucmp(subcmd, "save")){
7217 * Args: colid -
7218 * folder - imp new ans del
7221 int colid, flgs = 0, i;
7222 char *folder, *err;
7223 CONTEXT_S *cp;
7225 if(Tcl_GetIntFromObj(interp, objv[1], &colid) != TCL_ERROR){
7227 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
7228 if(i == colid){
7229 if((folder = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
7230 if(pseudo_selected(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream))){
7232 if(!READONLY_FOLDER(wps_global->mail_stream)
7233 && F_OFF(F_SAVE_WONT_DELETE, wps_global))
7234 flgs |= SV_DELETE;
7236 if(colid == 0 && !strucmp(folder, "inbox"))
7237 flgs |= SV_INBOXWOCNTXT;
7239 i = save(wps_global, wps_global->mail_stream,
7240 cp, folder, sp_msgmap(wps_global->mail_stream), flgs);
7242 err = (i == mn_total_cur(sp_msgmap(wps_global->mail_stream))) ? NULL : "problem saving";
7244 restore_selected(sp_msgmap(wps_global->mail_stream));
7245 if(err)
7246 return(peApplyError(interp, err));
7248 Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
7249 return(TCL_OK);
7251 else
7252 return(peApplyError(interp, "can't select"));
7254 else
7255 return(peApplyError(interp, "no folder name"));
7258 return(peApplyError(interp, "bad colid"));
7260 else
7261 return(peApplyError(interp, "invalid case"));
7263 else if(!strucmp(subcmd, "copy")){
7265 * Args: colid -
7266 * folder - imp new ans del
7269 int colid, flgs = 0, i;
7270 char *folder, *err;
7271 CONTEXT_S *cp;
7273 if(Tcl_GetIntFromObj(interp, objv[1], &colid) != TCL_ERROR){
7275 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
7276 if(i == colid){
7277 if((folder = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
7278 if(pseudo_selected(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream))){
7280 if(colid == 0 && !strucmp(folder, "inbox"))
7281 flgs |= SV_INBOXWOCNTXT;
7283 i = save(wps_global, wps_global->mail_stream,
7284 cp, folder, sp_msgmap(wps_global->mail_stream), flgs);
7286 err = (i == mn_total_cur(sp_msgmap(wps_global->mail_stream))) ? NULL : "problem copying";
7288 restore_selected(sp_msgmap(wps_global->mail_stream));
7289 if(err)
7290 return(peApplyError(interp, err));
7292 Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
7293 return(TCL_OK);
7295 else
7296 return(peApplyError(interp, "can't select"));
7298 else
7299 return(peApplyError(interp, "no folder name"));
7302 return(peApplyError(interp, "bad colid"));
7304 else
7305 return(peApplyError(interp, "invalid case"));
7307 else if(!strucmp(subcmd, "move")){
7309 * Args: colid -
7310 * folder - imp new ans del
7313 int colid, flgs = 0, i;
7314 char *folder, *err;
7315 CONTEXT_S *cp;
7317 if(Tcl_GetIntFromObj(interp, objv[1], &colid) != TCL_ERROR){
7319 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
7320 if(i == colid){
7321 if((folder = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
7322 if(pseudo_selected(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream))){
7324 flgs = SV_DELETE;
7326 if(colid == 0 && !strucmp(folder, "inbox"))
7327 flgs |= SV_INBOXWOCNTXT;
7329 i = save(wps_global, wps_global->mail_stream,
7330 cp, folder, sp_msgmap(wps_global->mail_stream), flgs);
7332 err = (i == mn_total_cur(sp_msgmap(wps_global->mail_stream))) ? NULL : "problem moving";
7334 restore_selected(sp_msgmap(wps_global->mail_stream));
7335 if(err)
7336 return(peApplyError(interp, err));
7338 Tcl_SetResult(interp, long2string(i), TCL_VOLATILE);
7339 return(TCL_OK);
7341 else
7342 return(peApplyError(interp, "can't select"));
7344 else
7345 return(peApplyError(interp, "no folder name"));
7348 return(peApplyError(interp, "bad colid"));
7350 else
7351 return(peApplyError(interp, "invalid case"));
7353 else if(!strucmp(subcmd, "spam")){
7355 * Args: spamaddr -
7356 * spamsubj -
7358 char *spamaddr, *spamsubj = NULL;
7359 long n, rawno;
7361 if((spamaddr = Tcl_GetStringFromObj(objv[1], NULL))
7362 && (spamsubj = Tcl_GetStringFromObj(objv[2], NULL))){
7363 for(n = 1L; n <= mn_get_total(sp_msgmap(wps_global->mail_stream)); n++){
7364 rawno = mn_m2raw(sp_msgmap(wps_global->mail_stream), n);
7365 if(get_lflag(wps_global->mail_stream, NULL, rawno, MN_SLCT)){
7366 char errbuf[WP_MAX_POST_ERROR + 1], *rs = NULL;
7368 if((rs = peSendSpamReport(rawno, spamaddr, spamsubj, errbuf)) != NULL){
7369 Tcl_SetResult(interp, rs, TCL_VOLATILE);
7370 return(TCL_ERROR);
7376 Tcl_SetResult(interp, "OK", TCL_VOLATILE);
7377 return(TCL_OK);
7382 return(peApplyError(interp, "unknown option"));
7386 char *
7387 peApplyFlag(MAILSTREAM *stream, MSGNO_S *msgmap, char flag, int not, long *flagged)
7389 char *seq, *flagstr;
7390 long flags, flagid;
7392 switch (flag) {
7393 case '*' :
7394 flagstr = "\\FLAGGED";
7395 flags = not ? 0L : ST_SET;
7396 flagid = not ? F_FLAG : F_UNFLAG;
7397 break;
7398 case 'n' :
7399 flagstr = "\\SEEN";
7400 flags = not ? ST_SET : 0L;
7401 flagid = not ? F_UNSEEN : F_SEEN;
7402 break;
7403 case 'a' :
7404 flagstr = "\\ANSWERED";
7405 flags = not ? 0L : ST_SET;
7406 flagid = not ? F_ANS : F_UNANS;
7407 break;
7408 case 'd':
7409 flagstr = "\\DELETED";
7410 flags = not ? 0L : ST_SET;
7411 flagid = not ? F_DEL : F_UNDEL;
7412 break;
7413 default :
7414 return("unknown flag");
7415 break;
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);
7425 return(NULL);
7427 else
7428 return("can't select");
7433 peApplyError(Tcl_Interp *interp, char *usage)
7435 char buf[256];
7437 snprintf(buf, sizeof(buf), "apply error: %.128s", usage);
7438 Tcl_SetResult(interp, buf, TCL_VOLATILE);
7439 return(TCL_ERROR);
7444 * peIndexFormat - Return with interp's result object set to
7445 * represent the index line's format as a list of
7446 * index-field-name, percentage-width pairs
7449 peIndexFormat(Tcl_Interp *interp)
7451 INDEX_COL_S *cdesc = NULL;
7452 char *name, wbuf[4], *dname;
7454 for(cdesc = wps_global->index_disp_format;
7455 cdesc->ctype != iNothing;
7456 cdesc++) {
7457 dname = NULL;
7458 switch(cdesc->ctype){
7459 case iFStatus:
7460 case iIStatus:
7461 case iSIStatus:
7462 dname = "iStatus";
7463 case iStatus:
7464 name = "Status";
7465 break;
7467 case iMessNo:
7468 name = "Number";
7469 break;
7471 case iPrio:
7472 case iPrioAlpha:
7473 case iPrioBang:
7474 name = "Priority";
7475 break;
7477 case iDate: case iSDate: case iSTime: case iLDate:
7478 case iS1Date: case iS2Date: case iS3Date: case iS4Date: case iDateIso:
7479 case iDateIsoS:
7480 case iSDateIso: case iSDateIsoS:
7481 case iSDateS1: case iSDateS2:
7482 case iSDateS3: case iSDateS4:
7483 case iSDateTime:
7484 case iSDateTimeIso: case iSDateTimeIsoS:
7485 case iSDateTimeS1: case iSDateTimeS2:
7486 case iSDateTimeS3: case iSDateTimeS4:
7487 case iSDateTime24:
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:
7493 case iCurPrefDate:
7494 name = "Date";
7495 break;
7497 case iCurDay: case iCurDay2Digit:
7498 case iCurDayOfWeek: case iCurDayOfWeekAbb:
7499 name = "Day";
7500 break;
7502 case iCurMon: case iCurMon2Digit:
7503 case iCurMonLong: case iCurMonAbb:
7504 name= "Month";
7505 break;
7507 case iTime24: case iTime12: case iTimezone:
7508 case iCurPrefTime:
7509 name = "Time";
7510 break;
7512 case iDay2Digit: case iDayOfWeek: case iDayOfWeekAbb:
7513 name = "Day";
7514 break;
7516 case iMonAbb: case iMon2Digit:
7517 name = "Month";
7518 break;
7520 case iYear: case iYear2Digit:
7521 case iCurYear: case iCurYear2Digit:
7522 name = "Year";
7523 break;
7525 case iScore :
7526 name = "Score";
7527 break;
7529 case iFromTo:
7530 case iFromToNotNews:
7531 case iFrom:
7532 name = "From";
7533 break;
7535 case iTo:
7536 case iToAndNews :
7537 name = "To";
7538 break;
7540 case iCc:
7541 name = "Cc";
7542 break;
7544 case iRecips:
7545 name = "Recipients";
7546 break;
7548 case iSender:
7549 name = "Sender";
7550 break;
7552 case iSize :
7553 case iSizeComma :
7554 case iSizeNarrow :
7555 case iDescripSize:
7556 case iKSize :
7557 name = "Size";
7558 break;
7560 case iAtt:
7561 name = "Attachments";
7562 break;
7564 case iAddress :
7565 name = "Address";
7566 break;
7568 case iMailbox :
7569 name = "Mailbox";
7570 break;
7572 case iOpeningText:
7573 case iOpeningTextNQ:
7574 name = "Excerpt";
7575 break;
7577 case iSubject :
7578 case iSubjKey :
7579 case iSubjKeyInit :
7580 case iSubjectText :
7581 case iSubjKeyText :
7582 case iShortSubject :
7583 case iShortSubjKey :
7584 case iSubjKeyInitText :
7585 case iShortSubjKeyInit :
7586 name = "Subject";
7587 break;
7589 case iNews:
7590 case iNewsAndTo :
7591 name = "News";
7592 break;
7594 case iNewsAndRecips:
7595 name = "News/Recip";
7596 break;
7598 case iRecipsAndNews:
7599 name = "Recip/News";
7600 break;
7602 default :
7603 name = "";
7604 break;
7607 if(cdesc->width > 0){
7608 int p = ((cdesc->width * 100) / FAKE_SCREEN_WIDTH);
7610 snprintf(wbuf, sizeof(wbuf), "%d%%", p);
7612 else
7613 wbuf[0] = '\0';
7615 if(peAppListF(interp, Tcl_GetObjResult(interp), "%s%s%s", name, wbuf, dname) != TCL_OK)
7616 return(TCL_ERROR);
7619 return(TCL_OK);
7624 peNewMailResult(Tcl_Interp *interp)
7626 unsigned long n, uid;
7628 if(sp_mail_box_changed(wps_global->mail_stream)){
7629 if((n = sp_mail_since_cmd(wps_global->mail_stream)) != 0L){
7630 /* first element is count of new messages */
7631 if(Tcl_ListObjAppendElement(interp,
7632 Tcl_GetObjResult(interp),
7633 Tcl_NewLongObj(n)) != TCL_OK)
7634 return(TCL_ERROR);
7636 /* second element is UID of most recent message */
7637 for(uid = wps_global->mail_stream->nmsgs; uid > 1L; uid--)
7638 if(!get_lflag(wps_global->mail_stream, NULL, uid, MN_EXLD))
7639 break;
7641 if(!uid){
7642 Tcl_ResetResult(interp);
7643 Tcl_SetResult(interp, "0 0 0", TCL_STATIC);
7644 return(TCL_ERROR);
7647 uid = mail_uid(wps_global->mail_stream, uid);
7649 if(Tcl_ListObjAppendElement(interp,
7650 Tcl_GetObjResult(interp),
7651 Tcl_NewLongObj(uid)) != TCL_OK)
7652 return(TCL_ERROR);
7654 else {
7655 if(Tcl_ListObjAppendElement(interp,
7656 Tcl_GetObjResult(interp),
7657 Tcl_NewIntObj(0)) != TCL_OK)
7658 return(TCL_ERROR);
7660 /* zero is UID of new message */
7661 if(Tcl_ListObjAppendElement(interp,
7662 Tcl_GetObjResult(interp),
7663 Tcl_NewIntObj(0)) != TCL_OK)
7664 return(TCL_ERROR);
7667 /* third element is expunge count */
7668 if(Tcl_ListObjAppendElement(interp,
7669 Tcl_GetObjResult(interp),
7670 Tcl_NewLongObj(sp_expunge_count(wps_global->mail_stream)
7671 ? sp_expunge_count(wps_global->mail_stream)
7672 : 0L)) != TCL_OK)
7673 return(TCL_ERROR);
7676 else
7677 Tcl_SetResult(interp, "0 0 0", TCL_STATIC);
7679 return(TCL_OK);
7683 /* * * * * * * * Start of Per-Thread/SubThread access functions * * * * * * * */
7687 * PEThreadCmd - access/manipulate various pieces of thread state
7690 PEThreadCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
7692 char *err, errbuf[256], *cmd, *op;
7693 long uidl;
7694 imapuid_t uid;
7696 dprint((2, "PEThreadCmd"));
7698 snprintf(err = errbuf, sizeof(errbuf), "Unknown %s request",
7699 Tcl_GetStringFromObj(objv[0], NULL));
7701 if(!(wps_global && wps_global->mail_stream)){
7702 snprintf(err = errbuf, sizeof(errbuf), "%s: No open mailbox",
7703 Tcl_GetStringFromObj(objv[0], NULL));
7705 else if(objc < 2){
7706 Tcl_WrongNumArgs(interp, 1, objv, "uid cmd ?args?");
7708 else if(Tcl_GetLongFromObj(interp, objv[1], &uidl) != TCL_OK){
7709 return(TCL_ERROR); /* conversion problem? */
7711 else if(!peSequenceNumber(uidl)){
7712 snprintf(err = errbuf, sizeof(errbuf), "%s: UID %ld doesn't exist",
7713 Tcl_GetStringFromObj(objv[0], NULL), uidl);
7715 else if((cmd = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
7716 uid = uidl;
7717 if(objc == 3){
7718 if(!strucmp(cmd,"info")){
7719 #define WP_MAX_THRD_PREFIX 256
7720 long raw;
7721 PINETHRD_S *pthrd;
7722 char tstr[WP_MAX_THRD_PREFIX];
7724 if((raw = peSequenceNumber(uid)) != 0L){
7726 * translate PINETHRD_S data into
7728 if((pthrd = msgno_thread_info(wps_global->mail_stream, raw, NULL, THD_TOP)) != NULL){
7730 tstr[0] = '\0';
7731 /* BUG: build tstr form pthrd */
7734 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
7735 Tcl_NewStringObj(tstr, -1));
7738 else
7739 Tcl_SetResult(interp, "0", TCL_STATIC);
7741 return(TCL_OK);
7745 else if(objc == 5){
7746 if(!strucmp(cmd,"flag")){
7747 if((op = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){
7748 if(!strucmp(op,"deleted")){
7749 int value;
7751 if(Tcl_GetIntFromObj(interp, objv[4], &value) != TCL_ERROR){
7752 long n;
7753 PINETHRD_S *pthrd;
7754 char *flag;
7756 while(1){
7757 if(!(n = peSequenceNumber(uid))){
7758 Tcl_SetResult(interp, "Unrecognized UID", TCL_STATIC);
7759 return(TCL_ERROR);
7762 flag = cpystr("\\DELETED");
7763 mail_flag(wps_global->mail_stream, long2string(n), flag, (value ? ST_SET : 0L));
7764 fs_give((void **) &flag);
7766 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
7767 Tcl_NewStringObj(ulong2string(uid), -1));
7769 if(++n <= wps_global->mail_stream->nmsgs){
7770 uid = mail_uid(wps_global->mail_stream, n);
7772 else
7773 break;
7775 if((pthrd = msgno_thread_info(wps_global->mail_stream, n, NULL,THD_TOP)) != NULL){
7777 else
7778 break;
7787 Tcl_SetResult(interp, err, TCL_STATIC);
7788 return(TCL_ERROR);
7793 /* * * * * * * * Start of Per-Message access functions * * * * * * * */
7797 static struct _message_cmds {
7798 char *cmd;
7799 int hcount;
7800 struct {
7801 int argcount;
7802 int (*f)(Tcl_Interp *, imapuid_t, int, Tcl_Obj **);
7803 } h[3];
7804 } message_cmds[] = {
7805 {"size", 1, {{3, peMessageSize}}},
7806 {"date", 2, {{3, peMessageDate}, {4, peMessageDate}}},
7807 {"subject", 1, {{3, peMessageSubject}}},
7808 {"fromaddr", 1, {{3, peMessageFromAddr}}},
7809 {"toaddr", 1, {{3, peMessageToAddr}}},
7810 {"ccaddr", 1, {{3, peMessageCcAddr}}},
7811 {"status", 1, {{3, peMessageStatus}}},
7812 {"statusbits", 1, {{3, peMessageStatusBits}}},
7813 {"charset", 1, {{3, peMessageCharset}}},
7814 {"number", 1, {{3, peMsgnoFromUID}}},
7815 {"envelope", 0},
7816 {"rawenvelope", 0},
7817 {"text", 1, {{3, peMessageText}}},
7818 {"header", 1, {{3, peMessageHeader}}},
7819 {"attachments", 1, {{3, peMessageAttachments}}},
7820 {"body", 3, {{3, peMessageBody}, {4, peMessageBody}}},
7821 {"cid", 1, {{4, peMessagePartFromCID}}},
7822 {"flag", 2, {{4, peGetFlag}, {5, peSetFlag}}},
7823 {"replyheaders", 2, {{3, peReplyHeaders},{4, peReplyHeaders}}},
7824 {"replytext", 2, {{4, peReplyText}, {5, peReplyText}}},
7825 {"forwardheaders", 2, {{3, peForwardHeaders}, {4, peForwardHeaders}}},
7826 {"forwardtext", 2, {{3, peForwardText}, {4, peForwardText}}},
7827 {"rawbody", 0},
7828 {"select", 2, {{3, peMsgSelect}, {4, peMsgSelect}}},
7829 {"detach", 1, {{5, peDetach}}},
7830 {"attachinfo", 1, {{4, peAttachInfo}}},
7831 {"savedefault", 1, {{3, peSaveDefault}}},
7832 {"save", 1, {{5, peSave}}},
7833 {"copy", 1, {{5, peCopy}}},
7834 {"move", 1, {{5, peMove}}},
7835 {"takeaddr", 1, {{3, peTakeaddr}}},
7836 {"takefrom", 1, {{3, peTakeFrom}}},
7837 {"replyquote", 1, {{3, peReplyQuote}}},
7838 {"bounce", 2, {{4, peMessageBounce},{5, peMessageBounce}}},
7839 {"spam", 1, {{5, peMessageSpamNotice}}},
7840 {"needpasswd", 1, {{3, peMessageNeedPassphrase}}},
7841 {NULL, 0}
7848 * PEMessageCmd - export various bits of message information
7850 * NOTE: all exported commands are of the form:
7852 * PEMessage <uid> <cmd> <args>
7855 PEMessageCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
7857 char *err, errbuf[256], *cmd;
7858 int i, j;
7859 long uidl;
7860 imapuid_t uid;
7862 dprint((5, "PEMessageCmd"));
7864 snprintf(err = errbuf, sizeof(errbuf), "Unknown %s request",
7865 Tcl_GetStringFromObj(objv[0], NULL));
7867 if(!(wps_global && wps_global->mail_stream)){
7868 snprintf(err = errbuf, sizeof(errbuf), "%s: No open mailbox",
7869 Tcl_GetStringFromObj(objv[0], NULL));
7871 else if(objc < 3){
7872 Tcl_WrongNumArgs(interp, 0, objv, "PEMessage <uid> cmd ?args?");
7874 else if(Tcl_GetLongFromObj(interp, objv[1], &uidl) != TCL_OK){
7875 return(TCL_ERROR); /* conversion problem? */
7877 else if(!peMessageNumber(uidl)){
7878 snprintf(err = errbuf, sizeof(errbuf), "%s: UID %ld doesn't exist",
7879 Tcl_GetStringFromObj(objv[0], NULL), uidl);
7881 else if((cmd = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
7882 uid = uidl;
7883 for(i = 0; message_cmds[i].cmd; i++)
7884 if(!strcmp(cmd, message_cmds[i].cmd)){
7885 for(j = 0; j < message_cmds[i].hcount; j++)
7886 if(message_cmds[i].h[j].argcount == objc)
7887 return((*message_cmds[i].h[j].f)(interp, uid, objc - 3,
7888 &((Tcl_Obj **)objv)[3]));
7890 snprintf(err = errbuf, sizeof(errbuf),
7891 "PEMessage: %s: mismatched argument count", cmd);
7892 break;
7896 Tcl_SetResult(interp, err, TCL_STATIC);
7897 return(TCL_ERROR);
7902 * return the uid's ordinal number within the CURRENT SORT
7904 long
7905 peMessageNumber(imapuid_t uid)
7907 return(mn_raw2m(sp_msgmap(wps_global->mail_stream), peSequenceNumber(uid)));
7911 * return the uid's RAW message number (for c-client reference, primarily)
7913 long
7914 peSequenceNumber(imapuid_t uid)
7916 return(mail_msgno(wps_global->mail_stream, uid));
7921 peMessageSize(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
7923 long raw;
7925 if((raw = peSequenceNumber(uid))
7926 && pine_mail_fetchstructure(wps_global->mail_stream, raw, NULL)){
7927 Tcl_SetResult(interp,
7928 long2string(mail_elt(wps_global->mail_stream,
7929 raw)->rfc822_size),
7930 TCL_VOLATILE);
7932 else
7933 Tcl_SetResult(interp, "0", TCL_STATIC);
7935 return(TCL_OK);
7940 peMessageDate(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
7942 char *cmd;
7943 long raw;
7944 ENVELOPE *env;
7945 MESSAGECACHE mc;
7947 if((raw = peSequenceNumber(uid))
7948 && (env = pine_mail_fetchstructure(wps_global->mail_stream, raw, NULL))){
7949 if(objc == 1 && objv[0]){
7950 if(mail_parse_date(&mc, env->date)){
7951 if((cmd = Tcl_GetStringFromObj(objv[0], NULL)) != NULL){
7952 if(!strucmp(cmd,"day")){
7953 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "%02d", mc.day);
7954 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
7955 return(TCL_OK);
7957 else if(!strucmp(cmd,"month")){
7958 Tcl_SetResult(interp, month_abbrev(mc.month), TCL_VOLATILE);
7959 return(TCL_OK);
7961 else if(!strucmp(cmd,"year")){
7962 Tcl_SetResult(interp, int2string(mc.year + BASEYEAR), TCL_VOLATILE);
7963 return(TCL_OK);
7965 else{
7966 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "peMessageDate cmd: %.20s", cmd);
7967 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
7970 else
7971 Tcl_SetResult(interp, "peMessageDate: can't get command", TCL_STATIC);
7973 else
7974 Tcl_SetResult(interp, "peMessageDate: can't parse date", TCL_STATIC);
7976 else{
7977 Tcl_SetResult(interp, env->date ? (char *) env->date : "", TCL_VOLATILE);
7978 return(TCL_OK);
7981 else
7982 Tcl_SetResult(interp, "Can't get message structure", TCL_STATIC);
7984 return(TCL_ERROR);
7989 peMessageFromAddr(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
7991 return(peMessageField(interp, uid, "from"));
7996 peMessageToAddr(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
7998 return(peMessageField(interp, uid, "to"));
8003 peMessageCcAddr(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
8005 return(peMessageField(interp, uid, "cc"));
8010 peMessageSubject(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
8012 return(peMessageField(interp, uid, "subject"));
8017 peMessageField(Tcl_Interp *interp, imapuid_t uid, char *field)
8019 long raw;
8020 char *s = "";
8021 ENVELOPE *env;
8023 if((raw = peSequenceNumber(uid))
8024 && (env = pine_mail_fetchstructure(wps_global->mail_stream, raw, NULL))){
8025 if(!strucmp(field, "from")){
8026 if(env->from && env->from->mailbox)
8027 snprintf(s = wtmp_20k_buf, SIZEOF_20KBUF, "%.256s%s%.256s", env->from->mailbox,
8028 (env->from->host) ? "@" : "", (env->from->host) ? env->from->host : "");
8030 else if(!strucmp(field, "to")){
8031 if(env->to && env->to->mailbox)
8032 snprintf(s = wtmp_20k_buf, SIZEOF_20KBUF, "%.256s%s%.256s", env->to->mailbox,
8033 (env->to->host) ? "@" : "", (env->to->host) ? env->to->host : "");
8035 else if(!strucmp(field, "cc")){
8036 if(env->cc && env->cc->mailbox)
8037 snprintf(s = wtmp_20k_buf, SIZEOF_20KBUF, "%.256s%s%.256s", env->cc->mailbox,
8038 (env->cc->host) ? "@" : "", (env->cc->host) ? env->cc->host : "");
8040 else if(!strucmp(field, "subject")){
8041 if(env->subject)
8042 snprintf(s = wtmp_20k_buf, SIZEOF_20KBUF, "%.256s", env->subject);
8044 else{
8045 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Unknown message field: %.20s", field);
8046 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
8047 return(TCL_ERROR);
8050 Tcl_SetResult(interp, s, TCL_VOLATILE);
8051 return(TCL_OK);
8054 Tcl_SetResult(interp, "Can't read message envelope", TCL_STATIC);
8055 return(TCL_ERROR);
8060 peMessageStatus(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
8062 long raw;
8063 MESSAGECACHE *mc;
8065 if((raw = peSequenceNumber(uid)) != 0L){
8066 if(!((mc = mail_elt(wps_global->mail_stream, raw))
8067 && mc->valid)){
8068 mail_fetch_flags(wps_global->mail_stream,
8069 ulong2string(uid), FT_UID);
8070 mc = mail_elt(wps_global->mail_stream, raw);
8073 if (mc->deleted)
8074 Tcl_ListObjAppendElement(interp,
8075 Tcl_GetObjResult(interp),
8076 Tcl_NewStringObj("Deleted", -1));
8078 if (mc->answered)
8079 Tcl_ListObjAppendElement(interp,
8080 Tcl_GetObjResult(interp),
8081 Tcl_NewStringObj("Answered", -1));
8083 if (!mc->seen)
8084 Tcl_ListObjAppendElement(interp,
8085 Tcl_GetObjResult(interp),
8086 Tcl_NewStringObj("New", -1));
8088 if (mc->flagged)
8089 Tcl_ListObjAppendElement(interp,
8090 Tcl_GetObjResult(interp),
8091 Tcl_NewStringObj("Important", -1));
8094 return(TCL_OK);
8099 peMessageCharset(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
8101 /* everything coming out of pith better be utf-8 */
8102 Tcl_SetResult(interp, "UTF-8", TCL_STATIC);
8103 return(TCL_OK);
8108 peMessageNeedPassphrase(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
8110 #ifdef SMIME
8111 return((wps_global && wps_global->smime && wps_global->smime->need_passphrase) ? TCL_OK : TCL_ERROR);
8112 #else
8113 return(TCL_ERROR);
8114 #endif /* SMIME */
8119 peMsgnoFromUID(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
8121 Tcl_SetResult(interp, long2string(peMessageNumber(uid)), TCL_VOLATILE);
8122 return(TCL_OK);
8127 * peInterpWritec - collect filtered output, appending to the
8128 * command's result list on each EOL
8131 peInterpWritec(int c)
8133 unsigned char ch = (unsigned char) (0xff & c);
8135 if(ch == '\n')
8136 return(peInterpFlush() == TCL_OK);
8137 else
8138 so_writec(ch, peED.store);
8140 return(1);
8145 * peInterpFlush - write accumulated line to result object mapping
8146 * embedded data into exportable tcl list members
8150 peInterpFlush(void)
8152 char *line, *p, *tp, *tp2, col1[32], col2[32];
8153 Tcl_Obj *lobjp, *objColor, *objPair;
8155 line = (char *) so_text(peED.store);
8157 if((lobjp = Tcl_NewListObj(0, NULL)) != NULL){
8158 if((p = strindex(line, TAG_EMBED)) != NULL){
8160 *p = '\0';
8162 if(p - line)
8163 peAppListF(peED.interp, lobjp, "%s%s", "t", line);
8165 switch(*++p){
8166 case TAG_HANDLE :
8168 int i, n;
8169 HANDLE_S *h;
8172 for(n = 0, i = *++p; i > 0; i--)
8173 n = (n * 10) + (*++p - '0');
8175 line = ++p; /* prepare for next section of line */
8177 if(!peED.inhandle){
8178 peED.inhandle = 1;
8180 if((h = get_handle(peED.handles, n)) != NULL)
8181 switch(h->type){
8182 case IMG :
8184 Tcl_Obj *llObj, *rObj;
8186 llObj = Tcl_NewListObj(0, NULL);
8187 Tcl_ListObjAppendElement(peED.interp, llObj, Tcl_NewStringObj("img", -1));
8189 rObj = Tcl_NewListObj(0, NULL);
8190 Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewStringObj(h->h.img.src ? h->h.img.src : "", -1));
8191 Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewStringObj(h->h.img.alt ? h->h.img.alt : "", -1));
8193 Tcl_ListObjAppendElement(peED.interp, llObj, rObj);
8195 Tcl_ListObjAppendElement(peED.interp, lobjp, llObj);
8196 peED.inhandle = 0;
8199 break;
8201 case URL :
8203 Tcl_Obj *llObj, *rObj;
8205 llObj = Tcl_NewListObj(0, NULL);
8206 Tcl_ListObjAppendElement(peED.interp, llObj, Tcl_NewStringObj("urlstart", -1));
8208 rObj = Tcl_NewListObj(0, NULL);
8209 Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewStringObj(h->h.url.path ? h->h.url.path : "", -1));
8210 Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewStringObj(h->h.url.name ? h->h.url.name : "", -1));
8212 Tcl_ListObjAppendElement(peED.interp, llObj, rObj);
8214 Tcl_ListObjAppendElement(peED.interp, lobjp, llObj);
8217 break;
8219 case Attach :
8221 Tcl_Obj *alObj, *rObj, *tObj, *stObj, *fnObj, *eObj;
8223 alObj = Tcl_NewListObj(0, NULL);
8224 Tcl_ListObjAppendElement(peED.interp, alObj, Tcl_NewStringObj("attach", -1));
8226 peGetMimeTyping(mail_body(wps_global->mail_stream,
8227 peSequenceNumber(peED.uid),
8228 (unsigned char *) h->h.attach->number),
8229 &tObj, &stObj, &fnObj, &eObj);
8232 rObj = Tcl_NewListObj(0, NULL);
8233 Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewLongObj(peED.uid));
8234 Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewStringObj(h->h.attach->number, -1));
8235 Tcl_ListObjAppendElement(peED.interp, rObj, tObj);
8236 Tcl_ListObjAppendElement(peED.interp, rObj, stObj);
8237 Tcl_ListObjAppendElement(peED.interp, rObj, fnObj);
8238 Tcl_ListObjAppendElement(peED.interp, rObj, eObj);
8240 Tcl_ListObjAppendElement(peED.interp, alObj, rObj);
8242 Tcl_ListObjAppendElement(peED.interp, lobjp, alObj);
8245 break;
8247 default :
8248 break;
8253 break;
8255 case TAG_FGCOLOR :
8256 if((tp = peColorStr(++p, col1)) && (strcmp(tp, peED.color.fg) || strcmp(tp, peED.color.fgdef))){
8257 /* look ahead */
8258 if(p[11] == TAG_EMBED
8259 && p[12] == TAG_BGCOLOR
8260 && (tp2 = peColorStr(p + 13, col2))){
8261 objColor = Tcl_NewListObj(0, NULL);
8262 objPair = Tcl_NewListObj(0, NULL);
8263 Tcl_ListObjAppendElement(peED.interp, objColor, Tcl_NewStringObj("color", -1));
8264 Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp, -1));
8265 Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp2, -1));
8266 Tcl_ListObjAppendElement(peED.interp, objColor, objPair);
8267 Tcl_ListObjAppendElement(peED.interp, lobjp, objColor);
8268 strcpy(peED.color.bg, tp2);
8269 p += 13;
8271 else if(strcmp(peED.color.bg, peED.color.bgdef)){
8272 objColor = Tcl_NewListObj(0, NULL);
8273 objPair = Tcl_NewListObj(0, NULL);
8274 Tcl_ListObjAppendElement(peED.interp, objColor, Tcl_NewStringObj("color", -1));
8275 Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp, -1));
8276 Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(peED.color.bgdef, -1));
8277 Tcl_ListObjAppendElement(peED.interp, objColor, objPair);
8278 Tcl_ListObjAppendElement(peED.interp, lobjp, objColor);
8279 strcpy(peED.color.bg, peED.color.bgdef);
8281 else
8282 peAppListF(peED.interp, lobjp, "%s%s", "fgcolor", tp);
8284 strcpy(peED.color.fg, tp);
8287 line = p + 11;
8288 break;
8290 case TAG_BGCOLOR :
8291 if((tp = peColorStr(++p, col1)) && (strcmp(tp, peED.color.bg) || strcmp(tp, peED.color.bgdef))){
8292 /* look ahead */
8293 if(p[11] == TAG_EMBED
8294 && p[12] == TAG_FGCOLOR
8295 && (tp2 = peColorStr(p + 13, col2))){
8296 objColor = Tcl_NewListObj(0, NULL);
8297 objPair = Tcl_NewListObj(0, NULL);
8298 Tcl_ListObjAppendElement(peED.interp, objColor, Tcl_NewStringObj("color", -1));
8299 Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp2, -1));
8300 Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp, -1));
8301 Tcl_ListObjAppendElement(peED.interp, objColor, objPair);
8302 Tcl_ListObjAppendElement(peED.interp, lobjp, objColor);
8303 strcpy(peED.color.fg, tp2);
8304 p += 13;
8306 else if(strcmp(peED.color.fg, peED.color.fgdef)){
8307 objColor = Tcl_NewListObj(0, NULL);
8308 objPair = Tcl_NewListObj(0, NULL);
8309 Tcl_ListObjAppendElement(peED.interp, objColor, Tcl_NewStringObj("color", -1));
8310 Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(peED.color.fgdef, -1));
8311 Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp, -1));
8312 Tcl_ListObjAppendElement(peED.interp, objColor, objPair);
8313 Tcl_ListObjAppendElement(peED.interp, lobjp, objColor);
8314 strcpy(peED.color.fg, peED.color.fgdef);
8316 else
8317 peAppListF(peED.interp, lobjp, "%s%s", "bgcolor", tp);
8319 strcpy(peED.color.bg, tp);
8322 line = p + 11;
8323 break;
8325 case TAG_ITALICON :
8326 peAppListF(peED.interp, lobjp, "%s%s", "italic", "on");
8327 line = p + 1;
8328 break;
8330 case TAG_ITALICOFF :
8331 peAppListF(peED.interp, lobjp, "%s%s", "italic", "off");
8332 line = p + 1;
8333 break;
8335 case TAG_BOLDON :
8336 peAppListF(peED.interp, lobjp, "%s%s", "bold", "on");
8337 line = p + 1;
8338 break;
8340 case TAG_BOLDOFF :
8341 peAppListF(peED.interp, lobjp, "%s%s", "bold", "off");
8342 line = p + 1;
8343 break;
8345 case TAG_ULINEON :
8346 peAppListF(peED.interp, lobjp, "%s%s", "underline", "on");
8347 line = p + 1;
8348 break;
8350 case TAG_ULINEOFF :
8351 peAppListF(peED.interp, lobjp, "%s%s", "underline", "off");
8352 line = p + 1;
8353 break;
8355 case TAG_STRIKEON :
8356 peAppListF(peED.interp, lobjp, "%s%s", "strikethru", "on");
8357 line = p + 1;
8358 break;
8360 case TAG_STRIKEOFF :
8361 peAppListF(peED.interp, lobjp, "%s%s", "strikethru", "off");
8362 line = p + 1;
8363 break;
8365 case TAG_BIGON :
8366 peAppListF(peED.interp, lobjp, "%s%s", "bigfont", "on");
8367 line = p + 1;
8368 break;
8370 case TAG_BIGOFF :
8371 peAppListF(peED.interp, lobjp, "%s%s", "bigfont", "off");
8372 line = p + 1;
8373 break;
8375 case TAG_SMALLON :
8376 peAppListF(peED.interp, lobjp, "%s%s", "smallfont", "on");
8377 line = p + 1;
8378 break;
8380 case TAG_SMALLOFF :
8381 peAppListF(peED.interp, lobjp, "%s%s", "smallfont", "off");
8382 line = p + 1;
8383 break;
8385 case TAG_INVOFF :
8386 case TAG_HANDLEOFF :
8387 if(peED.inhandle){
8388 peAppListF(peED.interp, lobjp, "%s%s", "urlend", "");
8389 peED.inhandle = 0;
8391 /* fall thru and advance "line" */
8393 default :
8394 line = p + 1;
8395 break;
8399 while((p = strindex(line, TAG_EMBED)) != NULL);
8401 if(*line)
8402 peAppListF(peED.interp, lobjp, "%s%s", "t", line);
8404 else
8405 peAppListF(peED.interp, lobjp, "%s%s", "t", line);
8407 else
8408 peAppListF(peED.interp, lobjp, "%s%s", "t", "");
8410 if(Tcl_ListObjAppendElement(peED.interp, peED.obj, lobjp) == TCL_OK){
8411 so_truncate(peED.store, 0L);
8412 return(TCL_OK);
8415 return(TCL_ERROR);
8421 * peInterpWritec - collect filtered output, appending to the
8422 * command's result list on each EOL
8425 peNullWritec(int c)
8427 return(1);
8431 char *
8432 peColorStr(char *s, char *b)
8434 int i, j, color;
8436 i = 0;
8437 b[0] = '\0';
8438 while(1){
8439 color = 0;
8440 for(j = 0; j < 3; j++, s++)
8441 if(isdigit((unsigned char) *s))
8442 color = (color * 10) + (*s - '0');
8444 s++; /* advance past ',' */
8445 if(color < 256)
8446 sprintf(b + strlen(b), "%2.2x", color);
8447 else
8448 break;
8450 if(++i == 3)
8451 return(b);
8455 return(NULL);
8460 * returns a list of elements
8463 peMessageHeader(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
8465 MESSAGECACHE *mc;
8466 HEADER_S h;
8467 int flags, rv = TCL_OK;
8468 long raw;
8469 #if 0
8470 char *color;
8471 #endif
8474 * ONLY full header mode (raw) output should get written to the
8475 * writec function we pass format_header. If there's something
8476 * in the store after formatting ,we'll write it to the Tcl result
8477 * then, not as its accumulated
8479 peED.interp = interp;
8480 peED.obj = Tcl_NewStringObj("", -1);
8482 if(peED.store)
8483 so_seek(peED.store, 0L, 0);
8484 else
8485 peED.store = so_get(CharStar, NULL, EDIT_ACCESS);
8487 flags = FM_DISPLAY | FM_NEW_MESS | FM_NOEDITORIAL | FM_NOHTMLREL | FM_HTMLRELATED;
8489 #if 0
8490 peED.color.fg[0] = '\0';
8491 if((color = pico_get_last_fg_color()) && (color = color_to_asciirgb(color))){
8492 peInterpWritec(TAG_EMBED);
8493 peInterpWritec(TAG_FGCOLOR);
8494 gf_puts(color, peInterpWritec);
8495 strcpy(peED.color.fgdef, peColorStr(color, wtmp_20k_buf));
8498 peED.color.bg[0] = '\0';
8499 if((color = pico_get_last_bg_color()) && (color = color_to_asciirgb(color))){
8500 peInterpWritec(TAG_EMBED);
8501 peInterpWritec(TAG_BGCOLOR);
8502 gf_puts(color, peInterpWritec);
8503 strcpy(peED.color.bgdef, peColorStr(color,wtmp_20k_buf));
8506 peInterpFlush();
8507 #endif
8509 raw = peSequenceNumber(uid);
8510 if(peED.uid != uid){
8511 peED.uid = uid;
8512 peED.body = NULL;
8514 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
8515 if(!((peED.env = pine_mail_fetchstructure(wps_global->mail_stream, raw, &peED.body))
8516 && (mc = mail_elt(wps_global->mail_stream, raw)))){
8517 char buf[256];
8519 snprintf(buf, sizeof(buf), "Error getting message %ld: %s", peMessageNumber(uid),
8520 wps_global->last_error[0] ? wps_global->last_error : "Indeterminate");
8522 dprint((1, "ERROR fetching %s of msg %ld: %s",
8523 peED.env ? "elt" : "env", mn_get_cur(sp_msgmap(wps_global->mail_stream)),
8524 wps_global->last_error[0] ? wps_global->last_error : "Indeterminate"));
8526 Tcl_SetResult(interp, buf, TCL_VOLATILE);
8527 rv = TCL_ERROR;
8529 else{
8530 zero_atmts(wps_global->atmts);
8531 #ifdef SMIME
8532 if(wps_global && wps_global->smime && wps_global->smime->need_passphrase)
8533 wps_global->smime->need_passphrase = 0;
8535 fiddle_smime_message(peED.body, raw);
8536 #endif
8537 describe_mime(peED.body, "", 1, 1, 0, flags);
8541 /* NO HANDLES init_handles(&peED.handles);*/
8544 * Collect header pieces into lists via the passed custom formatter. Collect
8545 * everything else in the storage object passed. The latter should only end up
8546 * with raw header data.
8548 * BUG: DEAL WITH COLORS
8550 if(rv == TCL_OK){
8551 HD_INIT(&h, wps_global->VAR_VIEW_HEADERS, wps_global->view_all_except, FE_DEFAULT);
8552 if(format_header(wps_global->mail_stream, raw, NULL, peED.env, &h,
8553 NULL, NULL, flags, peFormatEnvelope, peInterpWritec) != 0){
8554 char buf[256];
8556 snprintf(buf, sizeof(buf), "Error formatting header %ld", peMessageNumber(uid));
8557 dprint((1, buf));
8559 Tcl_SetResult(interp, buf, TCL_VOLATILE);
8560 rv = TCL_ERROR;
8564 peInterpFlush();
8565 peAppListF(peED.interp, Tcl_GetObjResult(peED.interp), "%s%s%o", "raw", "", peED.obj);
8567 so_give(&peED.store);
8568 return(rv);
8571 void
8572 peFormatEnvelope(MAILSTREAM *s, long int n, char *sect, ENVELOPE *e, gf_io_t pc, long int which, char *oacs, int flags)
8574 char *p2, buftmp[MAILTMPLEN];
8575 Tcl_Obj *objHdr;
8577 if(!e)
8578 return;
8580 if((which & FE_DATE) && e->date) {
8581 if((objHdr = Tcl_NewListObj(0, NULL)) != NULL){
8582 snprintf(buftmp, sizeof(buftmp), "%s", (char *) e->date);
8583 buftmp[sizeof(buftmp)-1] = '\0';
8584 p2 = (char *)rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf, SIZEOF_20KBUF, buftmp);
8585 peFormatEnvelopeText("Date", p2);
8587 /* BUG: how does error feedback bubble back up? */
8590 if((which & FE_FROM) && e->from)
8591 peFormatEnvelopeAddress(s, n, sect, "From", e->from, flags, oacs, pc);
8593 if((which & FE_REPLYTO) && e->reply_to && (!e->from || !address_is_same(e->reply_to, e->from)))
8594 peFormatEnvelopeAddress(s, n, sect, "Reply-To", e->reply_to, flags, oacs, pc);
8596 if((which & FE_TO) && e->to)
8597 peFormatEnvelopeAddress(s, n, sect, "To", e->to, flags, oacs, pc);
8599 if((which & FE_CC) && e->cc)
8600 peFormatEnvelopeAddress(s, n, sect, "Cc", e->cc, flags, oacs, pc);
8602 if((which & FE_BCC) && e->bcc)
8603 peFormatEnvelopeAddress(s, n, sect, "Bcc", e->bcc, flags, oacs, pc);
8605 if((which & FE_RETURNPATH) && e->return_path)
8606 peFormatEnvelopeAddress(s, n, sect, "Return-Path", e->return_path, flags, oacs, pc);
8608 if((which & FE_NEWSGROUPS) && e->newsgroups)
8609 peFormatEnvelopeNewsgroups("Newsgroups", e->newsgroups, flags, pc);
8611 if((which & FE_FOLLOWUPTO) && e->followup_to)
8612 peFormatEnvelopeNewsgroups("Followup-To", e->followup_to, flags, pc);
8614 if((which & FE_SUBJECT) && e->subject && e->subject[0]){
8615 if((objHdr = Tcl_NewListObj(0, NULL)) != NULL){
8616 char *freeme = NULL;
8618 p2 = iutf8ncpy((char *)(wtmp_20k_buf+10000),
8619 (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf, 10000, e->subject),
8620 SIZEOF_20KBUF-10000);
8622 if(flags & FM_DISPLAY
8623 && (wps_global->display_keywords_in_subject
8624 || wps_global->display_keywordinits_in_subject)){
8626 /* don't bother if no keywords are defined */
8627 if(some_user_flags_defined(s))
8628 p2 = freeme = prepend_keyword_subject(s, n, p2,
8629 wps_global->display_keywords_in_subject ? KW : KWInit,
8630 NULL, wps_global->VAR_KW_BRACES);
8633 peFormatEnvelopeText("Subject", p2);
8635 if(freeme)
8636 fs_give((void **) &freeme);
8640 if((which & FE_SENDER) && e->sender && (!e->from || !address_is_same(e->sender, e->from)))
8641 peFormatEnvelopeAddress(s, n, sect, "Sender", e->sender, flags, oacs, pc);
8643 if((which & FE_MESSAGEID) && e->message_id){
8644 p2 = iutf8ncpy((char *)(wtmp_20k_buf+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf, 10000, e->message_id), SIZEOF_20KBUF-10000);
8645 peFormatEnvelopeText("Message-ID", p2);
8648 if((which & FE_INREPLYTO) && e->in_reply_to){
8649 p2 = iutf8ncpy((char *)(wtmp_20k_buf+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf, 10000, e->in_reply_to), SIZEOF_20KBUF-10000);
8650 peFormatEnvelopeText("In-Reply-To", p2);
8653 if((which & FE_REFERENCES) && e->references) {
8654 p2 = iutf8ncpy((char *)(wtmp_20k_buf+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)wtmp_20k_buf, 10000, e->references), SIZEOF_20KBUF-10000);
8655 peFormatEnvelopeText("References", p2);
8661 * appends caller's result with: {"text" field_name {field_value}}
8663 void
8664 peFormatEnvelopeText(char *field_name, char *field_value)
8666 peAppListF(peED.interp, Tcl_GetObjResult(peED.interp), "%s%s%s", "text", field_name, field_value);
8671 * appends caller's result with: {"addr" field_name {{{personal} {mailbox}} ... }}
8672 * {"rawaddr" field_name {{raw_address} ... }}
8674 void
8675 peFormatEnvelopeAddress(MAILSTREAM *stream, long int msgno, char *section, char *field_name,
8676 struct mail_address *addr, int flags, char *oacs, gf_io_t pc)
8678 char *ptmp, *mtmp, *atype = "addr";
8679 int group = 0;
8680 ADDRESS *atmp;
8681 Tcl_Obj *objAddrList = NULL;
8682 STORE_S *tso;
8683 gf_io_t tpc;
8684 extern const char *rspecials;
8685 extern const char *rspecials_minus_quote_and_dot;
8687 if(!addr)
8688 return;
8691 * quickly run down address list to make sure none are patently bogus.
8692 * If so, just blat raw field out.
8694 for(atmp = addr; stream && atmp; atmp = atmp->next)
8695 if(atmp->host && atmp->host[0] == '.'){
8696 char *field, *fields[2];
8698 atype = "rawaddr";
8699 if((objAddrList = Tcl_NewListObj(0,NULL)) == NULL)
8700 return; /* BUG: handle list creation failure */
8702 fields[1] = NULL;
8703 fields[0] = cpystr(field_name);
8704 if((ptmp = strchr(fields[0], ':')) != NULL)
8705 *ptmp = '\0';
8707 if((field = pine_fetchheader_lines(stream, msgno, section, fields)) != NULL){
8708 char *h, *t;
8710 for(t = h = field; *h ; t++)
8711 if(*t == '\015' && *(t+1) == '\012'){
8712 *t = '\0'; /* tie off line */
8714 Tcl_ListObjAppendElement(peED.interp, objAddrList, Tcl_NewStringObj(h,-1));
8716 if(!*(h = (++t) + 1)) /* set new h and skip CRLF */
8717 break; /* no more to write */
8719 else if(!*t){ /* shouldn't happen much */
8720 if(h != t)
8721 Tcl_ListObjAppendElement(peED.interp, objAddrList, Tcl_NewStringObj(h,-1));
8723 break;
8726 fs_give((void **)&field);
8729 fs_give((void **)&fields[0]);
8732 if(!objAddrList){
8733 if((objAddrList = Tcl_NewListObj(0,NULL)) == NULL || (tso = so_get(CharStar, NULL, EDIT_ACCESS)) == NULL)
8734 return; /* BUG: handle list creation failure */
8736 gf_set_so_writec(&tpc, tso);
8738 while(addr){
8740 atmp = addr->next; /* remember what's next */
8741 addr->next = NULL;
8742 if(!addr->host && addr->mailbox){
8743 mtmp = addr->mailbox;
8744 addr->mailbox = cpystr((char *)rfc1522_decode_to_utf8(
8745 (unsigned char *)wtmp_20k_buf,
8746 SIZEOF_20KBUF, addr->mailbox));
8749 ptmp = addr->personal; /* RFC 1522 personal name? */
8750 addr->personal = iutf8ncpy((char *)wtmp_20k_buf, (char *)rfc1522_decode_to_utf8((unsigned char *)(wtmp_20k_buf+10000), SIZEOF_20KBUF-10000, addr->personal), 10000);
8751 wtmp_20k_buf[10000-1] = '\0';
8754 /* Logic taken from: pine_rfc822_write_address_noquote(addr, pc, &group); */
8755 if (addr->host) { /* ordinary address? */
8756 if (!(addr->personal || addr->adl)){
8757 so_seek(tso, 0L, 0);
8758 pine_rfc822_address (addr, tpc);
8759 peAppListF(peED.interp, objAddrList, "%s%o", "", Tcl_NewStringObj((char *) so_text(tso), so_tell(tso)));
8761 else { /* no, must use phrase <route-addr> form */
8762 Tcl_Obj *objTmp;
8764 if (addr->personal){
8765 so_seek(tso, 0L, 0);
8766 pine_rfc822_cat (addr->personal, rspecials_minus_quote_and_dot, tpc);
8767 objTmp = Tcl_NewStringObj((char *) so_text(tso), so_tell(tso));
8770 so_seek(tso, 0L, 0);
8771 pine_rfc822_address(addr, tpc);
8772 peAppListF(peED.interp, objAddrList, "%o%o", objTmp, Tcl_NewStringObj((char *) so_text(tso), so_tell(tso)));
8775 if(group)
8776 group++;
8778 else if (addr->mailbox) { /* start of group? */
8779 so_seek(tso, 0L, 0);
8780 /* yes, write group name */
8781 pine_rfc822_cat (addr->mailbox, rspecials, tpc);
8782 peAppListF(peED.interp, objAddrList, "%o%s", Tcl_NewStringObj((char *) so_text(tso), so_tell(tso)), "");
8783 group = 1; /* in a group */
8785 else if (group) { /* must be end of group (but be paranoid) */
8786 peAppListF(peED.interp, objAddrList, "%s%s", "", ";");
8787 group = 0; /* no longer in that group */
8790 addr->personal = ptmp; /* restore old personal ptr */
8791 if(!addr->host && addr->mailbox){
8792 fs_give((void **)&addr->mailbox);
8793 addr->mailbox = mtmp;
8796 addr->next = atmp;
8797 addr = atmp;
8800 gf_clear_so_writec(tso);
8801 so_give(&tso);
8804 peAppListF(peED.interp, Tcl_GetObjResult(peED.interp), "%s%s%o", atype, field_name, objAddrList);
8809 * appends caller's result with: {"news" field_name {{newsgroup1} {newsgroup2} ... }}
8811 void
8812 peFormatEnvelopeNewsgroups(char *field_name, char *newsgrps, int flags, gf_io_t pc)
8814 char buf[MAILTMPLEN];
8815 int llen;
8816 char *next_ng;
8817 Tcl_Obj *objNewsgroups;
8819 /* BUG: handle list creation failure */
8820 if(!newsgrps || !*newsgrps || (objNewsgroups = Tcl_NewListObj(0,NULL)) == NULL)
8821 return;
8823 llen = strlen(field_name);
8824 while(*newsgrps){
8825 for(next_ng = newsgrps; *next_ng && *next_ng != ','; next_ng++)
8828 strncpy(buf, newsgrps, MIN(next_ng - newsgrps, sizeof(buf)-1));
8829 buf[MIN(next_ng - newsgrps, sizeof(buf)-1)] = '\0';
8831 Tcl_ListObjAppendElement(peED.interp, objNewsgroups, Tcl_NewStringObj(buf,-1));
8833 newsgrps = next_ng;
8834 if(*newsgrps)
8835 newsgrps++;
8838 peAppListF(peED.interp, Tcl_GetObjResult(peED.interp), "news", field_name, objNewsgroups);
8843 peMessageAttachments(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
8845 MESSAGECACHE *mc;
8846 ATTACH_S *a;
8847 BODY *body;
8848 Tcl_Obj *objAtt, *tObj, *stObj, *fnObj;
8849 int flags, rv = TCL_OK;
8850 long raw;
8852 peED.interp = interp;
8853 peED.obj = Tcl_GetObjResult(interp);
8855 flags = FM_DISPLAY | FM_NEW_MESS | FM_NOEDITORIAL | FM_HTML | FM_NOHTMLREL | FM_HTMLRELATED | FM_HIDESERVER;
8857 raw = peSequenceNumber(uid);
8859 if(peED.uid != uid){
8860 memset(&peED, 0, sizeof(peED));
8862 peED.uid = uid;
8864 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
8865 if(!((peED.env = pine_mail_fetchstructure(wps_global->mail_stream, raw, &peED.body))
8866 && (mc = mail_elt(wps_global->mail_stream, raw)))){
8867 char buf[256];
8869 snprintf(buf, sizeof(buf), "Error getting message %ld: %s", peMessageNumber(uid),
8870 wps_global->last_error[0] ? wps_global->last_error : "Indeterminate");
8872 dprint((1, "ERROR fetching %s of msg %ld: %s",
8873 peED.env ? "elt" : "env", mn_get_cur(sp_msgmap(wps_global->mail_stream)),
8874 wps_global->last_error[0] ? wps_global->last_error : "Indeterminate"));
8876 Tcl_SetResult(interp, buf, TCL_VOLATILE);
8877 rv = TCL_ERROR;
8879 else{
8880 zero_atmts(wps_global->atmts);
8881 #ifdef SMIME
8882 if(wps_global && wps_global->smime && wps_global->smime->need_passphrase)
8883 wps_global->smime->need_passphrase = 0;
8885 fiddle_smime_message(peED.body, raw);
8886 #endif
8887 describe_mime(peED.body, "", 1, 1, 0, flags);
8891 /* package up attachment list */
8892 for(a = wps_global->atmts; rv == TCL_OK && a->description != NULL; a++)
8893 if((objAtt = Tcl_NewListObj(0, NULL)) != NULL
8894 && (body = mail_body(wps_global->mail_stream, raw, (unsigned char *) a->number)) != NULL){
8895 peGetMimeTyping(body, &tObj, &stObj, &fnObj, NULL);
8897 if(!(peAppListF(interp, objAtt, "%s", a->number ? a->number : "") == TCL_OK
8898 && peAppListF(interp, objAtt, "%s", a->shown ? "shown" : "") == TCL_OK
8899 && Tcl_ListObjAppendElement(interp, objAtt, tObj) == TCL_OK
8900 && Tcl_ListObjAppendElement(interp, objAtt, stObj) == TCL_OK
8901 && Tcl_ListObjAppendElement(interp, objAtt, fnObj) == TCL_OK
8902 && peAppListF(interp, objAtt, "%s", a->body->description) == TCL_OK
8903 && Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAtt) == TCL_OK))
8904 rv = TCL_ERROR;
8906 else
8907 rv = TCL_ERROR;
8909 return(rv);
8914 peMessageBody(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
8916 MESSAGECACHE *mc;
8917 int flags, rv = TCL_OK;
8918 long raw;
8919 char *color;
8921 peED.interp = interp;
8922 peED.obj = Tcl_GetObjResult(interp);
8924 if(peED.store)
8925 so_seek(peED.store, 0L, 0);
8926 else
8927 peED.store = so_get(CharStar, NULL, EDIT_ACCESS);
8929 flags = FM_DISPLAY | FM_NEW_MESS | FM_NOEDITORIAL | FM_NOHTMLREL | FM_HTMLRELATED;
8931 if(objc == 1 && objv[0]){ /* flags */
8932 int i, nFlags;
8933 Tcl_Obj **objFlags;
8934 char *flagstr;
8936 Tcl_ListObjGetElements(interp, objv[0], &nFlags, &objFlags);
8937 for(i = 0; i < nFlags; i++){
8938 if((flagstr = Tcl_GetStringFromObj(objFlags[i], NULL)) == NULL){
8939 rv = TCL_ERROR;
8942 if(!strucmp(flagstr, "html"))
8943 flags |= (FM_HTML | FM_HIDESERVER);
8944 else if(!strucmp(flagstr, "images"))
8945 flags |= (FM_HTMLIMAGES);
8949 peED.color.fg[0] = '\0';
8950 if((color = pico_get_last_fg_color()) && (color = color_to_asciirgb(color))){
8951 peInterpWritec(TAG_EMBED);
8952 peInterpWritec(TAG_FGCOLOR);
8953 gf_puts(color, peInterpWritec);
8954 strcpy(peED.color.fgdef, peColorStr(color, wtmp_20k_buf));
8957 peED.color.bg[0] = '\0';
8958 if((color = pico_get_last_bg_color()) && (color = color_to_asciirgb(color))){
8959 peInterpWritec(TAG_EMBED);
8960 peInterpWritec(TAG_BGCOLOR);
8961 gf_puts(color, peInterpWritec);
8962 strcpy(peED.color.bgdef, peColorStr(color,wtmp_20k_buf));
8965 peInterpFlush();
8967 init_handles(&peED.handles);
8969 raw = peSequenceNumber(uid);
8971 if(peED.uid != uid){
8972 peED.uid = uid;
8973 peED.body = NULL;
8975 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
8976 if(!((peED.env = pine_mail_fetchstructure(wps_global->mail_stream, raw, &peED.body))
8977 && (mc = mail_elt(wps_global->mail_stream, raw)))){
8978 char buf[256];
8980 snprintf(buf, sizeof(buf), "Error getting message %ld: %s", peMessageNumber(uid),
8981 wps_global->last_error[0] ? wps_global->last_error : "Indeterminate");
8983 dprint((1, "ERROR fetching %s of msg %ld: %s",
8984 peED.env ? "elt" : "env", mn_get_cur(sp_msgmap(wps_global->mail_stream)),
8985 wps_global->last_error[0] ? wps_global->last_error : "Indeterminate"));
8987 Tcl_SetResult(interp, buf, TCL_VOLATILE);
8988 rv = TCL_ERROR;
8990 else{
8991 zero_atmts(wps_global->atmts);
8992 #ifdef SMIME
8993 if(wps_global && wps_global->smime && wps_global->smime->need_passphrase)
8994 wps_global->smime->need_passphrase = 0;
8996 fiddle_smime_message(peED.body, raw);
8997 #endif
8998 describe_mime(peED.body, "", 1, 1, 0, flags);
9002 /* format message body */
9003 if(rv == TCL_OK){
9004 HEADER_S h;
9005 char *errstr;
9007 HD_INIT(&h, wps_global->VAR_VIEW_HEADERS, wps_global->view_all_except, FE_DEFAULT);
9008 #ifdef SMIME
9009 /* kind of a hack, the description maybe shouldn't be in the editorial stuff */
9010 if(wps_global->smime && wps_global->smime->need_passphrase)
9011 flags &= ~FM_NOEDITORIAL;
9012 #endif
9013 if((errstr = format_body(raw, peED.body, &peED.handles, &h, flags, FAKE_SCREEN_WIDTH, peInterpWritec)) != NULL){
9014 gf_puts(errstr, peInterpWritec);
9015 rv = TCL_ERROR;
9019 peInterpFlush();
9021 so_give(&peED.store);
9022 free_handles(&peED.handles);
9023 return(rv);
9028 peMessageText(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9030 MESSAGECACHE *mc;
9031 ENVELOPE *env;
9032 BODY *body;
9033 int flags;
9034 long raw;
9035 char *color;
9037 memset(&peED, 0, sizeof(peED));
9038 peED.interp = interp;
9039 peED.obj = Tcl_GetObjResult(interp);
9040 peED.store = so_get(CharStar, NULL, EDIT_ACCESS);
9042 peED.color.fg[0] = '\0';
9043 if((color = pico_get_last_fg_color()) && (color = color_to_asciirgb(color))){
9044 peInterpWritec(TAG_EMBED);
9045 peInterpWritec(TAG_FGCOLOR);
9046 gf_puts(color, peInterpWritec);
9047 strcpy(peED.color.fgdef, peColorStr(color, wtmp_20k_buf));
9050 peED.color.bg[0] = '\0';
9051 if((color = pico_get_last_bg_color()) && (color = color_to_asciirgb(color))){
9052 peInterpWritec(TAG_EMBED);
9053 peInterpWritec(TAG_BGCOLOR);
9054 gf_puts(color, peInterpWritec);
9055 strcpy(peED.color.bgdef, peColorStr(color,wtmp_20k_buf));
9058 raw = peSequenceNumber(peED.uid = uid);
9059 body = NULL;
9060 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
9061 if(!((env = pine_mail_fetchstructure(wps_global->mail_stream, raw, &body))
9062 && (mc = mail_elt(wps_global->mail_stream, raw)))){
9063 char buf[256];
9065 snprintf(buf, sizeof(buf), "Error getting message %ld: %s", peMessageNumber(uid),
9066 wps_global->last_error[0] ? wps_global->last_error : "Indeterminate");
9068 dprint((1, "ERROR fetching %s of msg %ld: %s",
9069 env ? "elt" : "env", mn_get_cur(sp_msgmap(wps_global->mail_stream)),
9070 wps_global->last_error[0] ? wps_global->last_error : "Indeterminate"));
9072 Tcl_SetResult(interp, buf, TCL_VOLATILE);
9073 return(TCL_ERROR);
9076 flags = FM_DISPLAY | FM_NEW_MESS | FM_NOEDITORIAL | FM_NOHTMLREL | FM_HTMLRELATED;
9078 init_handles(&peED.handles);
9080 (void) format_message(raw, env, body, &peED.handles, flags, peInterpWritec);
9082 peInterpFlush();
9084 so_give(&peED.store);
9085 free_handles(&peED.handles);
9086 return(TCL_OK);
9091 * peMessagePartFromCID - return part number assoc'd with given uid and CID
9094 peMessagePartFromCID(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9096 char *cid, sect_buf[256];
9097 long raw;
9098 ENVELOPE *env;
9099 BODY *body;
9101 raw = peSequenceNumber(peED.uid = uid);
9102 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
9104 if(objv[0] && (cid = Tcl_GetStringFromObj(objv[0], NULL)) && *cid != '\0'){
9105 if((env = pine_mail_fetchstructure(wps_global->mail_stream, raw, &body)) != NULL){
9106 sect_buf[0] = '\0';
9107 if(peLocateBodyByCID(cid, sect_buf, body)){
9108 Tcl_SetResult(interp, sect_buf, TCL_VOLATILE);
9111 else{
9112 Tcl_SetResult(interp, wps_global->last_error[0] ? wps_global->last_error : "Error getting CID", TCL_VOLATILE);
9113 return(TCL_ERROR);
9117 return(TCL_OK);
9122 peLocateBodyByCID(char *cid, char *section, BODY *body)
9124 if(body->type == TYPEMULTIPART){
9125 char subsection[256], *subp;
9126 int n;
9127 PART *part = body->nested.part;
9129 if(!(part = body->nested.part))
9130 return(0);
9132 subp = subsection;
9133 if(section && *section){
9134 for(n = 0;
9135 n < sizeof(subsection)-20 && (*subp = section[n]); n++, subp++)
9138 *subp++ = '.';
9141 n = 1;
9142 do {
9143 sprintf(subp, "%d", n++);
9144 if(peLocateBodyByCID(cid, subsection, &part->body)){
9145 strcpy(section, subsection);
9146 return(1);
9149 while((part = part->next) != NULL);
9151 return(0);
9154 return((body && body->id) ? !strcmp(cid, body->id) : 0);
9159 * peGetFlag - Return 1 or 0 based on requested flags current state
9161 * Params: argv[0] == flagname
9164 peGetFlag(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9166 char *flagname;
9168 Tcl_SetResult(interp,
9169 int2string(((flagname = Tcl_GetStringFromObj(objv[0], NULL)) != NULL)
9170 ? peIsFlagged(wps_global->mail_stream, uid, flagname)
9171 : 0),
9172 TCL_VOLATILE);
9173 return(TCL_OK);
9178 peIsFlagged(MAILSTREAM *stream, imapuid_t uid, char *flagname)
9180 MESSAGECACHE *mc;
9181 long raw = peSequenceNumber(uid);
9183 if(!((mc = mail_elt(stream, raw)) && mc->valid)){
9184 mail_fetch_flags(stream, ulong2string(uid), FT_UID);
9185 mc = mail_elt(stream, raw);
9188 if(!strucmp(flagname, "deleted"))
9189 return(mc->deleted);
9191 if(!strucmp(flagname, "new"))
9192 return(!mc->seen);
9194 if(!strucmp(flagname, "important"))
9195 return(mc->flagged);
9197 if(!strucmp(flagname, "answered"))
9198 return(mc->answered);
9200 if(!strucmp(flagname, "recent"))
9201 return(mc->recent);
9203 return(0);
9208 * peSetFlag - Set requested flags value to 1 or 0
9210 * Params: abjv[0] == flagname
9211 * objv[1] == newvalue
9214 peSetFlag(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9216 char *flagname, *flagstr = NULL;
9217 int value;
9219 if((flagname = Tcl_GetStringFromObj(objv[0], NULL))
9220 && Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_ERROR){
9221 if(!strucmp(flagname, "deleted")){
9222 flagstr = "\\DELETED";
9224 else if(!strucmp(flagname, "new")){
9225 flagstr = "\\SEEN";
9226 value = !value;
9228 else if(!strucmp(flagname, "important")){
9229 flagstr = "\\FLAGGED";
9231 else if(!strucmp(flagname, "answered")){
9232 flagstr = "\\ANSWERED";
9234 else if(!strucmp(flagname, "recent")){
9235 flagstr = "\\RECENT";
9238 if(flagstr){
9239 wps_global->c_client_error[0] = '\0';
9240 mail_flag(wps_global->mail_stream,
9241 ulong2string(uid),
9242 flagstr, (value ? ST_SET : 0L) | ST_UID);
9243 if(wps_global->c_client_error[0] != '\0'){
9244 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "peSetFlag: %.40s",
9245 wps_global->c_client_error);
9246 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
9247 return(TCL_ERROR);
9252 Tcl_SetResult(interp, value ? "1" : "0", TCL_STATIC);
9253 return(TCL_OK);
9258 * peMsgSelect - Return 1 or 0 based on whether given UID is selected
9260 * Params: argv[0] == selected
9263 peMsgSelect(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9265 int value;
9267 if(objc == 1 && objv[0]){
9268 if(Tcl_GetIntFromObj(interp, objv[0], &value) != TCL_ERROR){
9269 if(value){
9270 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream),
9271 peMessageNumber(uid), MN_SLCT, 1);
9272 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream),
9273 peMessageNumber(uid), MN_HIDE, 0);
9274 } else {
9275 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream),
9276 peMessageNumber(uid), MN_SLCT, 0);
9277 /* if zoomed, lite hidden bit */
9278 if(any_lflagged(sp_msgmap(wps_global->mail_stream), MN_HIDE))
9279 set_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream),
9280 peMessageNumber(uid), MN_HIDE, 1);
9284 else{
9285 Tcl_SetResult(interp, "peMsgSelect: can't get value", TCL_STATIC);
9286 return(TCL_ERROR);
9290 Tcl_SetResult(interp,
9291 (get_lflag(wps_global->mail_stream, NULL,
9292 peSequenceNumber(uid),
9293 MN_SLCT))
9294 ? "1" : "0",
9295 TCL_VOLATILE);
9296 return(TCL_OK);
9301 * peAppendIndexParts - append list of digested index pieces to given object
9303 * Params:
9307 peAppendIndexParts(Tcl_Interp *interp, imapuid_t uid, Tcl_Obj *aObj, int *fetched)
9309 Tcl_Obj *objField, *objElement, *objp;
9310 ICE_S *h;
9311 IFIELD_S *f;
9312 IELEM_S *ie;
9315 if((h = build_header_work(wps_global, wps_global->mail_stream,
9316 sp_msgmap(wps_global->mail_stream), peMessageNumber(uid),
9317 gPeITop, gPeICount, fetched)) != NULL){
9318 for(f = h->ifield; f; f = f->next){
9320 if((objField = Tcl_NewListObj(0, NULL)) == NULL)
9321 return(TCL_ERROR);
9323 for(ie = f->ielem; ie ; ie = ie->next){
9325 if((objElement = Tcl_NewListObj(0, NULL)) == NULL)
9326 return(TCL_ERROR);
9328 if(ie->datalen){
9329 /* FIRST: DATA */
9330 #if INTERNAL_INDEX_TRUNCATE
9331 char *ep;
9333 ep = (char *) fs_get((ie->datalen + 1) * sizeof(char));
9334 sprintf(ep, "%.*s", ie->wid, ie->data);
9336 /* and other stuff to pack trunc'd element into a new object */
9337 #endif
9339 objp = Tcl_NewStringObj(ie->data, ie->datalen);
9341 else
9342 objp = Tcl_NewStringObj("", -1);
9344 if(Tcl_ListObjAppendElement(interp, objElement, objp) != TCL_OK)
9345 return(TCL_ERROR);
9347 if(ie->color){
9348 Tcl_Obj *objColor;
9349 char hexcolor[32];
9351 if((objp = Tcl_NewListObj(0, NULL)) == NULL)
9352 return(TCL_ERROR);
9354 hex_colorstr(hexcolor, ie->color->fg);
9355 objColor = Tcl_NewStringObj(hexcolor, -1);
9356 if(Tcl_ListObjAppendElement(interp, objp, objColor) != TCL_OK)
9357 return(TCL_ERROR);
9359 hex_colorstr(hexcolor, ie->color->bg);
9360 objColor = Tcl_NewStringObj(hexcolor, -1);
9361 if(Tcl_ListObjAppendElement(interp, objp, objColor) != TCL_OK)
9362 return(TCL_ERROR);
9364 else
9365 objp = Tcl_NewStringObj("", -1);
9367 if(Tcl_ListObjAppendElement(interp, objElement, objp) != TCL_OK)
9368 return(TCL_ERROR);
9371 * IF we ever want to map the thread characters into nice
9372 * graphical symbols or take advantage of features like clicking
9373 * on a thread element to collapse and such, we need to have
9374 * element tagging. That's what the object creation and append
9375 * are placeholders for
9377 switch(ie->type){
9378 case eThreadInfo :
9379 objp = Tcl_NewStringObj("threadinfo", -1);
9380 break;
9381 case eText :
9382 objp = NULL;
9383 break;
9384 default :
9385 objp = Tcl_NewStringObj(int2string(ie->type), -1);
9386 break;
9389 if(objp && Tcl_ListObjAppendElement(interp, objElement, objp) != TCL_OK)
9390 return(TCL_ERROR);
9392 if(Tcl_ListObjAppendElement(interp, objField, objElement) != TCL_OK)
9393 return(TCL_ERROR);
9396 if(Tcl_ListObjAppendElement(interp, aObj, objField) != TCL_OK){
9397 return(TCL_ERROR);
9402 return(TCL_OK);
9407 * peAppendIndexColor - append index line's foreground/background color
9409 * Params:
9413 peAppendIndexColor(Tcl_Interp *interp, imapuid_t uid, Tcl_Obj *aObj, int *fetched)
9415 char hexfg[32], hexbg[32];
9416 ICE_S *h;
9418 if((h = build_header_work(wps_global, wps_global->mail_stream,
9419 sp_msgmap(wps_global->mail_stream), peMessageNumber(uid),
9420 gPeITop, gPeICount, fetched))
9421 && h->color_lookup_done
9422 && h->linecolor){
9424 hex_colorstr(hexfg, h->linecolor->fg);
9425 hex_colorstr(hexbg, h->linecolor->bg);
9427 return(peAppListF(interp, aObj, "%s%s", hexfg, hexbg));
9430 return(peAppListF(interp, aObj, "%s", ""));
9435 * peMessageStatusBits - return list flags indicating pine status bits
9437 * Params:
9439 * Returns: list of lists where:
9440 * * the first element is the list of
9441 * field elements data
9442 * * the second element is a two element
9443 * list containing the lines foreground
9444 * and background colors
9447 peMessageStatusBits(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9449 Tcl_SetResult(interp,
9450 peMsgStatBitString(wps_global, wps_global->mail_stream,
9451 sp_msgmap(wps_global->mail_stream), peMessageNumber(uid),
9452 gPeITop, gPeICount, NULL),
9453 TCL_STATIC);
9454 return(TCL_OK);
9458 char *
9459 peMsgStatBitString(struct pine *state,
9460 MAILSTREAM *stream,
9461 MSGNO_S *msgmap,
9462 long msgno,
9463 long top_msgno,
9464 long msgcount,
9465 int *fetched)
9467 static char buf[36];
9468 int i;
9469 long raw;
9470 MESSAGECACHE *mc;
9471 ICE_S *h;
9473 raw = mn_m2raw(msgmap, msgno);
9474 if((h = build_header_work(state, stream, msgmap,
9475 msgno, top_msgno, msgcount, fetched))
9476 && (mc = mail_elt(stream, raw))){
9477 /* return a string representing a bit field where:
9478 index meaning
9479 ----- -------
9480 0 "New"
9481 1 deleted
9482 2 answered
9483 3 flagged
9484 4 to us
9485 5 cc us
9486 6 recent
9487 7 forwarded
9488 8 attachments
9490 i = 0;
9491 buf[i++] = (mc->seen) ? '0' : '1';
9492 buf[i++] = (mc->deleted) ? '1' : '0';
9493 buf[i++] = (mc->answered) ? '1' : '0';
9494 buf[i++] = (mc->flagged) ? '1' : '0';
9495 buf[i++] = (h->to_us) ? '1' : '0';
9496 buf[i++] = (h->cc_us) ? '1' : '0';
9497 buf[i++] = (mc->recent) ? '1' : '0';
9498 buf[i++] = (user_flag_is_set(stream, raw, FORWARDED_FLAG)) ? '1' : '0';
9499 buf[i++] = '0';
9500 buf[i++] = '\0';
9502 return(buf);
9505 return("100000000");
9509 Tcl_Obj *
9510 peMsgStatNameList(Tcl_Interp *interp,
9511 struct pine *state,
9512 MAILSTREAM *stream,
9513 MSGNO_S *msgmap,
9514 long msgno,
9515 long top_msgno,
9516 long msgcount,
9517 int *fetched)
9519 Tcl_Obj *objList;
9520 long raw;
9521 MESSAGECACHE *mc;
9522 ICE_S *h;
9524 objList = Tcl_NewListObj(0, NULL);
9525 raw = mn_m2raw(msgmap, msgno);
9526 if((h = build_header_work(state, stream, msgmap,
9527 msgno, top_msgno, msgcount, fetched))
9528 && (mc = mail_elt(stream, raw))){
9529 if(!mc->seen)
9530 Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("new", -1));
9532 if(mc->deleted)
9533 Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("deleted", -1));
9535 if(mc->answered)
9536 Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("answered", -1));
9538 if(mc->flagged)
9539 Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("flagged", -1));
9541 if(h->to_us)
9542 Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("to_us", -1));
9544 if(h->cc_us)
9545 Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("cc_us", -1));
9547 if(mc->recent)
9548 Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("recent", -1));
9550 if(user_flag_is_set(stream, raw, FORWARDED_FLAG))
9551 Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("forwarded", -1));
9553 if(get_lflag(wps_global->mail_stream, sp_msgmap(wps_global->mail_stream), msgno, MN_SLCT))
9554 Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("selected", -1));
9557 return(objList);
9562 * peReplyHeaders - return subject used in reply to given message
9564 * Params:
9566 * Returns: list of header value pairs where headers are:
9567 * In-Reply-To:, Subject:, Cc:
9571 peReplyHeaders(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9573 long raw;
9574 int flags = RSF_FORCE_REPLY_TO | RSF_FORCE_REPLY_ALL, err = FALSE;
9575 char *errmsg = NULL, *fcc = NULL, *sect = NULL;
9576 ENVELOPE *env, *outgoing;
9577 BODY *body = NULL;
9578 ADDRESS *saved_from, *saved_to, *saved_cc, *saved_resent;
9580 saved_from = (ADDRESS *) NULL;
9581 saved_to = (ADDRESS *) NULL;
9582 saved_cc = (ADDRESS *) NULL;
9583 saved_resent = (ADDRESS *) NULL;
9585 raw = peSequenceNumber(uid);
9587 /* if we're given a valid section number that
9588 * corresponds to a valid msg/rfc822 body part
9589 * then set up headers in attached message.
9591 if(objc == 1 && objv[0]
9592 && (sect = Tcl_GetStringFromObj(objv[0], NULL)) && *sect != '\0'
9593 && (body = mail_body(wps_global->mail_stream, raw, (unsigned char *) sect))
9594 && body->type == TYPEMESSAGE
9595 && !strucmp(body->subtype, "rfc822")){
9596 env = body->nested.msg->env;
9598 else{
9599 sect = NULL;
9600 env = mail_fetchstructure(wps_global->mail_stream, raw, NULL);
9603 if(env){
9604 if(!reply_harvest(wps_global, raw, sect, env,
9605 &saved_from, &saved_to, &saved_cc,
9606 &saved_resent, &flags)){
9608 Tcl_SetResult(interp, "", TCL_STATIC);
9609 return(TCL_ERROR);
9612 outgoing = mail_newenvelope();
9614 reply_seed(wps_global, outgoing, env,
9615 saved_from, saved_to, saved_cc, saved_resent,
9616 &fcc, flags, &errmsg);
9617 if(errmsg){
9618 if(*errmsg){
9619 q_status_message1(SM_ORDER, 3, 3, "%.200s", errmsg);
9622 fs_give((void **)&errmsg);
9625 env = pine_mail_fetchstructure(wps_global->mail_stream, raw, NULL);
9627 outgoing->subject = reply_subject(env->subject, NULL, 0);
9628 outgoing->in_reply_to = reply_in_reply_to(env);
9630 err = !(peAppListF(interp, Tcl_GetObjResult(interp),
9631 "%s%a", "to", outgoing->to) == TCL_OK
9632 && peAppListF(interp, Tcl_GetObjResult(interp),
9633 "%s%a", "cc", outgoing->cc) == TCL_OK
9634 && peAppListF(interp, Tcl_GetObjResult(interp),
9635 "%s%s", "in-reply-to", outgoing->in_reply_to) == TCL_OK
9636 && peAppListF(interp, Tcl_GetObjResult(interp),
9637 "%s%s", "subject",
9638 rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf,
9639 SIZEOF_20KBUF, outgoing->subject)) == TCL_OK
9640 && (fcc ? peFccAppend(interp, Tcl_GetObjResult(interp), fcc, -1) : TRUE));
9643 /* Fill in x-reply-uid data and append it */
9644 if(!err && wps_global->mail_stream->uid_validity){
9645 char *prefix = reply_quote_str(env);
9647 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "(%lu %s)(1 %lu %lu)%s",
9648 strlen(prefix), prefix,
9649 wps_global->mail_stream->uid_validity, uid,
9650 wps_global->mail_stream->mailbox);
9652 fs_give((void **) &prefix);
9654 err = peAppListF(interp, Tcl_GetObjResult(interp), "%s%s",
9655 "x-reply-uid", wtmp_20k_buf) != TCL_OK;
9658 mail_free_envelope(&outgoing);
9660 if(err)
9661 return(TCL_ERROR);
9663 else
9664 Tcl_SetResult(interp, "", TCL_VOLATILE);
9666 return(TCL_OK);
9672 * peReplyText - return subject used in reply to given message
9674 * Params:
9676 * Returns:
9680 peReplyText(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9682 long msgno;
9683 char *prefix, *sect = NULL;
9684 int rv = TCL_OK;
9685 ENVELOPE *env;
9686 BODY *body = NULL, *orig_body;
9687 STORE_S *msgtext;
9688 REDRAFT_POS_S *redraft_pos = NULL;
9689 Tcl_Obj *objBody = NULL, *objAttach = NULL;
9691 msgno = peSequenceNumber(uid);
9693 if((msgtext = (void *) so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){
9694 Tcl_SetResult(interp, "Unable to create storage for reply text", TCL_VOLATILE);
9695 return(TCL_ERROR);
9698 /*--- Grab current envelope ---*/
9699 /* if we're given a valid section number that
9700 * corresponds to a valid msg/rfc822 body part
9701 * then set up to reply the attached message's
9702 * text.
9704 if(objc == 2 && objv[1]
9705 && (sect = Tcl_GetStringFromObj(objv[1], NULL)) && *sect != '\0'
9706 && (body = mail_body(wps_global->mail_stream, msgno, (unsigned char *) sect))
9707 && body->type == TYPEMESSAGE
9708 && !strucmp(body->subtype, "rfc822")){
9709 env = body->nested.msg->env;
9710 orig_body = body->nested.msg->body;
9712 else{
9713 sect = NULL;
9714 env = mail_fetchstructure(wps_global->mail_stream, msgno, &orig_body);
9715 if(!(env && orig_body)){
9716 Tcl_SetResult(interp, "Unable to fetch message parts", TCL_VOLATILE);
9717 return(TCL_ERROR);
9721 if((prefix = Tcl_GetStringFromObj(objv[0], NULL)) != NULL)
9722 prefix = cpystr(prefix);
9723 else
9724 prefix = reply_quote_str(env);
9727 * BUG? Should there be some way to signal to reply_bddy
9728 * that we'd like it to produced format=flowed body text?
9729 * right now it's hardwired to in pine/reply.c
9732 if((body = reply_body(wps_global->mail_stream, env, orig_body,
9733 msgno, sect, msgtext, prefix,
9734 TRUE, NULL, TRUE, &redraft_pos)) != NULL){
9736 objBody = Tcl_NewListObj(0, NULL);
9738 peSoStrToList(interp, objBody, msgtext);
9740 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objBody);
9742 /* sniff for attachments */
9743 objAttach = peMsgAttachCollector(interp, body);
9745 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach);
9748 pine_free_body(&body);
9750 else{
9751 Tcl_SetResult(interp, "Can't create body text", TCL_VOLATILE);
9752 rv = TCL_ERROR;
9755 fs_give((void **) &prefix);
9757 return(rv);
9762 peSoStrToList(Tcl_Interp *interp, Tcl_Obj *obj, STORE_S *so)
9764 char *sp, *ep;
9765 Tcl_Obj *objp;
9767 for(ep = (char *) so_text(so); *ep; ep++){
9768 sp = ep;
9770 while(*ep && *ep != '\n')
9771 ep++;
9773 objp = Tcl_NewStringObj(sp, ep - sp);
9775 if(Tcl_ListObjAppendElement(interp, obj, objp) != TCL_OK)
9776 return(FALSE);
9779 return(TRUE);
9784 * peForwardHeaders - return subject used in forward of given message
9786 * Params:
9788 * Returns:
9792 peForwardHeaders(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9795 int result;
9796 long raw;
9797 char *tmp, *sect = NULL;
9798 ENVELOPE *env;
9799 BODY *body;
9801 raw = peSequenceNumber(uid);
9803 /* if we're given a valid section number that
9804 * corresponds to a valid msg/rfc822 body part
9805 * then set up headers in attached message.
9807 if(objc == 1 && objv[0]
9808 && (sect = Tcl_GetStringFromObj(objv[0], NULL)) && *sect != '\0'
9809 && (body = mail_body(wps_global->mail_stream, raw, (unsigned char *) sect))
9810 && body->type == TYPEMESSAGE
9811 && !strucmp(body->subtype, "rfc822")){
9812 env = body->nested.msg->env;
9814 else{
9815 sect = NULL;
9816 env = mail_fetchstructure(wps_global->mail_stream, raw, NULL);
9819 if(env){
9820 tmp = forward_subject(env, FS_NONE);
9821 result = peAppListF(interp, Tcl_GetObjResult(interp),
9822 "%s%s", "subject", tmp);
9823 fs_give((void **) &tmp);
9825 /* Fill in x-reply-uid data and append it */
9826 if(result == TCL_OK && wps_global->mail_stream->uid_validity){
9827 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "()(1 %lu %lu)%s",
9828 wps_global->mail_stream->uid_validity, uid,
9829 wps_global->mail_stream->mailbox);
9830 result = peAppListF(interp, Tcl_GetObjResult(interp), "%s%s",
9831 "x-reply-uid", wtmp_20k_buf) != TCL_OK;
9834 return(result);
9837 Tcl_SetResult(interp, wps_global->last_error, TCL_VOLATILE);
9838 return(TCL_ERROR);
9844 * peForwardText - return body of message used in
9845 * forward of given message
9847 * Params:
9849 * Returns:
9853 peForwardText(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9855 long msgno;
9856 char *bodtext, *p, *sect = NULL;
9857 int rv = TCL_OK;
9858 ENVELOPE *env;
9859 BODY *body, *orig_body;
9860 STORE_S *msgtext;
9861 Tcl_Obj *objBody = NULL, *objAttach = NULL;
9863 msgno = peSequenceNumber(uid);
9865 if(objc == 1 && objv[0])
9866 sect = Tcl_GetStringFromObj(objv[0], NULL);
9868 if((msgtext = (void *) so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){
9869 Tcl_SetResult(interp, "Unable to create storage for forward text", TCL_VOLATILE);
9870 return(TCL_ERROR);
9874 if(F_ON(F_FORWARD_AS_ATTACHMENT, wps_global)){
9875 PART **pp;
9876 long totalsize = 0L;
9878 /*---- New Body to start with ----*/
9879 body = mail_newbody();
9880 body->type = TYPEMULTIPART;
9882 /*---- The TEXT part/body ----*/
9883 body->nested.part = mail_newbody_part();
9884 body->nested.part->body.type = TYPETEXT;
9885 body->nested.part->body.contents.text.data = (unsigned char *) msgtext;
9887 pp = &(body->nested.part->next);
9889 /*---- The Message body subparts ----*/
9890 env = pine_mail_fetchstructure(wps_global->mail_stream, msgno, NULL);
9892 if(forward_mime_msg(wps_global->mail_stream, msgno,
9893 (sect && *sect != '\0') ? sect : NULL, env, pp, msgtext)){
9894 totalsize = (*pp)->body.size.bytes;
9895 pp = &((*pp)->next);
9898 else{
9899 /*--- Grab current envelope ---*/
9900 /* if we're given a valid section number that
9901 * corresponds to a valid msg/rfc822 body part
9902 * then set up to forward the attached message's
9903 * text.
9906 if(sect && *sect != '\0'
9907 && (body = mail_body(wps_global->mail_stream, msgno, (unsigned char *) sect))
9908 && body->type == TYPEMESSAGE
9909 && !strucmp(body->subtype, "rfc822")){
9910 env = body->nested.msg->env;
9911 orig_body = body->nested.msg->body;
9913 else{
9914 sect = NULL;
9915 env = mail_fetchstructure(wps_global->mail_stream, msgno, &orig_body);
9916 if(!(env && orig_body)){
9917 Tcl_SetResult(interp, "Unable to fetch message parts", TCL_VOLATILE);
9918 return(TCL_ERROR);
9922 body = forward_body(wps_global->mail_stream, env, orig_body,
9923 msgno, sect, msgtext, FWD_NONE);
9926 if(body){
9927 bodtext = (char *) so_text(msgtext);
9929 objBody = Tcl_NewListObj(0, NULL);
9931 for(p = bodtext; *p; p++){
9932 Tcl_Obj *objp;
9934 bodtext = p;
9935 while(*p && *p != '\n')
9936 p++;
9938 objp = Tcl_NewStringObj(bodtext, p - bodtext);
9940 Tcl_ListObjAppendElement(interp, objBody, objp);
9943 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objBody);
9945 /* sniff for attachments */
9946 objAttach = peMsgAttachCollector(interp, body);
9947 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach);
9949 pine_free_body(&body);
9951 else{
9952 Tcl_SetResult(interp, "Can't create body text", TCL_VOLATILE);
9953 rv = TCL_ERROR;
9956 return(rv);
9962 * peDetach -
9964 * Params: argv[0] == attachment part number
9965 * argv[1] == directory to hold tmp file
9967 * Returns: list containing:
9969 * 0) response: OK or ERROR
9970 * if OK
9971 * 1) attachment's mime type
9972 * 2) attachment's mime sub-type
9973 * 3) attachment's size in bytes (decoded)
9974 * 4) attachment's given file name (if any)
9975 * 5) tmp file holding raw attachment data
9978 peDetach(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
9980 char *part, *err, *tfd, *tfn = NULL, *filename;
9981 long raw;
9982 gf_io_t pc;
9983 BODY *body;
9984 STORE_S *store;
9985 Tcl_Obj *rvobj, *tObj, *stObj, *fnObj;
9987 if((part = Tcl_GetStringFromObj(objv[0], NULL))
9988 && (raw = peSequenceNumber(uid))
9989 && (body = mail_body(wps_global->mail_stream, raw, (unsigned char *) part))){
9991 peGetMimeTyping(body, &tObj, &stObj, &fnObj, NULL);
9993 err = NULL;
9994 if(!(tfd = Tcl_GetStringFromObj(objv[1], NULL)) || *tfd == '\0'){
9995 tfn = temp_nam(tfd = NULL, "pd");
9997 else if(is_writable_dir(tfd) == 0){
9998 tfn = temp_nam(tfd, "pd");
10000 else
10001 tfn = tfd;
10003 filename = Tcl_GetStringFromObj(fnObj, NULL);
10004 dprint((5, "PEDetach(name: %s, tmpfile: %s)",
10005 filename ? filename : "<null>", tfn));
10007 if((store = so_get(FileStar, tfn, WRITE_ACCESS|OWNER_ONLY)) != NULL){
10008 gf_set_so_writec(&pc, store);
10009 err = detach(wps_global->mail_stream, raw, part, 0L, NULL, pc, NULL, 0);
10010 gf_clear_so_writec(store);
10011 so_give(&store);
10013 else
10014 err = "Can't allocate internal storage";
10016 else
10017 err = "Can't get message data";
10019 if(err){
10020 if(tfn)
10021 unlink(tfn);
10023 dprint((1, "PEDetach FAIL: %d: %s", errno, err));
10024 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Detach (%d): %s", errno, err);
10025 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
10026 return(TCL_ERROR);
10029 /* package up response */
10030 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10031 Tcl_NewListObj(1, &tObj));
10033 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10034 Tcl_NewListObj(1, &stObj));
10036 rvobj = Tcl_NewLongObj(name_file_size(tfn));
10037 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10038 Tcl_NewListObj(1, &rvobj));
10039 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10040 Tcl_NewListObj(1, &fnObj));
10041 rvobj = Tcl_NewStringObj(tfn, -1);
10042 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10043 Tcl_NewListObj(1, &rvobj));
10045 return(TCL_OK);
10050 * peAttachInfo -
10052 * Params: argv[0] == attachment part number
10054 * Returns: list containing:
10056 * 0) response: OK or ERROR
10057 * if OK
10058 * 1) attachment's mime type
10059 * 2) attachment's mime sub-type
10060 * 3) attachment's size in bytes (decoded)
10061 * 4) attachment's given file name (if any)
10062 * 5) tmp file holding raw attachment data
10065 peAttachInfo(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
10067 char *part;
10068 long raw;
10069 BODY *body;
10070 PARMLIST_S *plist;
10071 Tcl_Obj *tObj, *stObj, *fnObj;
10073 if((part = Tcl_GetStringFromObj(objv[0], NULL))
10074 && (raw = peSequenceNumber(uid))
10075 && (body = mail_body(wps_global->mail_stream, raw, (unsigned char *) part))){
10077 peGetMimeTyping(body, &tObj, &stObj, &fnObj, NULL);
10079 else{
10080 Tcl_SetResult(interp, "Can't get message data", TCL_STATIC);
10081 return(TCL_ERROR);
10084 /* package up response */
10086 /* filename */
10087 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), fnObj);
10089 /* type */
10090 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj);
10092 /* subtype */
10093 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), stObj);
10095 /* encoding */
10096 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10097 Tcl_NewStringObj((body->encoding < ENCMAX)
10098 ? body_encodings[body->encoding]
10099 : "Unknown", -1));
10101 /* parameters */
10102 if((plist = rfc2231_newparmlist(body->parameter)) != NULL){
10103 Tcl_Obj *lObj = Tcl_NewListObj(0, NULL);
10104 Tcl_Obj *pObj[2];
10106 while(rfc2231_list_params(plist)){
10107 pObj[0] = Tcl_NewStringObj(plist->attrib, -1);
10108 pObj[1] = Tcl_NewStringObj(plist->value, -1);
10109 Tcl_ListObjAppendElement(interp, lObj,
10110 Tcl_NewListObj(2, pObj));
10113 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), lObj);
10114 rfc2231_free_parmlist(&plist);
10117 /* size guesstimate */
10118 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10119 Tcl_NewStringObj(comatose((body->encoding == ENCBASE64)
10120 ? ((body->size.bytes * 3)/4)
10121 : body->size.bytes), -1));
10123 return(TCL_OK);
10128 * peSaveDefault - Default saved file name for the given message
10129 * specified collection/folder
10131 * Params:
10133 * Returns: name of saved message folder or empty string
10137 peSaveDefault(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
10139 char *folder;
10140 CONTEXT_S *cntxt, *cp;
10141 int colid;
10142 long rawno;
10143 ENVELOPE *env;
10145 if(uid){
10146 if(!(env = pine_mail_fetchstructure(wps_global->mail_stream,
10147 rawno = peSequenceNumber(uid),
10148 NULL))){
10149 Tcl_SetResult(interp, wps_global->last_error, TCL_VOLATILE);
10150 return(TCL_ERROR);
10153 else
10154 env = NULL;
10156 if(!(folder = save_get_default(wps_global, env, rawno, NULL, &cntxt))){
10157 Tcl_SetResult(interp, "Message expunged!", TCL_VOLATILE);
10158 return(TCL_ERROR); /* message expunged! */
10161 for(colid = 0, cp = wps_global->context_list; cp && cp != cntxt ; colid++, cp = cp->next)
10164 if(!cp)
10165 colid = 0;
10167 (void) Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10168 Tcl_NewIntObj(colid));
10169 (void) Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10170 Tcl_NewStringObj(folder, -1));
10171 return(TCL_OK);
10176 * peSaveWork - Save message with given UID in current folder to
10177 * specified collection/folder
10179 * Params: argv[0] == destination context number
10180 * argv[1] == testination foldername
10185 peSaveWork(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv, long sflags)
10187 int flgs = 0, i, colid;
10188 char *folder, *err = NULL;
10189 CONTEXT_S *cp;
10191 if(Tcl_GetIntFromObj(interp, objv[0], &colid) != TCL_ERROR){
10192 if((folder = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){
10193 mn_set_cur(sp_msgmap(wps_global->mail_stream), peMessageNumber(uid));
10194 for(i = 0, cp = wps_global->context_list; cp ; i++, cp = cp->next)
10195 if(i == colid)
10196 break;
10198 if(cp){
10199 if(!READONLY_FOLDER(wps_global->mail_stream)
10200 && (sflags & PSW_COPY) != PSW_COPY
10201 && ((sflags & PSW_MOVE) == PSW_MOVE || F_OFF(F_SAVE_WONT_DELETE, wps_global)))
10202 flgs |= SV_DELETE;
10204 if(colid == 0 && !strucmp(folder, "inbox"))
10205 flgs |= SV_INBOXWOCNTXT;
10207 if(sflags & (PSW_COPY | PSW_MOVE))
10208 flgs |= SV_FIX_DELS;
10210 i = save(wps_global, wps_global->mail_stream,
10211 cp, folder, sp_msgmap(wps_global->mail_stream), flgs);
10213 if(i == mn_total_cur(sp_msgmap(wps_global->mail_stream))){
10214 if(mn_total_cur(sp_msgmap(wps_global->mail_stream)) <= 1L){
10215 if(wps_global->context_list->next
10216 && context_isambig(folder)){
10217 char *tag = (cp->nickname && strlen(cp->nickname)) ? cp->nickname : (cp->label && strlen(cp->label)) ? cp->label : "Folders";
10218 snprintf(wtmp_20k_buf, SIZEOF_20KBUF,
10219 "Message %s %s to \"%.15s%s\" in <%.15s%s>",
10220 long2string(mn_get_cur(sp_msgmap(wps_global->mail_stream))),
10221 (sflags & PSW_MOVE) ? "moved" : "copied",
10222 folder,
10223 (strlen(folder) > 15) ? "..." : "",
10224 tag,
10225 (strlen(tag) > 15) ? "..." : "");
10227 else
10228 snprintf(wtmp_20k_buf, SIZEOF_20KBUF,
10229 "Message %s %s to folder \"%.27s%s\"",
10230 long2string(mn_get_cur(sp_msgmap(wps_global->mail_stream))),
10231 (sflags & PSW_MOVE) ? "moved" : "copied",
10232 folder,
10233 (strlen(folder) > 27) ? "..." : "");
10235 else{
10236 /* with mn_set_cur above, this *should not* happen */
10237 Tcl_SetResult(interp, "TOO MANY MESSAGES COPIED", TCL_VOLATILE);
10238 return(TCL_ERROR);
10241 if(sflags == PSW_NONE && (flgs & SV_DELETE)){
10242 strncat(wtmp_20k_buf, " and deleted", SIZEOF_20KBUF-strlen(wtmp_20k_buf)-1);
10243 wtmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
10246 q_status_message(SM_ORDER, 0, 3, wtmp_20k_buf);
10247 return(TCL_OK);
10250 err = wps_global->last_error;
10252 else
10253 err = "open: Unrecognized collection ID";
10255 else
10256 err = "open: Can't read folder";
10258 else
10259 err = "open: Can't get collection ID";
10261 Tcl_SetResult(interp, err, TCL_VOLATILE);
10262 return(TCL_ERROR);
10266 * peSave - Save message with given UID in current folder to
10267 * specified collection/folder
10269 * Params: argv[0] == destination context number
10270 * argv[1] == testination foldername
10272 * NOTE: just a wrapper around peSaveWork
10275 peSave(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
10277 return(peSaveWork(interp, uid, objc, objv, PSW_NONE));
10282 * peCopy - Copy message with given UID in current folder to
10283 * specified collection/folder
10285 * Params: argv[0] == destination context number
10286 * argv[1] == testination foldername
10288 * NOTE: just a wrapper around peSaveWork that makes sure
10289 * delete-on-save is NOT set
10292 peCopy(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
10294 return(peSaveWork(interp, uid, objc, objv, PSW_COPY));
10299 * peMove - Move message with given UID in current folder to
10300 * specified collection/folder
10302 * Params: argv[0] == destination context number
10303 * argv[1] == testination foldername
10305 * NOTE: just a wrapper around peSaveWork that makes sure
10306 * delete-on-save IS set so it can be expunged
10309 peMove(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
10311 return(peSaveWork(interp, uid, objc, objv, PSW_MOVE));
10316 * peGotoDefault - Default Goto command file name for the given message
10317 * specified collection/folder
10319 * Params:
10321 * Returns: name of Goto command default folder or empty string
10325 peGotoDefault(Tcl_Interp *interp, imapuid_t uid, Tcl_Obj **objv)
10327 char *folder = NULL;
10328 CONTEXT_S *cntxt, *cp;
10329 int colid, inbox;
10331 cntxt = broach_get_folder(wps_global->context_current, &inbox, &folder);
10333 for(colid = 0, cp = wps_global->context_list; cp != cntxt ; colid++, cp = cp->next)
10336 if(!cp)
10337 colid = 0;
10339 (void) Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10340 Tcl_NewIntObj(colid));
10341 (void) Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
10342 Tcl_NewStringObj(folder ? folder : "", -1));
10343 return(TCL_OK);
10348 * peReplyQuote -
10350 * Params: argv[0] == attachment part number
10352 * Returns: list containing:
10356 peReplyQuote(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
10358 char *quote;
10359 ENVELOPE *env;
10361 if(uid){
10362 if((env = pine_mail_fetchstructure(wps_global->mail_stream, peSequenceNumber(uid), NULL)) != NULL){
10363 quote = reply_quote_str(env);
10364 Tcl_SetResult(interp, quote, TCL_VOLATILE);
10365 fs_give((void **) &quote);
10367 else{
10368 Tcl_SetResult(interp, wps_global->last_error, TCL_VOLATILE);
10369 return(TCL_ERROR);
10372 else
10373 Tcl_SetResult(interp, "> ", TCL_VOLATILE);
10375 return(TCL_OK);
10379 void
10380 peGetMimeTyping(BODY *body, Tcl_Obj **tObjp, Tcl_Obj **stObjp, Tcl_Obj **fnObjp, Tcl_Obj **extObjp)
10382 char *ptype = NULL, *psubtype = NULL, *pfile = NULL;
10384 /*------- Figure out suggested file name ----*/
10385 if(body){
10386 if((pfile = get_filename_parameter(NULL, 0, body, NULL)) != NULL){
10388 * if part is generic, see if we can get anything
10389 * more from the suggested filename's extension...
10391 if(body->type == TYPEAPPLICATION
10392 && (!body->subtype
10393 || !strucmp(body->subtype, "octet-stream"))){
10394 BODY *fakebody = mail_newbody();
10396 if(set_mime_type_by_extension(fakebody, pfile)){
10397 ptype = body_type_names(fakebody->type);
10398 psubtype = cpystr(fakebody->subtype);
10401 mail_free_body(&fakebody);
10405 if(!ptype) {
10406 ptype = body_type_names(body->type);
10407 psubtype = cpystr(body->subtype
10408 ? body->subtype
10409 : (body->type == TYPETEXT)
10410 ? "plain"
10411 : (body->type == TYPEAPPLICATION)
10412 ? "octet-stream"
10413 : "");
10416 else{
10417 ptype = body_type_names(TYPETEXT);
10418 psubtype = cpystr("plain");
10421 if(extObjp){
10422 *extObjp = Tcl_NewStringObj("", 0);
10424 if(ptype && psubtype && pfile){
10425 size_t l;
10426 char *mtype;
10427 char extbuf[32]; /* mailcap.c limits to three */
10429 l = strlen(ptype) + strlen(psubtype) + 1;
10430 mtype = (char *) fs_get((l+1) * sizeof(char));
10432 snprintf(mtype, l+1, "%s/%s", ptype, psubtype);
10434 if(!set_mime_extension_by_type(extbuf, mtype)){
10435 char *dotp, *p;
10437 for(dotp = NULL, p = pfile; *p; p++)
10438 if(*p == '.')
10439 dotp = p + 1;
10441 if(dotp)
10442 Tcl_SetStringObj(*extObjp, dotp, -1);
10444 else
10445 Tcl_SetStringObj(*extObjp, extbuf, -1);
10447 fs_give((void **) &mtype);
10451 if(tObjp)
10452 *tObjp = Tcl_NewStringObj(ptype, -1);
10454 if(psubtype){
10455 if(stObjp)
10456 *stObjp = Tcl_NewStringObj(psubtype, -1);
10458 fs_give((void **) &psubtype);
10460 else if(stObjp)
10461 *stObjp = Tcl_NewStringObj("", 0);
10463 if(pfile){
10464 if(fnObjp)
10465 *fnObjp = Tcl_NewStringObj(pfile, -1);
10467 fs_give((void **) &pfile);
10469 else if(fnObjp)
10470 *fnObjp = Tcl_NewStringObj("", 0);
10475 * peAppListF - generate a list of elements based on fmt string,
10476 * then append it to the given list object
10480 peAppListF(Tcl_Interp *interp, Tcl_Obj *lobjp, char *fmt, ...)
10482 va_list args;
10483 char *p, *sval, nbuf[128];
10484 int ival, err = 0;
10485 unsigned int uval;
10486 long lval;
10487 unsigned long luval;
10488 PATTERN_S *pval;
10489 ADDRESS *aval;
10490 INTVL_S *vval;
10491 Tcl_Obj *lObj = NULL, *sObj;
10493 if((lObj = Tcl_NewListObj(0, NULL)) != NULL){
10494 va_start(args, fmt);
10495 for(p = fmt; *p && !err; p++){
10496 sObj = NULL;
10498 if(*p == '%')
10499 switch(*++p){
10500 case 'i' : /* int value */
10501 ival = va_arg(args, int);
10502 if((sObj = Tcl_NewIntObj(ival)) == NULL)
10503 err++;
10505 break;
10507 case 'u' : /* unsigned int value */
10508 uval = va_arg(args, unsigned int);
10509 snprintf(nbuf, sizeof(nbuf), "%u", uval);
10510 if((sObj = Tcl_NewStringObj(nbuf, -1)) == NULL)
10511 err++;
10513 break;
10515 case 'l' : /* long value */
10516 if(*(p+1) == 'u'){
10517 p++;
10518 luval = va_arg(args, unsigned long);
10519 snprintf(nbuf, sizeof(nbuf), "%lu", luval);
10520 if((sObj = Tcl_NewStringObj(nbuf, -1)) == NULL)
10521 err++;
10523 else{
10524 lval = va_arg(args, long);
10525 if((sObj = Tcl_NewLongObj(lval)) == NULL)
10526 err++;
10529 break;
10531 case 's' : /* string value */
10532 sval = va_arg(args, char *);
10533 sObj = Tcl_NewStringObj(sval ? sval : "", -1);
10534 if(sObj == NULL)
10535 err++;
10537 break;
10539 case 'a': /* ADDRESS list */
10540 aval = va_arg(args, ADDRESS *);
10541 if(aval){
10542 char *tmp, *p;
10543 RFC822BUFFER rbuf;
10544 size_t len;
10546 len = est_size(aval);
10547 tmp = (char *) fs_get(len * sizeof(char));
10548 tmp[0] = '\0';
10549 rbuf.f = dummy_soutr;
10550 rbuf.s = NULL;
10551 rbuf.beg = tmp;
10552 rbuf.cur = tmp;
10553 rbuf.end = tmp+len-1;
10554 rfc822_output_address_list(&rbuf, aval, 0L, NULL);
10555 *rbuf.cur = '\0';
10556 p = (char *) rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf, SIZEOF_20KBUF, tmp);
10557 sObj = Tcl_NewStringObj(p, strlen(p));
10558 fs_give((void **) &tmp);
10560 else
10561 sObj = Tcl_NewStringObj("", -1);
10563 break;
10565 case 'p': /* PATTERN_S * */
10566 pval = va_arg(args, PATTERN_S *);
10567 sval = pattern_to_string(pval);
10568 sObj = Tcl_NewStringObj(sval ? sval : "", -1);
10569 break;
10571 case 'v': /* INTVL_S * */
10572 vval = va_arg(args, INTVL_S *);
10573 if(vval){
10574 for(; vval != NULL; vval = vval->next){
10575 peAppListF(interp, sObj, "%l%l", vval->imin, vval->imax);
10578 else
10579 sObj = Tcl_NewListObj(0, NULL);
10581 break;
10583 case 'o': /* Tcl_Obj * */
10584 sObj = va_arg(args, Tcl_Obj *);
10585 break;
10588 if(sObj)
10589 Tcl_ListObjAppendElement(interp, lObj, sObj);
10592 va_end(args);
10595 return(lObj ? Tcl_ListObjAppendElement(interp, lobjp, lObj) : TCL_ERROR);
10599 * pePatAppendID - append list of pattern identity variables to given object
10601 void
10602 pePatAppendID(Tcl_Interp *interp, Tcl_Obj *patObj, PAT_S *pat)
10604 Tcl_Obj *resObj;
10606 resObj = Tcl_NewListObj(0, NULL);
10607 peAppListF(interp, resObj, "%s%s", "nickname", pat->patgrp->nick);
10608 peAppListF(interp, resObj, "%s%s", "comment", pat->patgrp->comment);
10609 Tcl_ListObjAppendElement(interp, patObj, resObj);
10614 * pePatAppendPattern - append list of pattern variables to given object
10616 void
10617 pePatAppendPattern(Tcl_Interp *interp, Tcl_Obj *patObj, PAT_S *pat)
10619 ARBHDR_S *ah;
10620 Tcl_Obj *resObj;
10622 resObj = Tcl_NewListObj(0, NULL);
10623 peAppListF(interp, resObj, "%s%p", "to", pat->patgrp->to);
10624 peAppListF(interp, resObj, "%s%p", "from", pat->patgrp->from);
10625 peAppListF(interp, resObj, "%s%p", "sender", pat->patgrp->sender);
10626 peAppListF(interp, resObj, "%s%p", "cc", pat->patgrp->cc);
10627 peAppListF(interp, resObj, "%s%p", "recip", pat->patgrp->recip);
10628 peAppListF(interp, resObj, "%s%p", "partic", pat->patgrp->partic);
10629 peAppListF(interp, resObj, "%s%p", "news", pat->patgrp->news);
10630 peAppListF(interp, resObj, "%s%p", "subj", pat->patgrp->subj);
10631 peAppListF(interp, resObj, "%s%p", "alltext", pat->patgrp->alltext);
10632 peAppListF(interp, resObj, "%s%p", "bodytext", pat->patgrp->bodytext);
10633 peAppListF(interp, resObj, "%s%p", "keyword", pat->patgrp->keyword);
10634 peAppListF(interp, resObj, "%s%p", "charset", pat->patgrp->charsets);
10636 peAppListF(interp, resObj, "%s%v", "score", pat->patgrp->score);
10637 peAppListF(interp, resObj, "%s%v", "age", pat->patgrp->age);
10638 peAppListF(interp, resObj, "%s%v", "size", pat->patgrp->size);
10640 if((ah = pat->patgrp->arbhdr) != NULL){
10641 Tcl_Obj *hlObj, *hObj;
10643 hlObj = Tcl_NewListObj(0, NULL);
10644 Tcl_ListObjAppendElement(interp, hlObj, Tcl_NewStringObj("headers", -1));
10646 for(; ah; ah = ah->next){
10647 hObj = Tcl_NewListObj(0, NULL);
10648 peAppListF(interp, hObj, "%s%p", ah->field ? ah->field : "", ah->p);
10649 Tcl_ListObjAppendElement(interp, hlObj, hObj);
10652 Tcl_ListObjAppendElement(interp, resObj, hlObj);
10655 switch(pat->patgrp->fldr_type){
10656 case FLDR_ANY:
10657 peAppListF(interp, resObj, "%s%s", "ftype", "any");
10658 break;
10659 case FLDR_NEWS:
10660 peAppListF(interp, resObj, "%s%s", "ftype", "news");
10661 break;
10662 case FLDR_EMAIL:
10663 peAppListF(interp, resObj, "%s%s", "ftype", "email");
10664 break;
10665 case FLDR_SPECIFIC:
10666 peAppListF(interp, resObj, "%s%s", "ftype", "specific");
10667 break;
10670 peAppListF(interp, resObj, "%s%p", "folder", pat->patgrp->folder);
10671 peAppListF(interp, resObj, "%s%s", "stat_new", pePatStatStr(pat->patgrp->stat_new));
10672 peAppListF(interp, resObj, "%s%s", "stat_rec", pePatStatStr(pat->patgrp->stat_rec));
10673 peAppListF(interp, resObj, "%s%s", "stat_del", pePatStatStr(pat->patgrp->stat_del));
10674 peAppListF(interp, resObj, "%s%s", "stat_imp", pePatStatStr(pat->patgrp->stat_imp));
10675 peAppListF(interp, resObj, "%s%s", "stat_ans", pePatStatStr(pat->patgrp->stat_ans));
10676 peAppListF(interp, resObj, "%s%s", "stat_8bitsubj", pePatStatStr(pat->patgrp->stat_8bitsubj));
10677 peAppListF(interp, resObj, "%s%s", "stat_bom", pePatStatStr(pat->patgrp->stat_bom));
10678 peAppListF(interp, resObj, "%s%s", "stat_boy", pePatStatStr(pat->patgrp->stat_boy));
10680 Tcl_ListObjAppendElement(interp, patObj, resObj);
10684 char *
10685 pePatStatStr(int value)
10687 switch(value){
10688 case PAT_STAT_EITHER:
10689 return("either");
10690 break;
10692 case PAT_STAT_YES:
10693 return("yes");
10694 break;
10696 default :
10697 return("no");
10698 break;
10704 * peCreateUserContext - create new wps_global and set it up
10706 char *
10707 peCreateUserContext(Tcl_Interp *interp, char *user, char *config, char *defconf)
10709 if(wps_global)
10710 peDestroyUserContext(&wps_global);
10712 set_collation(1, 1);
10714 wps_global = new_pine_struct();
10716 /*----------------------------------------------------------------------
10717 Place any necessary constraints on pith processing
10718 ----------------------------------------------------------------------*/
10720 /* got thru close procedure without expunging */
10721 wps_global->noexpunge_on_close = 1;
10723 /* do NOT let user set path to local executable */
10724 wps_global->vars[V_SENDMAIL_PATH].is_user = 0;
10727 /*----------------------------------------------------------------------
10728 Proceed with reading acquiring user settings
10729 ----------------------------------------------------------------------*/
10730 if(wps_global->pinerc)
10731 fs_give((void **) &wps_global->pinerc);
10733 if(wps_global->prc)
10734 free_pinerc_s(&wps_global->prc);
10736 if(!IS_REMOTE(config)){
10737 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "Non-Remote config: %s", config);
10738 return(wtmp_20k_buf);
10741 wps_global->prc = new_pinerc_s(config);
10743 if(defconf){
10744 if(wps_global->pconf)
10745 free_pinerc_s(&wps_global->pconf);
10747 wps_global->pconf = new_pinerc_s(defconf);
10751 * Fake up some user information
10753 wps_global->ui.login = cpystr(user);
10755 #ifdef DEBUG
10757 * Prep for IMAP debugging
10759 setup_imap_debug();
10760 #endif
10762 /* CHECK FOR AND PASS BACK ANY INIT ERRORS */
10763 return(peLoadConfig(wps_global));
10768 void
10769 peDestroyUserContext(struct pine **pps)
10772 completely_done_with_adrbks();
10774 free_pinerc_strings(pps);
10775 #if 0
10776 imap_flush_passwd_cache(TRUE);
10777 #endif
10778 clear_index_cache(sp_inbox_stream(), 0);
10779 free_newsgrp_cache();
10780 mailcap_free();
10781 close_patterns(0L);
10782 free_extra_hdrs();
10783 free_contexts(&wps_global->context_list);
10785 pico_endcolor();
10787 free_strlist(&peCertHosts);
10789 free_pine_struct(pps);
10793 char *
10794 peLoadConfig(struct pine *pine_state)
10796 int rv;
10797 char *s, *db = NULL;
10798 extern void init_signals(void); /* in signal.c */
10800 if(!pine_state)
10801 return("No global state present");
10803 #if 0
10804 /*turned off because we don't care about local user*/
10805 /* need home directory early */
10806 get_user_info(&pine_state->ui);
10808 pine_state->home_dir = cpystr((getenv("HOME") != NULL)
10809 ? getenv("HOME")
10810 : pine_state->ui.homedir);
10811 #endif
10813 init_pinerc(pine_state, &db);
10815 fs_give((void **) &db);
10818 * Initial allocation of array of stream pool pointers.
10819 * We do this before init_vars so that we can re-use streams used for
10820 * remote config files. These sizes may get changed later.
10822 wps_global->s_pool.max_remstream = 2;
10824 wps_global->c_client_error[0] = '\0';
10826 pePrepareForAuthException();
10828 peInitVars(pine_state);
10830 if((s = peAuthException()) != NULL)
10831 return(s);
10832 else if(wps_global->c_client_error[0])
10833 return(wps_global->c_client_error);
10835 mail_parameters(NULL, SET_SENDCOMMAND, (void *) pine_imap_cmd_happened);
10836 mail_parameters(NULL, SET_FREESTREAMSPAREP, (void *) sp_free_callback);
10837 mail_parameters(NULL, SET_FREEELTSPAREP, (void *) free_pine_elt);
10840 * Install callback to handle certificate validation failures,
10841 * allowing the user to continue if they wish.
10843 mail_parameters(NULL, SET_SSLCERTIFICATEQUERY, (void *) alpine_sslcertquery);
10844 mail_parameters(NULL, SET_SSLFAILURE, (void *) alpine_sslfailure);
10847 * Set up a c-client read timeout and timeout handler. In general,
10848 * it shouldn't happen, but a server crash or dead link can cause
10849 * pine to appear wedged if we don't set this up...
10851 mail_parameters(NULL, SET_OPENTIMEOUT,
10852 (void *)((pine_state->VAR_TCPOPENTIMEO
10853 && (rv = atoi(pine_state->VAR_TCPOPENTIMEO)) > 4)
10854 ? (long) rv : 30L));
10855 mail_parameters(NULL, SET_TIMEOUT, (void *) alpine_tcptimeout);
10857 if(pine_state->VAR_RSHOPENTIMEO
10858 && ((rv = atoi(pine_state->VAR_RSHOPENTIMEO)) == 0 || rv > 4))
10859 mail_parameters(NULL, SET_RSHTIMEOUT, (void *) (long) rv);
10861 if(pine_state->VAR_SSHOPENTIMEO
10862 && ((rv = atoi(pine_state->VAR_SSHOPENTIMEO)) == 0 || rv > 4))
10863 mail_parameters(NULL, SET_SSHTIMEOUT, (void *) (long) rv);
10866 * Tell c-client not to be so aggressive about uid mappings
10868 mail_parameters(NULL, SET_UIDLOOKAHEAD, (void *) 20);
10871 * Setup referral handling
10873 mail_parameters(NULL, SET_IMAPREFERRAL, (void *) imap_referral);
10874 mail_parameters(NULL, SET_MAILPROXYCOPY, (void *) imap_proxycopy);
10877 * Install extra headers to fetch along with all the other stuff
10878 * mail_fetch_structure and mail_fetch_overview requests.
10880 calc_extra_hdrs();
10882 if(get_extra_hdrs())
10883 (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS, (void *) get_extra_hdrs());
10885 (void) init_username(pine_state);
10887 (void) init_hostname(wps_global);
10889 #ifdef ENABLE_LDAP
10890 (void) init_ldap_pname(wps_global);
10891 #endif /* ENABLE_LDAP */
10893 if(wps_global->prc && wps_global->prc->type == Loc &&
10894 can_access(wps_global->pinerc, ACCESS_EXISTS) == 0 &&
10895 can_access(wps_global->pinerc, EDIT_ACCESS) != 0)
10896 wps_global->readonly_pinerc = 1;
10899 * c-client needs USR2 and we might as well
10900 * do something sensible with HUP and TERM
10902 init_signals();
10904 strncpy(pine_state->inbox_name, INBOX_NAME, sizeof(pine_state->inbox_name));
10905 pine_state->inbox_name[sizeof(pine_state->inbox_name)-1] = '\0';
10907 init_folders(pine_state); /* digest folder spec's */
10910 * Various options we want to make sure are set OUR way
10912 F_TURN_ON(F_QUELL_IMAP_ENV_CB, pine_state);
10913 F_TURN_ON(F_SLCTBL_ITEM_NOBOLD, pine_state);
10914 F_TURN_OFF(F_USE_SYSTEM_TRANS, pine_state);
10917 * Fake screen dimensions for index formatting and
10918 * message display wrap...
10920 wps_global->ttyo = (struct ttyo *) fs_get(sizeof(struct ttyo));
10921 wps_global->ttyo->screen_rows = FAKE_SCREEN_LENGTH;
10922 wps_global->ttyo->screen_cols = FAKE_SCREEN_WIDTH;
10923 if(wps_global->VAR_WP_COLUMNS){
10924 int w = atoi(wps_global->VAR_WP_COLUMNS);
10925 if(w >= 20 && w <= 128)
10926 wps_global->ttyo->screen_cols = w;
10929 wps_global->ttyo->header_rows = 0;
10930 wps_global->ttyo->footer_rows = 0;
10933 /* init colors */
10934 if(wps_global->VAR_NORM_FORE_COLOR)
10935 pico_nfcolor(wps_global->VAR_NORM_FORE_COLOR);
10937 if(wps_global->VAR_NORM_BACK_COLOR)
10938 pico_nbcolor(wps_global->VAR_NORM_BACK_COLOR);
10940 if(wps_global->VAR_REV_FORE_COLOR)
10941 pico_rfcolor(wps_global->VAR_REV_FORE_COLOR);
10943 if(wps_global->VAR_REV_BACK_COLOR)
10944 pico_rbcolor(wps_global->VAR_REV_BACK_COLOR);
10946 pico_set_normal_color();
10948 return(NULL);
10953 peCreateStream(Tcl_Interp *interp, CONTEXT_S *context, char *mailbox, int do_inbox)
10955 unsigned long flgs = 0L;
10956 char *s;
10958 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
10960 pePrepareForAuthException();
10962 if(do_inbox)
10963 flgs |= DB_INBOXWOCNTXT;
10965 if(do_broach_folder(mailbox, context, NULL, flgs) && wps_global->mail_stream){
10966 dprint((SYSDBG_INFO, "Mailbox open: %s",
10967 wps_global->mail_stream->mailbox ? wps_global->mail_stream->mailbox : "<UNKNOWN>"));
10968 return(TCL_OK);
10971 Tcl_SetResult(interp,
10972 (s = peAuthException())
10974 : (*wps_global->last_error)
10975 ? wps_global->last_error
10976 : "Login Error",
10977 TCL_VOLATILE);
10978 return(TCL_ERROR);
10982 void
10983 peDestroyStream(struct pine *ps)
10985 int cur_is_inbox;
10987 if(ps){
10988 cur_is_inbox = (sp_inbox_stream() == wps_global->mail_stream);
10990 /* clean up open streams */
10991 if(ps->mail_stream){
10992 expunge_and_close(ps->mail_stream, NULL, EC_NONE);
10993 wps_global->mail_stream = NULL;
10994 wps_global->cur_folder[0] = '\0';
10997 if(ps->msgmap)
10998 mn_give(&ps->msgmap);
11000 if(sp_inbox_stream() && !cur_is_inbox){
11001 ps->mail_stream = sp_inbox_stream();
11002 ps->msgmap = sp_msgmap(ps->mail_stream);
11003 sp_set_expunge_count(wps_global->mail_stream, 0L);
11004 expunge_and_close(sp_inbox_stream(), NULL, EC_NONE);
11005 mn_give(&ps->msgmap);
11012 * pePrepareForAuthException - set globals to get feedback from bowels of c-client
11014 void
11015 pePrepareForAuthException(void)
11017 peNoPassword = peCredentialError = peCertFailure = peCertQuery = 0;
11021 * pePrepareForAuthException - check globals getting feedback from bowels of c-client
11023 char *
11024 peAuthException()
11026 static char buf[CRED_REQ_SIZE];
11028 if(peCertQuery){
11029 snprintf(buf, CRED_REQ_SIZE, "%s %s", CERT_QUERY_STRING, peCredentialRequestor);
11030 return(buf);
11033 if(peCertFailure){
11034 snprintf(buf, CRED_REQ_SIZE, "%s %s", CERT_FAILURE_STRING, peCredentialRequestor);
11035 return(buf);
11038 if(peNoPassword){
11039 snprintf(buf, CRED_REQ_SIZE, "%s %s", AUTH_EMPTY_STRING, peCredentialRequestor);
11040 return(buf);
11043 if(peCredentialError){
11044 snprintf(buf, CRED_REQ_SIZE, "%s %s", AUTH_FAILURE_STRING, peCredentialRequestor);
11045 return(buf);
11048 return(NULL);
11052 void
11053 peInitVars(struct pine *ps)
11055 init_vars(ps, NULL);
11058 * fix display/keyboard-character-set to utf-8
11063 if(ps->display_charmap)
11064 fs_give((void **) &ps->display_charmap);
11066 ps->display_charmap = cpystr(WP_INTERNAL_CHARSET);
11068 if(ps->keyboard_charmap)
11069 fs_give((void **) &ps->keyboard_charmap);
11071 ps->keyboard_charmap = cpystr(WP_INTERNAL_CHARSET);
11073 (void) setup_for_input_output(FALSE, &ps->display_charmap, &ps->keyboard_charmap, &ps->input_cs, NULL);;
11079 peMessageBounce(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
11081 char *errstr = NULL, *to, *subj = NULL, errbuf[WP_MAX_POST_ERROR + 1];
11082 long rawno;
11083 ENVELOPE *env, *outgoing = NULL;
11084 METAENV *metaenv;
11085 PINEFIELD *custom;
11086 BODY *body = NULL;
11088 if(uid){
11089 rawno = peSequenceNumber(uid);
11091 if(objc > 0 && objv[0] && (to = Tcl_GetStringFromObj(objv[0], NULL))){
11092 if(objc == 2 && objv[1]){
11093 subj = Tcl_GetStringFromObj(objv[1], NULL);
11095 else if((env = mail_fetchstructure(wps_global->mail_stream, rawno, NULL)) != NULL){
11096 subj = env->subject;
11098 else{
11099 Tcl_SetResult(interp, wps_global->last_error, TCL_VOLATILE);
11100 return(TCL_ERROR);
11103 if((errstr = bounce_msg_body(wps_global->mail_stream, rawno, NULL,
11104 &to, subj, &outgoing, &body, NULL))){
11105 Tcl_SetResult(interp, errstr, TCL_VOLATILE);
11106 return(TCL_ERROR);
11109 metaenv = pine_new_env(outgoing, NULL, NULL, custom = peCustomHdrs());
11111 if(!outgoing->from)
11112 outgoing->from = generate_from();
11114 rfc822_date(wtmp_20k_buf);
11115 outgoing->date = (unsigned char *) cpystr(wtmp_20k_buf);
11117 outgoing->return_path = rfc822_cpy_adr(outgoing->from);
11118 if(!outgoing->message_id)
11119 outgoing->message_id = generate_message_id(NULL);
11121 /* NO FCC */
11123 if(peDoPost(metaenv, body, NULL, NULL, errbuf) != TCL_OK)
11124 errstr = errbuf;
11126 pine_free_body(&body);
11128 pine_free_env(&metaenv);
11130 if(custom)
11131 free_customs(custom);
11133 mail_free_envelope(&outgoing);
11134 pine_free_body(&body);
11139 Tcl_SetResult(interp, (errstr) ? errstr : "OK", TCL_VOLATILE);
11140 return(errstr ? TCL_ERROR : TCL_OK);
11145 peMessageSpamNotice(interp, uid, objc, objv)
11146 Tcl_Interp *interp;
11147 imapuid_t uid;
11148 int objc;
11149 Tcl_Obj **objv;
11151 char *to, *subj = NULL, errbuf[WP_MAX_POST_ERROR + 1], *rs = NULL;
11152 long rawno;
11154 if(uid){
11155 rawno = peSequenceNumber(uid);
11157 if(objv[0] && (to = Tcl_GetStringFromObj(objv[0], NULL)) && strlen(to)){
11159 if(objv[1])
11160 subj = Tcl_GetStringFromObj(objv[1], NULL);
11162 rs = peSendSpamReport(rawno, to, subj, errbuf);
11166 Tcl_SetResult(interp, (rs) ? rs : "OK", TCL_VOLATILE);
11167 return(rs ? TCL_ERROR : TCL_OK);
11171 char *
11172 peSendSpamReport(long rawno, char *to, char *subj, char *errbuf)
11174 char *errstr = NULL, *tmp_a_string;
11175 ENVELOPE *env, *outgoing;
11176 METAENV *metaenv;
11177 PINEFIELD *custom;
11178 BODY *body;
11179 static char *fakedomain = "@";
11180 void *msgtext;
11183 if((env = mail_fetchstructure(wps_global->mail_stream, rawno, NULL)) == NULL){
11184 return(wps_global->last_error);
11187 /* empty subject gets "spam" subject */
11188 if(!(subj && *subj))
11189 subj = env->subject;
11191 /*---- New Body to start with ----*/
11192 body = mail_newbody();
11193 body->type = TYPEMULTIPART;
11195 /*---- The TEXT part/body ----*/
11196 body->nested.part = mail_newbody_part();
11197 body->nested.part->body.type = TYPETEXT;
11199 if((msgtext = (void *)so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){
11200 pine_free_body(&body);
11201 return("peSendSpamReport: Can't allocate text");
11203 else{
11204 sprintf(wtmp_20k_buf,
11205 "The attached message is being reported to <%s> as Spam\n",
11206 to);
11207 so_puts((STORE_S *) msgtext, wtmp_20k_buf);
11208 body->nested.part->body.contents.text.data = msgtext;
11211 /*---- Attach the raw message ----*/
11212 if(forward_mime_msg(wps_global->mail_stream, rawno, NULL, env,
11213 &(body->nested.part->next), msgtext)){
11214 outgoing = mail_newenvelope();
11215 metaenv = pine_new_env(outgoing, NULL, NULL, custom = peCustomHdrs());
11217 else{
11218 pine_free_body(&body);
11219 return("peSendSpamReport: Can't generate forwarded message");
11222 /* rfc822_parse_adrlist feels free to destroy input so copy */
11223 tmp_a_string = cpystr(to);
11224 rfc822_parse_adrlist(&outgoing->to, tmp_a_string,
11225 (F_ON(F_COMPOSE_REJECTS_UNQUAL, wps_global))
11226 ? fakedomain : wps_global->maildomain);
11227 fs_give((void **) &tmp_a_string);
11229 outgoing->from = generate_from();
11230 outgoing->subject = cpystr(subj);
11231 outgoing->return_path = rfc822_cpy_adr(outgoing->from);
11232 outgoing->message_id = generate_message_id(NULL);
11234 rfc822_date(wtmp_20k_buf);
11235 outgoing->date = (unsigned char *) cpystr(wtmp_20k_buf);
11237 /* NO FCC for Spam Reporting */
11239 if(peDoPost(metaenv, body, NULL, NULL, errbuf) != TCL_OK)
11240 errstr = errbuf;
11242 pine_free_body(&body);
11244 pine_free_env(&metaenv);
11246 if(custom)
11247 free_customs(custom);
11249 mail_free_envelope(&outgoing);
11250 pine_free_body(&body);
11252 return(errstr);
11256 /* * * * * * * * * * * * * Start of Composer Routines * * * * * * * * * * * */
11260 * PEComposeCmd - export various bits of alpine state
11263 PEComposeCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
11265 char *err = "PECompose: Unknown request";
11267 dprint((2, "PEComposeCmd"));
11269 if(objc == 1){
11270 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
11272 else if(!wps_global){
11273 Tcl_SetResult(interp, "peCompose: no config present", TCL_STATIC);
11274 return(TCL_ERROR);
11276 else{
11277 char *s1 = Tcl_GetStringFromObj(objv[1], NULL);
11279 if(s1){
11280 if(!strcmp(s1, "post")){
11281 long flags = PMC_NONE;
11282 if(F_ON(F_COMPOSE_REJECTS_UNQUAL, wps_global))
11283 flags |= PMC_FORCE_QUAL;
11285 return(peMsgCollector(interp, objc - 2, (Tcl_Obj **) &objv[2], peDoPost, flags));
11287 else if(objc == 2){
11288 if(!strcmp(s1, "userhdrs")){
11289 int i;
11290 char *p;
11291 PINEFIELD *custom, *cp;
11292 ADDRESS *from;
11293 static char *standard[] = {"To", "Cc", "Bcc", "Fcc", "Attach", "Subject", NULL};
11295 custom = peCustomHdrs();
11297 for(i = 0; standard[i]; i++){
11298 p = NULL;
11299 for(cp = custom; cp; cp = cp->next)
11300 if(!strucmp(cp->name, standard[i]))
11301 p = cp->textbuf;
11303 peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", standard[i], p);
11306 for(cp = custom; cp != NULL; cp = cp->next){
11307 if(!strucmp(cp->name, "from")){
11308 if(F_OFF(F_ALLOW_CHANGING_FROM, wps_global))
11309 continue;
11311 if(cp->textbuf && strlen(cp->textbuf)){
11312 p = cp->textbuf;
11314 else{
11315 RFC822BUFFER rbuf;
11317 wtmp_20k_buf[0] = '\0';
11318 rbuf.f = dummy_soutr;
11319 rbuf.s = NULL;
11320 rbuf.beg = wtmp_20k_buf;
11321 rbuf.cur = wtmp_20k_buf;
11322 rbuf.end = wtmp_20k_buf+SIZEOF_20KBUF-1;
11323 rfc822_output_address_list(&rbuf, from = generate_from(), 0L, NULL);
11324 *rbuf.cur = '\0';
11325 mail_free_address(&from);
11326 p = wtmp_20k_buf;
11329 else{
11330 p = cp->textbuf;
11331 for(i = 0; standard[i]; i++)
11332 if(!strucmp(standard[i], cp->name))
11333 p = NULL;
11335 if(!p)
11336 continue;
11339 peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", cp->name, p);
11342 if(custom)
11343 free_customs(custom);
11345 return(TCL_OK);
11347 else if(!strcmp(s1, "syshdrs")){
11348 int i;
11349 static char *extras[] = {"In-Reply-To", "X-Reply-UID", NULL};
11351 for(i = 0; extras[i]; i++)
11352 peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", extras[i], NULL);
11354 return(TCL_OK);
11356 else if(!strcmp(s1, "composehdrs")){
11357 char **p, *q;
11359 if((p = wps_global->VAR_COMP_HDRS) && *p){
11360 for(; *p; p++)
11361 Tcl_ListObjAppendElement(interp,
11362 Tcl_GetObjResult(interp),
11363 Tcl_NewStringObj(*p, (q = strchr(*p, ':'))
11364 ? (q - *p) : -1));
11366 else
11367 Tcl_SetResult(interp, "", TCL_STATIC);
11369 return(TCL_OK);
11371 else if(!strcmp(s1, "fccdefault")){
11372 int ci = 0;
11373 CONTEXT_S *c = default_save_context(wps_global->context_list), *c2;
11375 for(c2 = wps_global->context_list; c && c != c2; c2 = c2->next)
11376 ci++;
11378 Tcl_ListObjAppendElement(interp,
11379 Tcl_GetObjResult(interp),
11380 Tcl_NewIntObj(ci));
11381 Tcl_ListObjAppendElement(interp,
11382 Tcl_GetObjResult(interp),
11383 Tcl_NewStringObj(wps_global->VAR_DEFAULT_FCC
11384 ? wps_global->VAR_DEFAULT_FCC
11385 : "", -1));
11386 return(TCL_OK);
11388 else if(!strcmp(s1, "noattach")){
11389 peFreeAttach(&peCompAttach);
11390 Tcl_SetResult(interp, "OK", TCL_VOLATILE);
11391 return(TCL_OK);
11393 else if(!strcmp(s1, "from")){
11394 RFC822BUFFER rbuf;
11395 ADDRESS *from = generate_from();
11396 wtmp_20k_buf[0] = '\0';
11397 rbuf.f = dummy_soutr;
11398 rbuf.s = NULL;
11399 rbuf.beg = wtmp_20k_buf;
11400 rbuf.cur = wtmp_20k_buf;
11401 rbuf.end = wtmp_20k_buf+SIZEOF_20KBUF-1;
11402 rfc822_output_address_list(&rbuf, from, 0L, NULL);
11403 *rbuf.cur = '\0';
11404 mail_free_address(&from);
11405 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
11406 return(TCL_OK);
11408 else if(!strcmp(s1, "attachments")){
11409 COMPATT_S *p;
11410 Tcl_Obj *objAttach;
11412 for(p = peCompAttach; p; p = p->next)
11413 if(p->file){
11414 objAttach = Tcl_NewListObj(0, NULL);
11416 /* id */
11417 Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(p->id,-1));
11419 /* file name */
11420 Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(p->l.f.remote,-1));
11422 /* file size */
11423 Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewLongObj(p->l.f.size));
11425 /* type/subtype */
11426 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "%s/%s", p->l.f.type, p->l.f.subtype);
11427 Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(wtmp_20k_buf,-1));
11429 /* append to list */
11430 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach);
11432 else if(p->body){
11433 char *name;
11435 objAttach = Tcl_NewListObj(0, NULL);
11437 /* id */
11438 Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(p->id,-1));
11440 /* file name */
11441 if((name = get_filename_parameter(NULL, 0, p->l.b.body, NULL)) != NULL){
11442 Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(name, -1));
11443 fs_give((void **) &name);
11445 else
11446 Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj("Unknown", -1));
11448 /* file size */
11449 Tcl_ListObjAppendElement(interp, objAttach,
11450 Tcl_NewLongObj((p->l.b.body->encoding == ENCBASE64)
11451 ? ((p->l.b.body->size.bytes * 3)/4)
11452 : p->l.b.body->size.bytes));
11454 /* type/subtype */
11455 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "%s/%s",
11456 body_type_names(p->l.b.body->type),
11457 p->l.b.body->subtype ? p->l.b.body->subtype : "Unknown");
11458 Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(wtmp_20k_buf, -1));
11460 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach);
11463 return(TCL_OK);
11466 else if(objc == 3){
11467 if(!strcmp(s1, "unattach")){
11468 char *id;
11470 if((id = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
11471 if(peClearAttachID(id)){
11472 Tcl_SetResult(interp, "OK", TCL_STATIC);
11473 return(TCL_OK);
11475 else
11476 err = "Can't access attachment id";
11478 else
11479 err = "Can't read attachment id";
11481 else if(!strcmp(s1, "attachinfo")){
11482 COMPATT_S *a;
11483 char *id, *s;
11485 /* return: remote-filename size "type/subtype" */
11486 if((id = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
11487 if((a = peGetAttachID(id)) != NULL){
11488 if(a->file){
11489 /* file name */
11490 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(a->l.f.remote,-1));
11492 /* file size */
11493 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewLongObj(a->l.f.size));
11495 /* type/subtype */
11496 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "%s/%s", a->l.f.type, a->l.f.subtype);
11497 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(wtmp_20k_buf,-1));
11499 /* description */
11500 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
11501 Tcl_NewStringObj((a->l.f.description) ? a->l.f.description : "",-1));
11502 return(TCL_OK);
11504 else if(a->body){
11505 char *name;
11507 /* file name */
11508 if((name = get_filename_parameter(NULL, 0, a->l.b.body, NULL)) != NULL){
11509 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(name, -1));
11510 fs_give((void **) &name);
11512 else
11513 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj("Unknown", -1));
11515 /* file size */
11516 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
11517 Tcl_NewLongObj((a->l.b.body->encoding == ENCBASE64)
11518 ? ((a->l.b.body->size.bytes * 3)/4)
11519 : a->l.b.body->size.bytes));
11521 /* type/subtype */
11522 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "%s/%s",
11523 body_type_names(a->l.b.body->type),
11524 a->l.b.body->subtype ? a->l.b.body->subtype : "Unknown");
11526 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(wtmp_20k_buf, -1));
11528 /* description */
11529 if(a->l.b.body->description){
11530 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "%.*s", 256, a->l.b.body->description);
11532 else if((s = parameter_val(a->l.b.body->parameter, "description")) != NULL){
11533 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "%.*s", 256, s);
11534 fs_give((void **) &s);
11536 else
11537 wtmp_20k_buf[0] = '\0';
11539 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(wtmp_20k_buf, -1));
11541 return(TCL_OK);
11544 err = "Unknown attachment type";
11546 else
11547 err = "Can't access attachment id";
11549 else
11550 err = "Can't read attachment id";
11553 else if(objc == 7){
11554 if(!strcmp(s1, "attach")){
11555 char *file, *remote, *type, *subtype, *desc;
11557 if((file = Tcl_GetStringFromObj(objv[2], NULL))
11558 && (type = Tcl_GetStringFromObj(objv[3], NULL))
11559 && (subtype = Tcl_GetStringFromObj(objv[4], NULL))
11560 && (remote = Tcl_GetStringFromObj(objv[5], NULL))){
11561 int dl;
11563 desc = Tcl_GetStringFromObj(objv[6], &dl);
11565 if(desc){
11566 Tcl_SetResult(interp, peFileAttachID(file, type, subtype, remote, desc, dl), TCL_VOLATILE);
11567 return(TCL_OK);
11569 else
11570 err = "Can't read file description";
11572 else
11573 err = "Can't read file name";
11579 Tcl_SetResult(interp, err, TCL_STATIC);
11580 return(TCL_ERROR);
11584 COMPATT_S *
11585 peNewAttach(void)
11587 COMPATT_S *p = (COMPATT_S *) fs_get(sizeof(COMPATT_S));
11588 memset(p, 0, sizeof(COMPATT_S));
11589 return(p);
11593 void
11594 peFreeAttach(COMPATT_S **a)
11596 if(a && *a){
11597 fs_give((void **) &(*a)->id);
11599 if((*a)->file){
11600 if((*a)->l.f.type)
11601 fs_give((void **) &(*a)->l.f.type);
11603 if((*a)->l.f.subtype)
11604 fs_give((void **) &(*a)->l.f.subtype);
11606 if((*a)->l.f.remote)
11607 fs_give((void **) &(*a)->l.f.remote);
11609 if((*a)->l.f.local){
11610 (void) unlink((*a)->l.f.local);
11611 fs_give((void **) &(*a)->l.f.local);
11614 if((*a)->l.f.description)
11615 fs_give((void **) &(*a)->l.f.description);
11617 else if((*a)->body){
11618 pine_free_body(&(*a)->l.b.body);
11621 peFreeAttach(&(*a)->next);
11622 fs_give((void **) a);
11627 char *
11628 peFileAttachID(char *f, char *t, char *st, char *r, char *d, int dl)
11630 COMPATT_S *ap = peNewAttach(), *p;
11631 long hval;
11633 ap->file = TRUE;
11634 ap->l.f.local = cpystr(f);
11635 ap->l.f.size = name_file_size(f);
11637 hval = line_hash(f);
11638 while(1) /* collisions? */
11639 if(peGetAttachID(ap->id = cpystr(long2string(hval)))){
11640 fs_give((void **) &ap->id);
11641 hval += 1;
11643 else
11644 break;
11646 ap->l.f.remote = cpystr(r ? r : "");
11647 ap->l.f.type = cpystr(t ? t : "Text");
11648 ap->l.f.subtype = cpystr(st ? st : "Plain");
11650 ap->l.f.description = fs_get(dl + 1);
11651 snprintf(ap->l.f.description, dl + 1, "%s", d);
11653 if((p = peCompAttach) != NULL){
11655 if(!p->next){
11656 p->next = ap;
11657 break;
11659 while((p = p->next) != NULL);
11661 else
11662 peCompAttach = ap;
11664 return(ap->id);
11668 char *
11669 peBodyAttachID(BODY *b)
11671 COMPATT_S *ap = peNewAttach(), *p;
11672 unsigned long hval;
11674 ap->body = TRUE;
11675 ap->l.b.body = copy_body(NULL, b);
11677 hval = b->id ? line_hash(b->id) : time(0);
11678 while(1) /* collisions? */
11679 if(peGetAttachID(ap->id = cpystr(ulong2string(hval)))){
11680 fs_give((void **) &ap->id);
11681 hval += 1;
11683 else
11684 break;
11686 /* move contents pointer to copy */
11687 peBodyMoveContents(b, ap->l.b.body);
11689 if((p = peCompAttach) != NULL){
11691 if(!p->next){
11692 p->next = ap;
11693 break;
11695 while((p = p->next) != NULL);
11697 else
11698 peCompAttach = ap;
11700 return(ap->id);
11704 void
11705 peBodyMoveContents(BODY *bs, BODY *bd)
11707 if(bs && bd){
11708 if(bs->type == TYPEMULTIPART && bd->type == TYPEMULTIPART){
11709 PART *ps = bs->nested.part,
11710 *pd = bd->nested.part;
11711 do /* for each part */
11712 peBodyMoveContents(&ps->body, &pd->body);
11713 while ((ps = ps->next) && (pd = pd->next)); /* until done */
11715 else if(bs->contents.text.data){
11716 bd->contents.text.data = bs->contents.text.data;
11717 bs->contents.text.data = NULL;
11724 COMPATT_S *
11725 peGetAttachID(char *h)
11727 COMPATT_S *p;
11729 for(p = peCompAttach; p; p = p->next)
11730 if(!strcmp(p->id, h))
11731 return(p);
11733 return(NULL);
11738 peClearAttachID(char *h)
11740 COMPATT_S *pp, *pt = NULL;
11742 for(pp = peCompAttach; pp; pp = pp->next){
11743 if(!strcmp(pp->id, h)){
11744 if(pt)
11745 pt->next = pp->next;
11746 else
11747 peCompAttach = pp->next;
11749 pp->next = NULL;
11750 peFreeAttach(&pp);
11751 return(TRUE);
11754 pt = pp;
11757 return(FALSE);
11762 * peDoPost - handle preparing header and body text for posting, prepare
11763 * for any Fcc, then call the mailer to send it out
11766 peDoPost(METAENV *metaenv, BODY *body, char *fcc, CONTEXT_S **fcc_cntxtp, char *errp)
11768 int rv = TCL_OK, recipients;
11769 char *s;
11771 if(commence_fcc(fcc, fcc_cntxtp, TRUE)){
11773 wps_global->c_client_error[0] = wps_global->last_error[0] = '\0';
11774 pePrepareForAuthException();
11776 if((recipients = (metaenv->env->to || metaenv->env->cc || metaenv->env->bcc))
11777 && call_mailer(metaenv, body, NULL, 0, NULL, NULL) < 0){
11778 if((s = peAuthException()) != NULL){
11779 strcpy(errp, s);
11781 else if(wps_global->last_error[0]){
11782 sprintf(errp, "Send Error: %.*s", 64, wps_global->last_error);
11784 else if(wps_global->c_client_error[0]){
11785 sprintf(errp, "Send Error: %.*s", 64, wps_global->c_client_error);
11787 else
11788 strcpy(errp, "Sending Failure");
11790 rv = TCL_ERROR;
11791 dprint((1, "call_mailer failed!"));
11793 else if(fcc && fcc_cntxtp && !wrapup_fcc(fcc, *fcc_cntxtp, recipients ? NULL : metaenv, body)){
11794 strcpy(errp, "Fcc Failed!. No message saved.");
11795 rv = TCL_ERROR;
11796 dprint((1, "explicit fcc write failed!"));
11798 else{
11799 PINEFIELD *pf;
11800 REPLY_S *reply = NULL;
11802 /* success, now look for x-reply-uid to flip answered flag for? */
11804 for(pf = metaenv->local; pf && pf->name; pf = pf->next)
11805 if(!strucmp(pf->name, "x-reply-uid")){
11806 if(pf->textbuf){
11807 if((reply = (REPLY_S *) build_reply_uid(pf->textbuf)) != NULL){
11809 update_answered_flags(reply);
11811 if(reply->mailbox)
11812 fs_give((void **) &reply->mailbox);
11814 if(reply->prefix)
11815 fs_give((void **) &reply->prefix);
11817 if(reply->data.uid.msgs)
11818 fs_give((void **) &reply->data.uid.msgs);
11820 fs_give((void **) &reply);
11824 break;
11828 else{
11829 dprint((1,"can't open fcc, cont"));
11831 strcpy(errp, "Can't open Fcc");
11832 rv = TCL_ERROR;
11835 return(rv);
11841 * pePostponeCmd - export various bits of alpine state
11844 PEPostponeCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
11846 char *err = "PEPostpone: unknown request";
11847 long uidl;
11848 imapuid_t uid;
11850 dprint((2, "PEPostponeCmd"));
11852 if(objc == 1){
11853 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
11855 else if(!wps_global){
11856 Tcl_SetResult(interp, "pePostpone: no config present", TCL_STATIC);
11857 return(TCL_ERROR);
11859 else{
11860 char *s1 = Tcl_GetStringFromObj(objv[1], NULL);
11862 if(s1){
11863 if(!strcmp(s1, "extract")){
11864 if(Tcl_GetLongFromObj(interp, objv[2], &uidl) == TCL_OK){
11865 Tcl_Obj *objHdr = NULL, *objBod = NULL, *objAttach = NULL, *objOpts = NULL;
11866 MAILSTREAM *stream;
11867 BODY *b;
11868 ENVELOPE *env = NULL;
11869 PINEFIELD *custom = NULL, *cp;
11870 REPLY_S *reply = NULL;
11871 ACTION_S *role = NULL;
11872 STORE_S *so;
11873 long n;
11874 int rv = TCL_OK;
11875 char *fcc = NULL, *lcc = NULL;
11876 unsigned flags = REDRAFT_DEL | REDRAFT_PPND;
11878 uid = uidl;
11879 if(objc > 3){ /* optional flags */
11880 int i, nFlags;
11881 Tcl_Obj **objFlags;
11882 char *flagstr;
11884 Tcl_ListObjGetElements(interp, objv[3], &nFlags, &objFlags);
11885 for(i = 0; i < nFlags; i++){
11886 if((flagstr = Tcl_GetStringFromObj(objFlags[i], NULL)) == NULL){
11887 rv = TCL_ERROR;
11890 if(!strucmp(flagstr, "html"))
11891 flags |= REDRAFT_HTML;
11894 /* BUG: should probably complain if argc > 4 */
11896 if(rv == TCL_OK
11897 && postponed_stream(&stream, wps_global->VAR_POSTPONED_FOLDER, "Postponed", 0)
11898 && stream){
11899 if((so = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
11900 if((n = mail_msgno(stream, uid)) > 0L){
11901 if(redraft_work(&stream, n, &env, &b, &fcc, &lcc, &reply,
11902 NULL, &custom, &role, /* should role be NULL? */
11903 flags, so)){
11904 char *charset = NULL;
11906 /* prepare to package up for caller */
11907 objHdr = Tcl_NewListObj(0, NULL);
11909 /* determine body part's charset */
11910 if((charset = parameter_val(b->parameter,"charset")) != NULL){
11911 objOpts = Tcl_NewListObj(0, NULL);
11912 peAppListF(interp, objOpts, "%s%s", "charset", charset);
11913 fs_give((void **) &charset);
11916 /* body part's MIME subtype */
11917 if(b->subtype && strucmp(b->subtype,"plain")){
11918 if(!objOpts)
11919 objOpts = Tcl_NewListObj(0, NULL);
11921 peAppListF(interp, objOpts, "%s%s", "subtype", b->subtype);
11924 peAppListF(interp, objHdr, "%s%a", "from",
11925 role && role->from ? role->from : env->from);
11926 peAppListF(interp, objHdr, "%s%a", "to", env->to);
11927 peAppListF(interp, objHdr, "%s%a", "cc", env->cc);
11928 peAppListF(interp, objHdr, "%s%a", "bcc", env->bcc);
11929 peAppListF(interp, objHdr, "%s%s", "in-reply-to", env->in_reply_to);
11930 peAppListF(interp, objHdr, "%s%s", "subject",
11931 rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf,
11932 SIZEOF_20KBUF, env->subject));
11934 if(fcc)
11935 peFccAppend(interp, objHdr, fcc, -1);
11937 for(cp = custom; cp && cp->name; cp = cp->next)
11938 switch(cp->type){
11939 case Address :
11940 strncpy(wtmp_20k_buf, cp->name, SIZEOF_20KBUF);
11941 wtmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
11942 peAppListF(interp, objHdr, "%s%a",
11943 lcase((unsigned char *) wtmp_20k_buf), *cp->addr);
11944 break;
11946 case Attachment :
11947 break;
11949 case Fcc :
11950 case Subject :
11951 break; /* ignored */
11953 default :
11954 strncpy(wtmp_20k_buf, cp->name, SIZEOF_20KBUF);
11955 wtmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
11956 peAppListF(interp, objHdr, "%s%s",
11957 lcase((unsigned char *) wtmp_20k_buf), cp->textbuf ? cp->textbuf : cp->val);
11958 break;
11961 if(reply){
11962 /* blat x-Reply-UID: for possible use? */
11963 if(reply->uid){
11964 char uidbuf[MAILTMPLEN], *p;
11965 long i;
11967 for(i = 0L, p = wtmp_20k_buf; reply->data.uid.msgs[i]; i++){
11968 if(i)
11969 sstrncpy(&p, ",", SIZEOF_20KBUF-(p-wtmp_20k_buf));
11971 sstrncpy(&p,ulong2string(reply->data.uid.msgs[i]), SIZEOF_20KBUF-(p-wtmp_20k_buf));
11974 wtmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
11976 snprintf(uidbuf, sizeof(uidbuf), "(%s%s%s)(%ld %lu %s)%s",
11977 reply->prefix ? int2string(strlen(reply->prefix))
11978 : (reply->forwarded) ? "" : "0 ",
11979 reply->prefix ? " " : "",
11980 reply->prefix ? reply->prefix : "",
11981 i, reply->data.uid.validity,
11982 wtmp_20k_buf, reply->mailbox);
11984 peAppListF(interp, objHdr, "%s%s", "x-reply-uid", uidbuf);
11987 fs_give((void **) &reply->mailbox);
11988 fs_give((void **) &reply->prefix);
11989 fs_give((void **) &reply->data.uid.msgs);
11990 fs_give((void **) &reply);
11993 objBod = Tcl_NewListObj(0, NULL);
11994 peSoStrToList(interp, objBod, so);
11996 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objHdr);
11997 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objBod);
11999 objAttach = peMsgAttachCollector(interp, b);
12001 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach);
12003 if(objOpts){
12004 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),objOpts);
12007 /* clean up */
12008 if(fcc)
12009 fs_give((void **) &fcc);
12011 if(lcc)
12012 fs_give((void **) &lcc);
12014 mail_free_envelope(&env);
12015 pine_free_body(&b);
12016 free_action(&role);
12018 /* if Drafts got whacked, open INBOX */
12019 if(!wps_global->mail_stream)
12020 do_broach_folder(wps_global->inbox_name,
12021 wps_global->context_list,
12022 NULL, DB_INBOXWOCNTXT);
12024 return(TCL_OK);
12027 so_give(&so);
12029 else
12030 err = "Unknown UID";
12032 else
12033 err = "No internal storage";
12035 /* redraft_work cleaned up the "stream" */
12037 else
12038 err = "No Postponed stream";
12040 else
12041 err = "Malformed extract request";
12043 else if(objc == 2){
12044 if(!strcmp(s1, "any")){
12045 MAILSTREAM *stream;
12047 if(postponed_stream(&stream, wps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
12048 Tcl_SetResult(interp, "1", TCL_STATIC);
12050 if(stream != wps_global->mail_stream)
12051 pine_mail_close(stream);
12053 else
12054 Tcl_SetResult(interp, "0", TCL_STATIC);
12056 return(TCL_OK);
12058 else if(!strcmp(s1, "count")){
12059 MAILSTREAM *stream;
12061 if(postponed_stream(&stream, wps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
12062 Tcl_SetResult(interp, long2string(stream->nmsgs), TCL_STATIC);
12064 if(stream != wps_global->mail_stream)
12065 pine_mail_close(stream);
12067 else
12068 Tcl_SetResult(interp, "-1", TCL_STATIC);
12070 return(TCL_OK);
12072 else if(!strcmp(s1, "list")){
12073 MAILSTREAM *stream;
12074 ENVELOPE *env;
12075 Tcl_Obj *objEnv = NULL, *objEnvList;
12076 long n;
12078 if(postponed_stream(&stream, wps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
12079 if(!stream->nmsgs){
12080 (void) redraft_cleanup(&stream, FALSE, REDRAFT_PPND);
12081 Tcl_SetResult(interp, "", TCL_STATIC);
12082 return(TCL_OK);
12085 objEnvList = Tcl_NewListObj(0, NULL);
12087 for(n = 1; n <= stream->nmsgs; n++){
12088 if((env = pine_mail_fetchstructure(stream, n, NULL)) != NULL){
12089 objEnv = Tcl_NewListObj(0, NULL);
12091 peAppListF(interp, objEnv, "%s%s", "uid",
12092 ulong2string(mail_uid(stream, n)));
12094 peAppListF(interp, objEnv, "%s%a", "to", env->to);
12096 date_str((char *)env->date, iSDate, 1, wtmp_20k_buf, SIZEOF_20KBUF, 0);
12098 peAppListF(interp, objEnv, "%s%s", "date", wtmp_20k_buf);
12100 peAppListF(interp, objEnv, "%s%s", "subj",
12101 rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf,
12102 SIZEOF_20KBUF, env->subject));
12104 Tcl_ListObjAppendElement(interp, objEnvList, objEnv);
12108 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objEnvList);
12110 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
12111 Tcl_NewStringObj("utf-8", -1));
12113 if(stream != wps_global->mail_stream)
12114 pine_mail_close(stream);
12117 return(TCL_OK);
12120 else if(objc == 3){
12121 if(!strcmp(s1, "append")){
12122 int rv;
12124 if((rv = peMsgCollector(interp, objc - 2, (Tcl_Obj **) &objv[2], peDoPostpone, PMC_NONE)) == TCL_OK)
12125 Tcl_SetResult(interp, ulong2string(get_last_append_uid()), TCL_VOLATILE);
12127 return(rv);
12129 else if(!strcmp(s1, "draft")){
12130 int rv;
12132 if((rv = peMsgCollector(interp, objc - 2, (Tcl_Obj **) &objv[2], peDoPostpone, PMC_PRSRV_ATT)) == TCL_OK)
12133 Tcl_SetResult(interp, ulong2string(get_last_append_uid()), TCL_VOLATILE);
12135 return(rv);
12137 else if(!strcmp(s1, "delete")){
12138 if(Tcl_GetLongFromObj(interp, objv[2], &uidl) == TCL_OK){
12139 MAILSTREAM *stream;
12140 long rawno;
12142 uid = uidl;
12143 if(postponed_stream(&stream, wps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){
12144 if((rawno = mail_msgno(stream, uid)) > 0L){
12145 mail_flag(stream, long2string(rawno), "\\DELETED", ST_SET);
12146 wps_global->expunge_in_progress = 1;
12147 mail_expunge(stream);
12148 wps_global->expunge_in_progress = 0;
12149 if(stream != wps_global->mail_stream)
12150 pine_mail_actually_close(stream);
12152 return(TCL_OK);
12154 else
12155 err = "PEPostpone delete: UID no longer exists";
12157 else
12158 err = "PEPostpone delete: No Postponed stream";
12160 else
12161 err = "PEPostpone delete: No uid provided";
12167 Tcl_SetResult(interp, err, TCL_STATIC);
12168 return(TCL_ERROR);
12173 * peDoPostpone - handle postponing after message collection
12176 peDoPostpone(METAENV *metaenv, BODY *body, char *fcc, CONTEXT_S **fcc_cntxtp, char *errp)
12178 PINEFIELD *pf;
12179 int rv;
12180 appenduid_t *au;
12183 * resolve fcc and store it in fcc custom header field data
12185 if(fcc && *fcc && fcc_cntxtp && *fcc_cntxtp)
12186 for(pf = metaenv->local; pf && pf->name; pf = pf->next)
12187 if(!strucmp("fcc", pf->name)){
12188 char *name, *rs, path_in_context[MAILTMPLEN];
12190 if(pf->textbuf) /* free old value */
12191 fs_give((void **) &pf->textbuf);
12193 /* replace nickname with full name */
12194 if(!(name = folder_is_nick(fcc, FOLDERS(*fcc_cntxtp), FN_NONE)))
12195 name = fcc;
12197 if(context_isambig(name) && !(((*fcc_cntxtp)->use) & CNTXT_SAVEDFLT)){
12198 context_apply(path_in_context, *fcc_cntxtp, name, sizeof(path_in_context));
12199 rs = IS_REMOTE(path_in_context) ? path_in_context : NULL;
12201 else
12202 rs = cpystr(name);
12204 if(rs){
12205 pf->textbuf = cpystr(rs);
12206 pf->text = &pf->textbuf;
12209 break;
12212 au = mail_parameters(NIL, GET_APPENDUID, NIL);
12213 mail_parameters(NIL, SET_APPENDUID, (void *) appenduid_cb);
12215 rv = write_postponed(metaenv, body);
12217 mail_parameters(NIL, SET_APPENDUID, (void *) au);
12219 return((rv < 0) ? TCL_ERROR : TCL_OK);
12224 * peMsgCollector - Collect message parts and call specified handler
12227 peMsgCollector(Tcl_Interp *interp,
12228 int objc,
12229 Tcl_Obj **objv,
12230 int (*postfunc)(METAENV *, BODY *, char *, CONTEXT_S **, char *),
12231 long flags)
12233 Tcl_Obj **objMsg, **objField, **objBody;
12234 int i, j, vl, nMsg, nField, nBody;
12235 char *field, *value, *err = NULL;
12236 MSG_COL_S md;
12237 PINEFIELD *pf;
12238 STRLIST_S *tp, *lp;
12239 static char *fakedomain = "@";
12241 memset(&md, 0, sizeof(MSG_COL_S));
12242 md.postop_fcc_no_attach = -1;
12243 md.postfunc = postfunc;
12244 md.qualified_addrs = ((flags & PMC_FORCE_QUAL) == PMC_FORCE_QUAL);
12246 if(objc != 1){
12247 Tcl_SetResult(interp, "Malformed message data", TCL_STATIC);
12248 return(TCL_ERROR);
12250 else if(!wps_global){
12251 Tcl_SetResult(interp, "No open folder", TCL_STATIC);
12252 return(TCL_ERROR);
12255 md.outgoing = mail_newenvelope();
12257 md.metaenv = pine_new_env(md.outgoing, NULL, NULL, md.custom = peCustomHdrs());
12259 Tcl_ListObjGetElements(interp, objv[0], &nMsg, &objMsg);
12260 for(i = 0; i < nMsg; i++){
12261 if(Tcl_ListObjGetElements(interp, objMsg[i], &nField, &objField) != TCL_OK){
12262 err = ""; /* interp's result object has error message */
12263 return(peMsgCollected(interp, &md, err, flags));
12266 if(nField && (field = Tcl_GetStringFromObj(objField[0], NULL))){
12267 if(!strcmp(field, "body")){
12268 if(md.msgtext){
12269 err = "Too many bodies";
12270 return(peMsgCollected(interp, &md, err, flags));
12272 else if((md.msgtext = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
12273 /* mark storage object as user edited */
12274 (void) so_attr(md.msgtext, "edited", "1");
12276 Tcl_ListObjGetElements(interp, objField[1], &nBody, &objBody);
12277 for(j = 0; j < nBody; j++){
12278 value = Tcl_GetStringFromObj(objBody[j], &vl);
12279 if(value){
12280 so_nputs(md.msgtext, value, vl);
12281 so_puts(md.msgtext, "\n");
12283 else{
12284 err = "Value read failure";
12285 return(peMsgCollected(interp, &md, err, flags));
12289 else {
12290 err = "Can't acquire body storage";
12291 return(peMsgCollected(interp, &md, err, flags));
12294 else if(!strucmp(field, "attach")){
12295 char *id;
12296 COMPATT_S *a;
12298 if(nField == 2
12299 && (id = Tcl_GetStringFromObj(objField[1], NULL))
12300 && (a = peGetAttachID(id))){
12301 tp = new_strlist(id);
12302 if((lp = md.attach) != NULL){
12304 if(!lp->next){
12305 lp->next = tp;
12306 break;
12308 while((lp = lp->next) != NULL);
12310 else
12311 md.attach = tp;
12313 else{
12314 strcpy(err = wtmp_20k_buf, "Unknown attachment ID");
12315 return(peMsgCollected(interp, &md, err, flags));
12318 else if(!strucmp(field, "fcc")){
12319 Tcl_Obj **objFcc;
12320 int nFcc;
12322 if(Tcl_ListObjGetElements(interp, objField[1], &nFcc, &objFcc) == TCL_OK
12323 && nFcc == 2
12324 && Tcl_GetIntFromObj(interp, objFcc[0], &md.fcc_colid) == TCL_OK
12325 && (value = Tcl_GetStringFromObj(objFcc[1], NULL))){
12326 if(md.fcc)
12327 fs_give((void **) &md.fcc);
12329 md.fcc = cpystr(value);
12331 else {
12332 strcpy(err = wtmp_20k_buf, "Unrecognized Fcc specification");
12333 return(peMsgCollected(interp, &md, err, flags));
12336 else if(!strucmp(field, "postoption")){
12337 Tcl_Obj **objPO;
12338 int nPO, ival;
12340 value = NULL;
12341 if(Tcl_ListObjGetElements(interp, objField[1], &nPO, &objPO) == TCL_OK
12342 && nPO == 2
12343 && (value = Tcl_GetStringFromObj(objPO[0], NULL))){
12344 if(!strucmp(value,"fcc-without-attachments")){
12345 if(Tcl_GetIntFromObj(interp, objPO[1], &ival) == TCL_OK){
12346 md.postop_fcc_no_attach = (ival != 0);
12348 else{
12349 sprintf(err = wtmp_20k_buf, "Malformed Post Option: fcc-without-attachments");
12350 return(peMsgCollected(interp, &md, err, flags));
12353 else if(!strucmp(value, "charset")){
12354 if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){
12355 char *p;
12357 for(p = value; ; p++){ /* sanity check */
12358 if(!*p){
12359 md.charset = cpystr(value);
12360 break;
12363 if(isspace((unsigned char ) *p)
12364 || !isprint((unsigned char) *p))
12365 break;
12367 if(p - value > 255)
12368 break;
12371 else{
12372 err = "Post option read failure";
12373 return(peMsgCollected(interp, &md, err, flags));
12376 else if(!strucmp(value, "flowed")){
12377 if(F_OFF(F_QUELL_FLOWED_TEXT,wps_global)){
12378 if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){
12379 if(!strucmp(value, "yes"))
12380 md.flowed = 1;
12382 else{
12383 err = "Post option read failure";
12384 return(peMsgCollected(interp, &md, err, flags));
12388 else if(!strucmp(value, "subtype")){
12389 if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){
12390 if(!strucmp(value, "html"))
12391 md.html = 1;
12393 else{
12394 err = "Post option read failure";
12395 return(peMsgCollected(interp, &md, err, flags));
12398 else if(!strucmp(value, "priority")){
12399 if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){
12400 char *priority = NULL;
12402 if(!strucmp(value, "highest"))
12403 priority = "Highest";
12404 else if(!strucmp(value, "high"))
12405 priority = "High";
12406 else if(!strucmp(value, "normal"))
12407 priority = "Normal";
12408 else if(!strucmp(value, "low"))
12409 priority = "Low";
12410 else if(!strucmp(value, "lowest"))
12411 priority = "Lowest";
12413 if(priority){
12414 if((pf = set_priority_header(md.metaenv, priority)) != NULL)
12415 pf->text = &pf->textbuf;
12418 else{
12419 err = "Post option read failure";
12420 return(peMsgCollected(interp, &md, err, flags));
12423 else{
12424 sprintf(err = wtmp_20k_buf, "Unknown Post Option: %s", value);
12425 return(peMsgCollected(interp, &md, err, flags));
12428 else{
12429 sprintf(err = wtmp_20k_buf, "Malformed Post Option");
12430 return(peMsgCollected(interp, &md, err, flags));
12433 else {
12434 if(nField != 2){
12435 sprintf(err = wtmp_20k_buf, "Malformed header (%s)", field);
12436 return(peMsgCollected(interp, &md, err, flags));
12439 if((value = Tcl_GetStringFromObj(objField[1], &vl)) != NULL){
12440 ADDRESS **addrp = NULL;
12441 char **valp = NULL, *valcpy;
12443 if(!strucmp(field, "from")){
12444 addrp = &md.outgoing->from;
12446 else if(!strucmp(field, "reply-to")){
12447 addrp = &md.outgoing->reply_to;
12449 else if(!strucmp(field, "to")){
12450 addrp = &md.outgoing->to;
12452 else if(!strucmp(field, "cc")){
12453 addrp = &md.outgoing->cc;
12455 else if(!strucmp(field, "bcc")){
12456 addrp = &md.outgoing->bcc;
12458 else if(!strucmp(field, "subject")){
12459 valp = &md.outgoing->subject;
12461 else if(!strucmp(field, "in-reply-to")){
12462 valp = &md.outgoing->in_reply_to;
12464 else if(!strucmp(field, "newsgroups")){
12465 valp = &md.outgoing->newsgroups;
12467 else if(!strucmp(field, "followup-to")){
12468 valp = &md.outgoing->followup_to;
12470 else if(!strucmp(field, "references")){
12471 valp = &md.outgoing->references;
12473 else if(!strucmp(field, "x-reply-uid")){
12474 for(pf = md.metaenv->local; pf && pf->name; pf = pf->next)
12475 if(!strucmp(pf->name, "x-reply-uid")){
12476 valp = pf->text = &pf->textbuf;
12477 break;
12480 else if(!strucmp(field, "x-auth-received")){
12481 for(pf = md.metaenv->local; pf && pf->name; pf = pf->next)
12482 if(!strucmp(pf->name, "x-auth-received")){
12483 valp = pf->text = &pf->textbuf;
12484 break;
12487 else{
12488 for(pf = md.metaenv->custom; pf && pf->name; pf = pf->next)
12489 if(!strucmp(field, pf->name)){
12490 if(pf->type == Address)
12491 addrp = pf->addr;
12492 else if(vl)
12493 valp = &pf->textbuf;
12494 else if(pf->textbuf)
12495 fs_give((void **) &pf->textbuf);
12497 break;
12500 if(!pf)
12501 dprint((2, "\nPOST: unrecognized field - %s\n", field));
12504 if(valp){
12505 if(*valp)
12506 fs_give((void **) valp);
12508 sprintf(*valp = fs_get((vl + 1) * sizeof(char)), "%.*s", vl, value);
12511 if(addrp){
12512 sprintf(valcpy = fs_get((vl + 1) * sizeof(char)), "%.*s", vl, value);
12514 for(; *addrp; addrp = &(*addrp)->next)
12517 rfc822_parse_adrlist(addrp, valcpy,
12518 (flags & PMC_FORCE_QUAL)
12519 ? fakedomain : wps_global->maildomain);
12520 fs_give((void **) &valcpy);
12523 else{
12524 err = "Value read failure";
12525 return(peMsgCollected(interp, &md, err, flags));
12531 return(peMsgCollected(interp, &md, err, flags));
12536 * peMsgCollected - Dispatch collected message data and cleanup
12539 peMsgCollected(Tcl_Interp *interp, MSG_COL_S *md, char *err, long flags)
12541 int rv = TCL_OK, non_ascii = FALSE;
12542 unsigned char c;
12543 BODY *body = NULL, *tbp = NULL;
12544 char errbuf[WP_MAX_POST_ERROR + 1], *charset;
12545 STRLIST_S *lp;
12547 if(err){
12548 if(md->msgtext)
12549 so_give(&md->msgtext);
12551 rv = TCL_ERROR;
12553 else if(md->qualified_addrs && check_addresses(md->metaenv) == CA_BAD){
12554 sprintf(err = wtmp_20k_buf, "Address must be fully qualified.");
12555 rv = TCL_ERROR;
12557 else{
12558 /* sniff body for possible multipart wrapping to protect encoding */
12559 so_seek(md->msgtext, 0L, 0);
12561 while(so_readc(&c, md->msgtext))
12562 if(!c || c & 0x80){
12563 non_ascii = TRUE;
12564 break;
12567 if(!md->outgoing->from)
12568 md->outgoing->from = generate_from();
12570 rfc822_date(wtmp_20k_buf);
12571 md->outgoing->date = (unsigned char *) cpystr(wtmp_20k_buf);
12572 md->outgoing->return_path = rfc822_cpy_adr(md->outgoing->from);
12573 md->outgoing->message_id = generate_message_id(NULL);
12575 body = mail_newbody();
12577 /* wire any attachments to body */
12578 if(md->attach || (non_ascii && F_OFF(F_COMPOSE_ALWAYS_DOWNGRADE, wps_global))){
12579 PART **np;
12580 PARAMETER **pp;
12581 COMPATT_S *a;
12583 /* setup slot for message text */
12584 body->type = TYPEMULTIPART;
12585 body->nested.part = mail_newbody_part();
12586 tbp = &body->nested.part->body;
12588 /* link in attachments */
12589 for(lp = md->attach, np = &body->nested.part->next; lp; lp = lp->next, np = &(*np)->next){
12590 if(!(a = peGetAttachID(lp->name))){
12591 err = "Unknown Attachment ID";
12592 rv = TCL_ERROR;
12593 break;
12596 *np = mail_newbody_part();
12598 if(a->file){
12599 (*np)->body.id = generate_message_id(NULL);
12600 (*np)->body.description = cpystr(a->l.f.description);
12602 /* set name parameter */
12603 for(pp = &(*np)->body.parameter; *pp; )
12604 if(!struncmp((*pp)->attribute, "name", 4)
12605 && (!*((*pp)->attribute + 4)
12606 || *((*pp)->attribute + 4) == '*')){
12607 PARAMETER *free_me = *pp;
12608 *pp = (*pp)->next;
12609 free_me->next = NULL;
12610 mail_free_body_parameter(&free_me);
12612 else
12613 pp = &(*pp)->next;
12615 *pp = NULL;
12616 set_parameter(pp, "name", a->l.f.remote);
12618 /* Then set the Content-Disposition ala RFC1806 */
12619 if(!(*np)->body.disposition.type){
12620 (*np)->body.disposition.type = cpystr("attachment");
12621 for(pp = &(*np)->body.disposition.parameter; *pp; )
12622 if(!struncmp((*pp)->attribute, "filename", 4)
12623 && (!*((*pp)->attribute + 4)
12624 || *((*pp)->attribute + 4) == '*')){
12625 PARAMETER *free_me = *pp;
12626 *pp = (*pp)->next;
12627 free_me->next = NULL;
12628 mail_free_body_parameter(&free_me);
12630 else
12631 pp = &(*pp)->next;
12633 *pp = NULL;
12634 set_parameter(pp, "filename", a->l.f.remote);
12637 if(((*np)->body.contents.text.data = (void *) so_get(FileStar, a->l.f.local, READ_ACCESS)) != NULL){
12638 (*np)->body.type = mt_translate_type(a->l.f.type);
12639 (*np)->body.subtype = cpystr(a->l.f.subtype);
12640 (*np)->body.encoding = ENCBINARY;
12641 (*np)->body.size.bytes = name_file_size(a->l.f.local);
12643 if((*np)->body.type == TYPEOTHER
12644 && !set_mime_type_by_extension(&(*np)->body, a->l.f.local))
12645 set_mime_type_by_grope(&(*np)->body);
12647 so_release((STORE_S *)(*np)->body.contents.text.data);
12649 else{
12650 /* unravel here */
12651 err = "Can't open uploaded attachment";
12652 rv = TCL_ERROR;
12653 break;
12656 else if(a->body){
12657 BODY *newbody = copy_body(NULL, a->l.b.body);
12658 (*np)->body = *newbody;
12659 fs_give((void **) &newbody);
12660 peBodyMoveContents(a->l.b.body, &(*np)->body);
12662 else{
12663 err = "BOTCH: Unknown attachment type";
12664 rv = TCL_ERROR;
12665 break;
12669 else
12670 tbp = body;
12672 /* assign MIME parameters to text body part */
12673 tbp->type = TYPETEXT;
12674 if(md->html) tbp->subtype = cpystr("HTML");
12676 tbp->contents.text.data = (void *) md->msgtext;
12677 tbp->encoding = ENCOTHER;
12679 /* set any text flowed param */
12680 if(md->flowed)
12681 peMsgSetParm(&tbp->parameter, "format", "flowed");
12683 if(rv == TCL_OK){
12684 CONTEXT_S *fcc_cntxt = wps_global->context_list;
12686 while(md->fcc_colid--)
12687 if(fcc_cntxt->next)
12688 fcc_cntxt = fcc_cntxt->next;
12690 if(md->postop_fcc_no_attach >= 0){
12691 int oldval = F_ON(F_NO_FCC_ATTACH, wps_global);
12692 F_SET(F_NO_FCC_ATTACH, wps_global, md->postop_fcc_no_attach);
12693 md->postop_fcc_no_attach = oldval;
12696 pine_encode_body(body);
12698 rv = (*md->postfunc)(md->metaenv, body, md->fcc, &fcc_cntxt, errbuf);
12700 if(md->postop_fcc_no_attach >= 0){
12701 F_SET(F_NO_FCC_ATTACH, wps_global, md->postop_fcc_no_attach);
12704 if(rv == TCL_OK){
12705 if((flags & PMC_PRSRV_ATT) == 0)
12706 peFreeAttach(&peCompAttach);
12708 else{
12709 /* maintain pointers to attachments */
12710 (void) peMsgAttachCollector(NULL, body);
12711 err = errbuf;
12715 pine_free_body(&body);
12718 if(md->charset)
12719 fs_give((void **) &md->charset);
12721 free_strlist(&md->attach);
12723 pine_free_env(&md->metaenv);
12725 if(md->custom)
12726 free_customs(md->custom);
12728 mail_free_envelope(&md->outgoing);
12730 if(err && *err)
12731 Tcl_SetResult(interp, err, TCL_VOLATILE);
12733 return(rv);
12737 void
12738 peMsgSetParm(PARAMETER **pp, char *pa, char *pv)
12740 for(; *pp; pp = &(*pp)->next)
12741 if(!strucmp(pa, (*pp)->attribute)){
12742 if((*pp)->value)
12743 fs_give((void **) &(*pp)->value);
12745 break;
12748 if(!*pp){
12749 *pp = mail_newbody_parameter();
12750 (*pp)->attribute = cpystr(pa);
12753 (*pp)->value = cpystr(pv);
12757 Tcl_Obj *
12758 peMsgAttachCollector(Tcl_Interp *interp, BODY *b)
12760 char *id, *name = NULL;
12761 PART *part;
12762 Tcl_Obj *aListObj = NULL, *aObj = NULL;
12764 peFreeAttach(&peCompAttach);
12766 if(interp)
12767 aListObj = Tcl_NewListObj(0, NULL);
12769 if(b->type == TYPEMULTIPART){
12771 * Walk first level, clipping branches and adding them
12772 * to the attachment list...
12774 for(part = b->nested.part->next; part; part = part->next) {
12775 id = peBodyAttachID(&part->body);
12776 aObj = Tcl_NewListObj(0, NULL);
12778 if(interp){
12779 Tcl_ListObjAppendElement(interp, aObj, Tcl_NewStringObj(id, -1));
12781 /* name */
12782 if((name = get_filename_parameter(NULL, 0, &part->body, NULL)) != NULL){
12783 Tcl_ListObjAppendElement(interp, aObj, Tcl_NewStringObj(name, -1));
12784 fs_give((void **) &name);
12786 else
12787 Tcl_ListObjAppendElement(interp, aObj, Tcl_NewStringObj("Unknown", -1));
12789 /* size */
12790 Tcl_ListObjAppendElement(interp, aObj,
12791 Tcl_NewLongObj((part->body.encoding == ENCBASE64)
12792 ? ((part->body.size.bytes * 3)/4)
12793 : part->body.size.bytes));
12795 /* type */
12796 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "%s/%s",
12797 body_type_names(part->body.type),
12798 part->body.subtype ? part->body.subtype : rfc822_default_subtype (part->body.type));
12799 Tcl_ListObjAppendElement(interp, aObj, Tcl_NewStringObj(wtmp_20k_buf, -1));
12800 Tcl_ListObjAppendElement(interp, aListObj, aObj);
12805 return (aListObj);
12810 peFccAppend(Tcl_Interp *interp, Tcl_Obj *obj, char *fcc, int colid)
12812 Tcl_Obj *objfcc = NULL;
12814 if(colid < 0)
12815 colid = (wps_global->context_list && (wps_global->context_list->use & CNTXT_INCMNG)) ? 1 : 0;
12817 return((objfcc = Tcl_NewListObj(0, NULL))
12818 && Tcl_ListObjAppendElement(interp, objfcc, Tcl_NewStringObj("fcc", -1)) == TCL_OK
12819 && peAppListF(interp, objfcc, "%i%s", colid, fcc) == TCL_OK
12820 && Tcl_ListObjAppendElement(interp, obj, objfcc) == TCL_OK);
12824 /* * * * * * * * * * * * * Start of Address Management Routines * * * * * * * * * * * */
12828 * PEAddressCmd - export various bits of address book/directory access
12831 PEAddressCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
12833 char *op;
12835 dprint((2, "PEAddressCmd"));
12837 if(objc == 1){
12838 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
12839 return(TCL_ERROR);
12841 else if(!wps_global){
12842 Tcl_SetResult(interp, "PEAddress: no open folder", TCL_STATIC);
12843 return(TCL_ERROR);
12845 else if((op = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){
12846 if(objc == 2){
12847 if(!strcmp(op, "safecheck")){
12848 if(peInitAddrbooks(interp, 1) != TCL_OK)
12849 return(TCL_ERROR);
12850 return(TCL_OK);
12852 else if(!strcmp(op, "books")){
12853 int i;
12856 * return the list of configured address books
12859 if(peInitAddrbooks(interp, 0) != TCL_OK)
12860 return(TCL_ERROR);
12862 for(i = 0; i < as.n_addrbk; i++){
12863 Tcl_Obj *objmv[4];
12865 objmv[0] = Tcl_NewIntObj(i);
12866 if(as.adrbks[i].abnick){
12867 objmv[1] = Tcl_NewStringObj(as.adrbks[i].abnick, -1);
12869 else {
12870 char buf[256];
12872 snprintf(buf, sizeof(buf), "Address book number %d", i + 1);
12873 objmv[1] = Tcl_NewStringObj(buf, -1);
12876 objmv[2] = Tcl_NewStringObj(as.adrbks[i].filename ? as.adrbks[i].filename : "", -1);
12878 objmv[3] = Tcl_NewIntObj(as.adrbks[i].access == ReadWrite);
12880 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
12881 Tcl_NewListObj(4, objmv));
12884 return(TCL_OK);
12887 else if(objc == 3){
12888 if(!strcmp(op, "parselist")){
12889 char *addrstr;
12890 ADDRESS *addrlist = NULL, *atmp, *anextp;
12891 static char *fakedomain = "@";
12893 if((addrstr = Tcl_GetStringFromObj(objv[2], NULL)) != NULL)
12894 addrstr = cpystr(addrstr); /* can't munge tcl copy */
12896 wps_global->c_client_error[0] = '\0';
12897 rfc822_parse_adrlist(&addrlist, addrstr,
12898 (F_ON(F_COMPOSE_REJECTS_UNQUAL, wps_global))
12899 ? fakedomain : wps_global->maildomain);
12901 fs_give((void **) &addrstr);
12902 if(wps_global->c_client_error[0]){
12903 Tcl_SetResult(interp, wps_global->c_client_error, TCL_STATIC);
12904 return(TCL_ERROR);
12907 for(atmp = addrlist; atmp; ){
12908 RFC822BUFFER rbuf;
12910 anextp = atmp->next;
12911 atmp->next = NULL;
12912 wtmp_20k_buf[0] = '\0';
12913 rbuf.f = dummy_soutr;
12914 rbuf.s = NULL;
12915 rbuf.beg = wtmp_20k_buf;
12916 rbuf.cur = wtmp_20k_buf;
12917 rbuf.end = wtmp_20k_buf+SIZEOF_20KBUF-1;
12918 rfc822_output_address_list(&rbuf, atmp, 0L, NULL);
12919 *rbuf.cur = '\0';
12920 Tcl_ListObjAppendElement(interp,
12921 Tcl_GetObjResult(interp),
12922 Tcl_NewStringObj(wtmp_20k_buf, -1));
12923 atmp = anextp;
12926 mail_free_address(&addrlist);
12927 return(TCL_OK);
12929 else if(!strcmp(op, "xlookup")){
12930 char *addrstr;
12931 ADDRESS *addrlist = NULL, *atmp, *anextp;
12932 static char *fakedomain = "@";
12934 if((addrstr = Tcl_GetStringFromObj(objv[2], NULL)) != NULL)
12935 addrstr = cpystr(addrstr); /* can't munge tcl copy */
12937 wps_global->c_client_error[0] = '\0';
12938 rfc822_parse_adrlist(&addrlist, addrstr,
12939 (F_ON(F_COMPOSE_REJECTS_UNQUAL, wps_global))
12940 ? fakedomain : wps_global->maildomain);
12942 fs_give((void **) &addrstr);
12943 if(wps_global->c_client_error[0]){
12944 Tcl_SetResult(interp, wps_global->c_client_error, TCL_STATIC);
12945 return(TCL_ERROR);
12948 for(atmp = addrlist; atmp; ){
12949 anextp = atmp->next;
12950 atmp->next = NULL;
12951 wtmp_20k_buf[0] = '\0';
12952 if(atmp->host){
12953 if(atmp->host[0] == '@'){
12954 /* leading ampersand means "missing-hostname" */
12956 else{
12957 RFC822BUFFER rbuf;
12959 rbuf.f = dummy_soutr;
12960 rbuf.s = NULL;
12961 rbuf.beg = wtmp_20k_buf;
12962 rbuf.cur = wtmp_20k_buf;
12963 rbuf.end = wtmp_20k_buf+SIZEOF_20KBUF-1;
12964 rfc822_output_address_list(&rbuf, atmp, 0L, NULL);
12965 *rbuf.cur = '\0';
12966 Tcl_ListObjAppendElement(interp,
12967 Tcl_GetObjResult(interp),
12968 Tcl_NewStringObj(wtmp_20k_buf, -1));
12970 } /* else group syntax, move on */
12972 atmp = anextp;
12975 mail_free_address(&addrlist);
12976 return(TCL_OK);
12978 else if(!strcmp(op, "format")){
12979 int i, booknum;
12980 char buf[256], *s;
12982 if(peInitAddrbooks(interp, 0) != TCL_OK)
12983 return(TCL_ERROR);
12988 if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK)
12989 for(i = 0; i < as.n_addrbk; i++)
12990 if(i == booknum){
12991 addrbook_new_disp_form(&as.adrbks[booknum], wps_global->VAR_ABOOK_FORMATS, booknum, NULL);
12993 for(i = 0; i < NFIELDS && as.adrbks[booknum].disp_form[i].type != Notused; i++){
12994 switch(as.adrbks[booknum].disp_form[i].type){
12995 case Nickname :
12996 s = "nick";
12997 break;
12998 case Fullname :
12999 s = "full";
13000 break;
13001 case Addr :
13002 s = "addr";
13003 break;
13004 case Filecopy :
13005 s = "fcc";
13006 break;
13007 case Comment :
13008 s = "comment";
13009 break;
13010 default :
13011 s = NULL;
13012 break;
13015 if(s){
13016 Tcl_Obj *objmv[2];
13018 objmv[0] = Tcl_NewStringObj(s, -1);
13019 objmv[1] = Tcl_NewIntObj((100 * as.adrbks[booknum].disp_form[i].width) / wps_global->ttyo->screen_cols);
13020 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
13021 Tcl_NewListObj(2, objmv));
13026 return(TCL_OK);
13029 snprintf(buf, sizeof(buf), "PEAddress list: unknown address book number \"%d\"", booknum);
13030 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13031 return(TCL_ERROR);
13033 else if(!strcmp(op, "list")){
13034 int i, j, k, n, booknum;
13035 char buf[256], *s;
13036 AdrBk_Entry *ae;
13037 Tcl_Obj *objev[NFIELDS + 1], *objhv[2];
13039 if(peInitAddrbooks(interp, 0) != TCL_OK)
13040 return(TCL_ERROR);
13045 if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK)
13046 for(i = 0; i < as.n_addrbk; i++)
13047 if(i == booknum){
13048 addrbook_new_disp_form(&as.adrbks[booknum], wps_global->VAR_ABOOK_FORMATS, booknum, NULL);
13050 for(i = 0;
13051 (ae = adrbk_get_ae(as.adrbks[booknum].address_book, i));
13052 i++){
13054 /* first member is type: Single, List or Lookup */
13055 switch(ae->tag){
13056 case Single :
13057 s = "single";
13058 break;
13059 case List :
13060 s = "list";
13061 break;
13062 default : /* not set!?! */
13063 continue;
13066 if(!ae->nickname)
13067 continue;
13069 objhv[0] = Tcl_NewStringObj(ae->nickname, -1);
13070 objhv[1] = Tcl_NewStringObj(s, -1);
13071 objev[n = 0] = Tcl_NewListObj(2, objhv);
13074 * set fields based on VAR_ABOOK_FORMATS
13077 for(j = 0; j < NFIELDS && as.adrbks[booknum].disp_form[j].type != Notused; j++){
13078 switch(as.adrbks[booknum].disp_form[j].type){
13079 case Nickname :
13080 objev[++n] = Tcl_NewStringObj(ae->nickname, -1);
13081 break;
13082 case Fullname :
13083 objev[++n] = Tcl_NewStringObj(ae->fullname, -1);
13084 break;
13085 case Addr :
13086 if(ae->tag == Single){
13087 objev[++n] = Tcl_NewStringObj(ae->addr.addr, -1);
13089 else{
13090 Tcl_Obj **objav;
13092 for(k = 0; ae->addr.list[k]; k++)
13095 objav = (Tcl_Obj **) fs_get(k * sizeof(Tcl_Obj *));
13096 for(k = 0; ae->addr.list[k]; k++)
13097 objav[k] = Tcl_NewStringObj(ae->addr.list[k], -1);
13099 objev[++n] = Tcl_NewListObj(k, objav);
13100 fs_give((void **) &objav);
13102 break;
13103 case Filecopy :
13104 objev[++n] = Tcl_NewStringObj(ae->fcc ? ae->fcc : "", -1);
13105 break;
13106 case Comment :
13107 objev[++n] = Tcl_NewStringObj(ae->extra ? ae->extra : "", -1);
13108 break;
13109 default :
13110 s = NULL;
13111 break;
13115 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
13116 Tcl_NewListObj(n + 1, objev));
13119 return(TCL_OK);
13122 snprintf(buf, sizeof(buf), "PEAddress list: unknown address book number \"%d\"", booknum);
13123 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13124 return(TCL_ERROR);
13127 else if(objc == 4){
13128 if(!strcmp(op, "verify")){
13130 * The object here is to check the following list of field values
13131 * to see that they are valid address list, expanding if necessary.
13132 * The first argument is the list of field values, with "to" being
13133 * first. The second arg is the current fcc value.
13135 * The return value is of the following form:
13137 * { {{errstr {{oldstr newstr {ldap-opts ...}} ...}} ...} newfcc}
13139 Tcl_Obj **objVal;
13140 char *addrstr, *newaddr = NULL, *error = NULL,
13141 *tstr1, *tstr2, *fcc, *newfcc = NULL;
13142 BuildTo toaddr;
13143 int rv, badadrs, i , numlistvals,
13144 numldapqueries = 0;
13145 Tcl_Obj *resObj = NULL, *secObj, *strObj, *adrObj, *res2Obj;
13146 #ifdef ENABLE_LDAP
13147 WPLDAPRES_S **tsl;
13149 wpldap_global->query_no++;
13150 if(wpldap_global->ldap_search_list){
13151 wpldap_global->ldap_search_list =
13152 free_wpldapres(wpldap_global->ldap_search_list);
13155 tsl = &(wpldap_global->ldap_search_list);
13156 #endif /* ENABLE_LDAP */
13158 if(Tcl_ListObjGetElements(interp, objv[2], &numlistvals,
13159 &objVal) == TCL_OK){
13160 if((fcc = Tcl_GetStringFromObj(objv[3], NULL)) == NULL)
13161 return TCL_ERROR;
13162 res2Obj = Tcl_NewListObj(0, NULL);
13163 for(i = 0; i < numlistvals; i++){
13164 size_t l;
13166 if((addrstr = Tcl_GetStringFromObj(objVal[i], NULL)) == NULL)
13167 return TCL_ERROR;
13169 addrstr = cpystr(addrstr); /* can't munge tcl copy */
13170 toaddr.type = Str;
13171 toaddr.arg.str = cpystr(addrstr);
13172 l = strlen(addrstr);
13173 badadrs = 0;
13174 resObj = Tcl_NewListObj(0, NULL);
13175 secObj = Tcl_NewListObj(0, NULL);
13176 for(tstr1 = addrstr; tstr1; tstr1 = tstr2){
13177 tstr2 = strqchr(tstr1, ',', 0, -1);
13178 if(tstr2)
13179 *tstr2 = '\0';
13181 strncpy(toaddr.arg.str, tstr1, l);
13182 toaddr.arg.str[l] = '\0';
13184 removing_leading_and_trailing_white_space(toaddr.arg.str);
13185 if(*toaddr.arg.str){
13186 if(i == 0 && tstr1 == addrstr)
13187 newfcc = cpystr(fcc);
13189 rv = our_build_address(toaddr, &newaddr, &error, &newfcc, NULL);
13191 if(rv == 0){
13192 strObj = Tcl_NewListObj(0, NULL);
13193 Tcl_ListObjAppendElement(interp, strObj,
13194 Tcl_NewStringObj(toaddr.arg.str, -1));
13195 Tcl_ListObjAppendElement(interp, strObj,
13196 Tcl_NewStringObj(newaddr,-1));
13197 /* append whether or not ldap stuff
13198 * was returned
13200 adrObj = Tcl_NewListObj(0,NULL);
13201 #ifdef ENABLE_LDAP
13202 if(*tsl) {
13203 LDAP_CHOOSE_S *tres;
13204 LDAP_SERV_RES_S *trl;
13205 LDAPMessage *e;
13206 ADDRESS *newadr;
13207 char *ret_to;
13209 tres = (LDAP_CHOOSE_S *)fs_get(sizeof(LDAP_CHOOSE_S));
13210 for(trl = (*tsl)->reslist; trl;
13211 trl = trl->next){
13212 for(e = ldap_first_entry(trl->ld,
13213 trl->res);
13214 e != NULL;
13215 e = ldap_next_entry(trl->ld, e)){
13216 tres->ld = trl->ld;
13217 tres->selected_entry = e;
13218 tres->info_used = trl->info_used;
13219 tres->serv = trl->serv;
13220 if((newadr = address_from_ldap(tres)) != NULL){
13221 if(newadr->mailbox && newadr->host){
13222 RFC822BUFFER rbuf;
13223 size_t len;
13225 len = est_size(newadr);
13226 ret_to = (char *)fs_get(len * sizeof(char));
13227 ret_to[0] = '\0';
13228 rbuf.f = dummy_soutr;
13229 rbuf.s = NULL;
13230 rbuf.beg = ret_to;
13231 rbuf.cur = ret_to;
13232 rbuf.end = ret_to+len-1;
13233 rfc822_output_address_list(&rbuf, newadr, 0L, NULL);
13234 *rbuf.cur = '\0';
13235 Tcl_ListObjAppendElement(interp,
13236 adrObj, Tcl_NewStringObj(ret_to, -1));
13237 fs_give((void **)&ret_to);
13239 mail_free_address(&newadr);
13243 fs_give((void **)&tres);
13244 numldapqueries++;
13245 tsl = &((*tsl)->next);
13247 #endif /* ENABLE_LDAP */
13248 Tcl_ListObjAppendElement(interp, strObj, adrObj);
13249 Tcl_ListObjAppendElement(interp, secObj, strObj);
13251 else {
13252 badadrs = 1;
13253 break;
13256 if(tstr2){
13257 *tstr2 = ',';
13258 tstr2++;
13261 resObj = Tcl_NewListObj(0, NULL);
13262 Tcl_ListObjAppendElement(interp, resObj,
13263 Tcl_NewStringObj(badadrs
13264 ? (error ? error : "Unknown")
13265 : "", -1));
13266 Tcl_ListObjAppendElement(interp, resObj, secObj);
13267 Tcl_ListObjAppendElement(interp, res2Obj, resObj);
13268 fs_give((void **) &addrstr);
13269 fs_give((void **) &toaddr.arg.str);
13271 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), res2Obj);
13272 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
13273 Tcl_NewStringObj(newfcc ? newfcc
13274 : (fcc ? fcc : ""), -1));
13275 if(newfcc) fs_give((void **)&newfcc);
13276 return(TCL_OK);
13278 return(TCL_ERROR);
13280 else if(!strcmp(op, "expand")){
13281 BuildTo toaddr;
13282 char *addrstr, *newaddr = NULL, *error = NULL, *fcc, *newfcc = NULL;
13283 int rv;
13286 * Return value will be of the form:
13287 * {"addrstr",
13288 * ldap-query-number,
13289 * "fcc"
13292 * ldap-query-number will be nonzero if
13293 * there is something interesting to display as a result
13294 * of an ldap query.
13298 * Given what looks like an rfc822 address line, parse the
13299 * contents and expand any tokens that look like they ought
13300 * to be.
13303 if((addrstr = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
13304 toaddr.type = Str;
13305 toaddr.arg.str = cpystr(addrstr); /* can't munge tcl copy */
13306 fcc = Tcl_GetStringFromObj(objv[3], NULL);
13307 #ifdef ENABLE_LDAP
13308 wpldap_global->query_no++;
13309 if(wpldap_global->ldap_search_list){
13310 wpldap_global->ldap_search_list =
13311 free_wpldapres(wpldap_global->ldap_search_list);
13313 #endif /* ENABLE_LDAP */
13314 newfcc = cpystr(fcc);
13315 rv = our_build_address(toaddr, &newaddr, &error, &newfcc, NULL);
13316 fs_give((void **) &toaddr.arg.str);
13317 if(rv == 0){
13318 #ifdef ENABLE_LDAP
13320 * c-client quotes results with spaces in them, so we'll go
13321 * through and unquote them.
13323 if(wpldap_global->ldap_search_list){
13324 WPLDAPRES_S *tres;
13325 char *tstr1, *tstr2;
13326 char *qstr1, *newnewaddr;
13327 int qstr1len;
13329 for(tres = wpldap_global->ldap_search_list;
13330 tres; tres = tres->next){
13331 if(strqchr(tres->str, ' ', 0, -1)){
13332 qstr1len = strlen(tres->str) + 3;
13333 qstr1 = (char *)fs_get(qstr1len*sizeof(char));
13334 snprintf(qstr1, qstr1len, "\"%.*s\"", qstr1len, tres->str);
13335 for(tstr1 = newaddr; tstr1; tstr1 = tstr2){
13336 tstr2 = strqchr(tstr1, ',', 0, -1);
13337 if(strncmp(qstr1, tstr1, tstr2 ? tstr2 - tstr1
13338 : strlen(tstr1)) == 0){
13339 size_t l;
13340 l = strlen(newaddr) + strlen(tres->str) + 2
13341 + (tstr2 ? strlen(tstr2) : 0);
13342 newnewaddr = (char *) fs_get(l * sizeof(char));
13343 snprintf(newnewaddr, l, "%.*s%s%s", (int) (tstr1 - newaddr),
13344 newaddr, tres->str, tstr2 ? tstr2 : "");
13345 fs_give((void **)&newaddr);
13346 newaddr = newnewaddr;
13347 break;
13349 if(tstr2)
13350 tstr2++;
13351 if(tstr2 && *tstr2 == ' ')
13352 tstr2++;
13354 if(qstr1)
13355 fs_give((void **) &qstr1);
13359 #endif /* ENABLE_LDAP */
13360 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
13361 Tcl_NewStringObj(newaddr, -1)) != TCL_OK)
13362 return(TCL_ERROR);
13363 #ifdef ENABLE_LDAP
13364 if(wpldap_global->ldap_search_list){
13365 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
13366 Tcl_NewIntObj(wpldap_global->query_no)) != TCL_OK)
13367 return(TCL_ERROR);
13369 else
13370 #endif /* ENABLE_LDAP */
13371 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
13372 Tcl_NewIntObj(0)) != TCL_OK)
13373 return(TCL_ERROR);
13374 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
13375 Tcl_NewStringObj(newfcc ? newfcc
13376 : (fcc ? fcc : ""), -1)) != TCL_OK)
13377 return(TCL_ERROR);
13378 if(newfcc) fs_give((void **)&newfcc);
13380 return(TCL_OK);
13382 else{
13383 Tcl_SetResult(interp, error ? error : "Indeterminate error", TCL_VOLATILE);
13384 if(newfcc) fs_give((void **)&newfcc);
13385 return(TCL_ERROR);
13389 else if(!strcmp(op, "complete")){
13391 * CMD: complete uid
13393 * Look for possible completions for
13394 * given query_string.
13396 * ARGS: <query_string> <uid>
13398 * Returns: candidate list: {nickname {personal mailbox}}
13400 char *query, *errstr;
13401 long uid;
13402 COMPLETE_S *completions, *cp;
13404 if(peInitAddrbooks(interp, 0) == TCL_OK){
13405 if((query = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){
13406 if(Tcl_GetLongFromObj(interp, objv[3], &uid) == TCL_OK){
13408 completions = adrbk_list_of_completions(query,
13409 wps_global->mail_stream,
13410 uid,
13411 #ifdef ENABLE_LDAP
13412 ((strlen(query) >= 5) ? ALC_INCLUDE_LDAP : 0) |
13413 #endif /* ENABLE_LDAP */
13416 if(completions){
13417 for(cp = completions; cp; cp = cp->next)
13418 peAppListF(interp, Tcl_GetObjResult(interp), "%s %s %s",
13419 cp->nickname ? cp->nickname : "",
13420 cp->full_address ? cp->full_address : "",
13421 cp->fcc ? cp->fcc : "");
13423 free_complete_s(&completions);
13425 else
13426 Tcl_SetResult(interp, "", TCL_STATIC);
13428 return(TCL_OK);
13430 else
13431 errstr = "PEAddress: Cannot read UID";
13433 else
13434 errstr = "PEAddress: Cannot get completion query";
13436 else
13437 errstr = "PEAddress: Address Book initialization failed";
13439 Tcl_SetResult(interp, errstr, TCL_STATIC);
13440 return(TCL_ERROR);
13443 else if(objc == 5){
13444 if(!strcmp(op, "entry")){
13445 int booknum, i, aindex;
13446 char *nick, *astr = NULL, *errstr = NULL, *fccstr = NULL, buf[128];
13447 AdrBk_Entry *ae;
13448 BuildTo bldto;
13450 if(peInitAddrbooks(interp, 0) != TCL_OK)
13451 return(TCL_ERROR);
13454 * Given an address book handle and nickname, return address
13456 if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK)
13457 for(i = 0; i < as.n_addrbk; i++)
13458 if(i == booknum){
13459 if((nick = Tcl_GetStringFromObj(objv[3], NULL)) == NULL){
13460 Tcl_SetResult(interp, "PEAddress list: Can't get nickname", TCL_STATIC);
13461 return(TCL_ERROR);
13463 if(Tcl_GetIntFromObj(interp, objv[4], &aindex) != TCL_OK
13464 || (*nick == '\0' && aindex < 0)){
13465 Tcl_SetResult(interp, "PEAddress list: Can't get aindex", TCL_STATIC);
13466 return(TCL_ERROR);
13468 if((*nick)
13469 ? (ae = adrbk_lookup_by_nick(as.adrbks[booknum].address_book, nick, NULL))
13470 : (ae = adrbk_get_ae(as.adrbks[booknum].address_book, aindex))){
13471 bldto.type = Abe;
13472 bldto.arg.abe = ae;
13474 (void) our_build_address(bldto, &astr, &errstr, &fccstr, NULL);
13476 if(errstr){
13477 if(astr)
13478 fs_give((void **) &astr);
13480 Tcl_SetResult(interp, errstr, TCL_VOLATILE);
13481 return(TCL_ERROR);
13484 if(astr){
13485 char *p;
13486 int l;
13488 l = (4*strlen(astr) + 1) * sizeof(char);
13489 p = (char *) fs_get(l);
13490 if(rfc1522_decode_to_utf8((unsigned char *) p, l, astr) == (unsigned char *) p){
13491 fs_give((void **) &astr);
13492 astr = p;
13494 else
13495 fs_give((void **)&p);
13499 if(astr){
13500 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
13501 Tcl_NewStringObj(astr, -1));
13502 fs_give((void **) &astr);
13504 if(fccstr){
13505 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
13506 Tcl_NewStringObj(*fccstr ? fccstr : "\"\"", -1));
13507 fs_give((void **) &fccstr);
13509 else
13510 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
13511 Tcl_NewStringObj("", -1));
13513 else
13514 Tcl_SetResult(interp, "", TCL_STATIC);
13516 return(TCL_OK);
13519 snprintf(buf, sizeof(buf), "PEAddress list: unknown address book ID %d", booknum);
13520 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13521 return(TCL_ERROR);
13523 else if(!strcmp(op, "fullentry")){
13524 int booknum, j, aindex;
13525 char *nick;
13526 AdrBk_Entry *ae;
13527 Tcl_Obj *resObj;
13529 if(peInitAddrbooks(interp, 0) != TCL_OK)
13530 return(TCL_ERROR);
13533 * Given an address book handle and nickname, return
13534 * nickname, fullname, address(es), fcc, and comments
13536 if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK){
13537 if(booknum >= 0 && booknum < as.n_addrbk){
13538 if((nick = Tcl_GetStringFromObj(objv[3], NULL)) == NULL)
13539 return(TCL_ERROR);
13540 if(Tcl_GetIntFromObj(interp, objv[4], &aindex) != TCL_OK
13541 || (*nick == '\0' && aindex < 0))
13542 return(TCL_ERROR);
13543 if((*nick)
13544 ? (ae = adrbk_lookup_by_nick(as.adrbks[booknum].address_book, nick, NULL))
13545 : (ae = adrbk_get_ae(as.adrbks[booknum].address_book, aindex))){
13546 Tcl_ListObjAppendElement(interp,
13547 Tcl_GetObjResult(interp),
13548 Tcl_NewStringObj(ae->nickname ? ae->nickname : "", -1));
13549 Tcl_ListObjAppendElement(interp,
13550 Tcl_GetObjResult(interp),
13551 Tcl_NewStringObj(ae->fullname ? ae->fullname : "", -1));
13552 resObj = Tcl_NewListObj(0,NULL);
13553 if(ae->tag == Single)
13554 Tcl_ListObjAppendElement(interp,
13555 resObj,
13556 Tcl_NewStringObj(ae->addr.addr ? ae->addr.addr : "", -1));
13557 else {
13558 for(j = 0; ae->addr.list[j]; j++)
13559 Tcl_ListObjAppendElement(interp, resObj,
13560 Tcl_NewStringObj(ae->addr.list[j] ? ae->addr.list[j] : "", -1));
13562 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), resObj);
13563 Tcl_ListObjAppendElement(interp,
13564 Tcl_GetObjResult(interp),
13565 Tcl_NewStringObj(ae->fcc ? ae->fcc : "", -1));
13566 Tcl_ListObjAppendElement(interp,
13567 Tcl_GetObjResult(interp),
13568 Tcl_NewStringObj(ae->extra ? ae->extra : "", -1));
13569 return(TCL_OK);
13573 return(TCL_ERROR);
13575 else if(!strcmp(op, "delete")){
13576 char *nick, buf[256];
13577 int booknum, aindex;
13578 adrbk_cntr_t old_entry;
13579 AdrBk *ab;
13580 if(peInitAddrbooks(interp, 0) != TCL_OK){
13581 snprintf(buf, sizeof(buf), "PEAddress delete: couldn't init addressbooks");
13582 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13583 return(TCL_ERROR);
13585 if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK){
13586 nick = Tcl_GetStringFromObj(objv[3], NULL);
13587 removing_leading_and_trailing_white_space(nick);
13589 else
13590 return(TCL_ERROR);
13591 if(booknum >= 0 && booknum < as.n_addrbk) {
13592 if(as.adrbks[booknum].access != ReadWrite) return TCL_ERROR;
13593 ab = as.adrbks[booknum].address_book;
13595 else{
13596 snprintf(buf, sizeof(buf), "PEAddress delete: Book number out of range");
13597 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13598 return(TCL_ERROR);
13600 if((Tcl_GetIntFromObj(interp, objv[4], &aindex) != TCL_OK)
13601 || (*nick == '\0' && aindex < 0))
13602 return(TCL_ERROR);
13603 adrbk_check_validity(ab, 1L);
13604 if(ab->flags & FILE_OUTOFDATE ||
13605 (ab->rd && ab->rd->flags & REM_OUTOFDATE)){
13606 Tcl_SetResult(interp,
13607 "Address book out of sync. Cannot update at this moment",
13608 TCL_VOLATILE);
13609 return(TCL_ERROR);
13611 if(!nick){
13612 snprintf(buf, sizeof(buf), "PEAddress delete: No nickname");
13613 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13614 return(TCL_ERROR);
13616 if((*nick)
13617 ? (!adrbk_lookup_by_nick(ab, nick, &old_entry))
13618 : ((old_entry = (adrbk_cntr_t)aindex) == -1)){
13619 snprintf(buf, sizeof(buf), "PEAddress delete: Nickname \"%.128s\" not found", nick);
13620 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13621 return(TCL_ERROR);
13623 if(adrbk_delete(ab, old_entry, 0, 0, 1, 1)){
13624 snprintf(buf, sizeof(buf), "PEAddress delete: Couldn't delete addressbook entry");
13625 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13626 return(TCL_ERROR);
13628 return(TCL_OK);
13631 else if((objc == 10 || objc == 11) && !strcmp(op, "edit")){
13632 if(!strcmp(op, "edit")){
13633 int booknum, adri, add, rv, aindex;
13634 char *nick, *fn, *fcc, *comment, *addrfield,
13635 buf[256], **addrs, *orignick = NULL;
13636 AdrBk_Entry *ae = NULL;
13637 AdrBk *ab;
13638 adrbk_cntr_t old_entry = NO_NEXT, new_entry;
13639 Tag tag;
13640 ADDRESS *adr = NULL;
13643 if(peInitAddrbooks(interp, 0) != TCL_OK)
13644 return(TCL_ERROR);
13645 if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK){
13646 if(as.adrbks[booknum].access != ReadWrite) return TCL_ERROR;
13647 nick = Tcl_GetStringFromObj(objv[3], NULL);
13648 removing_leading_and_trailing_white_space(nick);
13649 if(Tcl_GetIntFromObj(interp, objv[4], &aindex) != TCL_OK){
13650 Tcl_SetResult(interp, "No Address Handle", TCL_VOLATILE);
13651 return(TCL_ERROR);
13653 fn = Tcl_GetStringFromObj(objv[5], NULL);
13654 removing_leading_and_trailing_white_space(fn);
13655 if(!*fn) fn = NULL;
13656 addrfield = Tcl_GetStringFromObj(objv[6], NULL);
13657 removing_leading_and_trailing_white_space(addrfield);
13658 if(!*addrfield) addrfield = NULL;
13660 if(Tcl_ListObjGetElements(interp, objv[7], &numlistvals, &objVal) != TCL_OK)
13661 return(TCL_ERROR);
13663 fcc = Tcl_GetStringFromObj(objv[7], NULL);
13664 removing_leading_and_trailing_white_space(fcc);
13665 if(!*fcc) fcc = NULL;
13666 comment = Tcl_GetStringFromObj(objv[8], NULL);
13667 removing_leading_and_trailing_white_space(comment);
13668 if(!*comment) comment = NULL;
13669 if(Tcl_GetIntFromObj(interp, objv[9], &add) != TCL_OK)
13670 return(TCL_ERROR);
13671 if(objc == 11) {
13673 * if objc == 11 then that means that they changed the
13674 * value of nick to something else, and this one is the
13675 * original nick
13677 orignick = Tcl_GetStringFromObj(objv[10], NULL);
13678 removing_leading_and_trailing_white_space(orignick);
13680 if((addrs = parse_addrlist(addrfield)) != NULL){
13681 int tbuflen = strlen(addrfield);
13682 char *tbuf;
13683 if(!(tbuf = (char *) fs_get(sizeof(char) * (tbuflen+128)))){
13684 Tcl_SetResult(interp, "malloc error", TCL_VOLATILE);
13685 fs_give((void **) &addrs);
13686 return(TCL_ERROR);
13688 for(adri = 0; addrs[adri]; adri++){
13689 if(*(addrs[adri])){
13690 wps_global->c_client_error[0] = '\0';
13691 strncpy(tbuf, addrs[adri], tbuflen+128);
13692 tbuf[tbuflen+128-1] = '\0';
13693 rfc822_parse_adrlist(&adr, tbuf, "@");
13694 if(adr) mail_free_address(&adr);
13695 adr = NULL;
13696 if(wps_global->c_client_error[0]){
13697 snprintf(buf, sizeof(buf),"Problem with address %.10s%s: %s",
13698 addrs[adri], strlen(addrs[adri]) > 10 ?
13699 "..." : "", wps_global->c_client_error);
13700 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13701 if(tbuf)
13702 fs_give((void **) &tbuf);
13703 fs_give((void **) &addrs);
13704 return(TCL_ERROR);
13708 if(tbuf) fs_give((void **)&tbuf);
13710 else adri = 0;
13712 /* addrs[adri] = NULL; */
13714 if(adri > 1) tag = List;
13715 else tag = Single;
13717 if(booknum >= 0 && booknum < as.n_addrbk) {
13718 ab = as.adrbks[booknum].address_book;
13720 else{
13721 if(addrs)
13722 fs_give((void **) &addrs);
13723 return(TCL_ERROR);
13725 adrbk_check_validity(ab, 1L);
13726 if(ab->flags & FILE_OUTOFDATE ||
13727 (ab->rd && ab->rd->flags & REM_OUTOFDATE)){
13728 Tcl_SetResult(interp,
13729 "Address book out of sync. Cannot update at this moment",
13730 TCL_VOLATILE);
13731 return(TCL_ERROR);
13733 if(aindex >= 0){
13734 ae = adrbk_get_ae(as.adrbks[booknum].address_book, aindex);
13735 if(ae){
13736 old_entry = (adrbk_cntr_t) aindex;
13738 else{
13739 Tcl_SetResult(interp, "No Address Handle!", TCL_VOLATILE);
13740 return(TCL_ERROR);
13743 else if(nick && *nick && adrbk_lookup_by_nick(ab, nick, NULL)){
13744 snprintf(buf, sizeof(buf), "Entry with nickname %.128s already exists.",
13745 nick);
13746 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13747 if(addrs)
13748 fs_give((void **) &addrs);
13749 return(TCL_ERROR);
13751 if(ae &&
13752 ((tag == List && ae->tag == Single) ||
13753 (tag == Single && ae->tag == List))){
13754 if(adrbk_delete(ab, old_entry, 0,0,1,0)){
13755 snprintf(buf, sizeof(buf), "Problem updating from %s to %s.",
13756 ae->tag == Single ? "Single" : "List",
13757 tag == List ? "List" : "Single");
13758 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13759 if(addrs)
13760 fs_give((void **) &addrs);
13761 return(TCL_ERROR);
13763 old_entry = NO_NEXT;
13765 if((rv = adrbk_add(ab, old_entry,
13766 nick ? nick : "",
13767 fn ? fn : "",
13768 tag == List ? (char *)addrs :
13769 (addrs && *addrs) ? *addrs : "",
13770 fcc ? fcc : "",
13771 comment ? comment : "",
13772 tag, &new_entry, NULL, 0, 1,
13773 tag == List ? 0 : 1)) != 0){
13774 snprintf(buf, sizeof(buf), "Couldn't add entry! rv=%d.", rv);
13775 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13776 if(addrs)
13777 fs_give((void **) &addrs);
13778 return(TCL_ERROR);
13780 if(tag == List) {
13781 adrbk_listdel_all(ab, new_entry);
13782 adrbk_nlistadd(ab, new_entry, NULL, NULL, addrs, 0, 1, 1);
13784 return(TCL_OK);
13786 snprintf(buf, sizeof(buf), "Unknown address book ID %d", booknum);
13787 Tcl_SetResult(interp, buf, TCL_VOLATILE);
13788 return(TCL_ERROR);
13793 Tcl_SetResult(interp, "PEAddress: unrecognized command", TCL_STATIC);
13794 return(TCL_ERROR);
13799 peInitAddrbooks(Tcl_Interp *interp, int safe)
13801 if(wps_global->remote_abook_validity > 0)
13802 (void)adrbk_check_and_fix_all(safe, 0, 0);
13804 if(!init_addrbooks(NoDisplay, 1, 1, 0)){
13805 Tcl_SetResult(interp, "No Address Book Configured", TCL_STATIC);
13806 return(TCL_ERROR);
13809 return(TCL_OK);
13815 peRuleStatVal(char *str, int *n)
13817 if(!str)
13818 return(1);
13820 if(!strcmp(str, "either"))
13821 *n = PAT_STAT_EITHER;
13822 else if(!strcmp(str, "yes"))
13823 *n = PAT_STAT_YES;
13824 else if(!strcmp(str, "no"))
13825 *n = PAT_STAT_NO;
13826 else
13827 return 1;
13829 return 0;
13833 #define RS_RULE_EDIT 0x0001
13834 #define RS_RULE_ADD 0x0002
13835 #define RS_RULE_DELETE 0x0004
13836 #define RS_RULE_SHUFFUP 0x0008
13837 #define RS_RULE_SHUFFDOWN 0x0010
13838 #define RS_RULE_GETPAT 0x0100
13839 #define RS_RULE_FINDPAT 0x0200
13842 peRuleSet(Tcl_Interp *interp, Tcl_Obj **objv)
13844 char *rule, *patvar, *patval, *actvar, *actval, *tstr, *ruleaction;
13845 int rno, nPat, nPatEmnt, nAct, nActEmnt, i, rv = 0;
13846 Tcl_Obj **objPat, **objPatEmnt, **objAct, **objActEmnt;
13847 long rflags = PAT_USE_CHANGED, aflags = 0;
13848 PAT_STATE pstate;
13849 PAT_S *pat, *new_pat;
13851 if(!(rule = Tcl_GetStringFromObj(objv[0], NULL)))
13852 return(TCL_ERROR);
13854 if(!(ruleaction = Tcl_GetStringFromObj(objv[1], NULL)))
13855 return(TCL_ERROR);
13857 if(Tcl_GetIntFromObj(interp, objv[2], &rno) == TCL_ERROR)
13858 return(TCL_ERROR);
13860 if(!(strcmp(rule, "filter")))
13861 rflags |= ROLE_DO_FILTER;
13862 else if(!(strcmp(rule, "score")))
13863 rflags |= ROLE_DO_SCORES;
13864 else if(!(strcmp(rule, "indexcolor")))
13865 rflags |= ROLE_DO_INCOLS;
13866 else
13867 return(TCL_ERROR);
13869 if(!(strcmp(ruleaction, "edit"))){
13870 aflags |= RS_RULE_EDIT;
13871 aflags |= RS_RULE_GETPAT;
13872 aflags |= RS_RULE_FINDPAT;
13874 else if(!(strcmp(ruleaction, "add"))){
13875 aflags |= RS_RULE_ADD;
13876 aflags |= RS_RULE_GETPAT;
13878 else if(!(strcmp(ruleaction, "delete"))){
13879 aflags |= RS_RULE_DELETE;
13880 aflags |= RS_RULE_FINDPAT;
13882 else if(!(strcmp(ruleaction, "shuffup"))){
13883 aflags |= RS_RULE_SHUFFUP;
13884 aflags |= RS_RULE_FINDPAT;
13886 else if(!(strcmp(ruleaction, "shuffdown"))){
13887 aflags |= RS_RULE_SHUFFDOWN;
13888 aflags |= RS_RULE_FINDPAT;
13890 else return(TCL_ERROR);
13892 if(aflags & RS_RULE_FINDPAT){
13893 if(any_patterns(rflags, &pstate)){
13894 for(pat = first_pattern(&pstate), i = 0;
13895 pat && i != rno;
13896 pat = next_pattern(&pstate), i++);
13897 if(i != rno) return(TCL_ERROR);
13900 if(aflags & RS_RULE_GETPAT){
13901 int tcl_error = 0;
13903 Tcl_ListObjGetElements(interp, objv[3], &nPat, &objPat);
13904 Tcl_ListObjGetElements(interp, objv[4], &nAct, &objAct);
13906 new_pat = (PAT_S *)fs_get(sizeof(PAT_S));
13907 memset(new_pat, 0, sizeof(PAT_S));
13908 new_pat->patgrp = (PATGRP_S *)fs_get(sizeof(PATGRP_S));
13909 memset(new_pat->patgrp, 0, sizeof(PATGRP_S));
13910 new_pat->action = (ACTION_S *)fs_get(sizeof(ACTION_S));
13911 memset(new_pat->action, 0, sizeof(ACTION_S));
13913 /* Set up the pattern group */
13914 for(i = 0; i < nPat; i++){
13915 Tcl_ListObjGetElements(interp, objPat[i], &nPatEmnt, &objPatEmnt);
13916 if(nPatEmnt != 2) return(TCL_ERROR);
13917 patvar = Tcl_GetStringFromObj(objPatEmnt[0], NULL);
13918 patval = Tcl_GetStringFromObj(objPatEmnt[1], NULL);
13919 if(!patvar || !patval) return(TCL_ERROR);
13921 tstr = NULL;
13922 if(*patval){
13923 tstr = cpystr(patval);
13924 removing_leading_and_trailing_white_space(tstr);
13925 if(!(*tstr))
13926 fs_give((void **) &tstr);
13929 if(!(strcmp(patvar, "nickname"))){
13930 new_pat->patgrp->nick = tstr;
13931 tstr = NULL;
13933 else if(!(strcmp(patvar, "comment"))){
13934 new_pat->patgrp->comment = tstr;
13935 tstr = NULL;
13937 else if(!(strcmp(patvar, "to"))){
13938 new_pat->patgrp->to = string_to_pattern(tstr);
13940 else if(!(strcmp(patvar, "from"))){
13941 new_pat->patgrp->from = string_to_pattern(tstr);
13943 else if(!(strcmp(patvar, "sender"))){
13944 new_pat->patgrp->sender = string_to_pattern(tstr);
13946 else if(!(strcmp(patvar, "cc"))){
13947 new_pat->patgrp->cc = string_to_pattern(tstr);
13949 else if(!(strcmp(patvar, "recip"))){
13950 new_pat->patgrp->recip = string_to_pattern(tstr);
13952 else if(!(strcmp(patvar, "partic"))){
13953 new_pat->patgrp->partic = string_to_pattern(tstr);
13955 else if(!(strcmp(patvar, "news"))){
13956 new_pat->patgrp->news = string_to_pattern(tstr);
13958 else if(!(strcmp(patvar, "subj"))){
13959 new_pat->patgrp->subj = string_to_pattern(tstr);
13961 else if(!(strcmp(patvar, "bodytext"))){
13962 new_pat->patgrp->bodytext = string_to_pattern(tstr);
13964 else if(!(strcmp(patvar, "alltext"))){
13965 new_pat->patgrp->alltext = string_to_pattern(tstr);
13967 else if(!(strcmp(patvar, "keyword"))){
13968 new_pat->patgrp->keyword = string_to_pattern(tstr);
13970 else if(!(strcmp(patvar, "charset"))){
13971 new_pat->patgrp->charsets = string_to_pattern(tstr);
13973 else if(!(strcmp(patvar, "ftype"))){
13974 if(!tstr) return(TCL_ERROR);
13976 if(!(strcmp(tstr, "any")))
13977 new_pat->patgrp->fldr_type = FLDR_ANY;
13978 else if(!(strcmp(tstr, "news")))
13979 new_pat->patgrp->fldr_type = FLDR_NEWS;
13980 else if(!(strcmp(tstr, "email")))
13981 new_pat->patgrp->fldr_type = FLDR_EMAIL;
13982 else if(!(strcmp(tstr, "specific")))
13983 new_pat->patgrp->fldr_type = FLDR_SPECIFIC;
13984 else{
13985 free_pat(&new_pat);
13986 return(TCL_ERROR);
13989 else if(!(strcmp(patvar, "folder"))){
13990 new_pat->patgrp->folder = string_to_pattern(tstr);
13992 else if(!(strcmp(patvar, "stat_new"))){
13993 if(peRuleStatVal(tstr, &new_pat->patgrp->stat_new)){
13994 free_pat(&new_pat);
13995 tcl_error++;
13998 else if(!(strcmp(patvar, "stat_rec"))){
13999 if(peRuleStatVal(tstr, &new_pat->patgrp->stat_rec)){
14000 free_pat(&new_pat);
14001 tcl_error++;
14004 else if(!(strcmp(patvar, "stat_del"))){
14005 if(peRuleStatVal(tstr, &new_pat->patgrp->stat_del)){
14006 free_pat(&new_pat);
14007 tcl_error++;
14010 else if(!(strcmp(patvar, "stat_imp"))){
14011 if(peRuleStatVal(tstr, &new_pat->patgrp->stat_imp)){
14012 free_pat(&new_pat);
14013 tcl_error++;
14016 else if(!(strcmp(patvar, "stat_ans"))){
14017 if(peRuleStatVal(tstr, &new_pat->patgrp->stat_ans)){
14018 free_pat(&new_pat);
14019 tcl_error++;
14022 else if(!(strcmp(patvar, "stat_8bitsubj"))){
14023 if(peRuleStatVal(tstr, &new_pat->patgrp->stat_8bitsubj)){
14024 free_pat(&new_pat);
14025 tcl_error++;
14028 else if(!(strcmp(patvar, "stat_bom"))){
14029 if(peRuleStatVal(tstr, &new_pat->patgrp->stat_bom)){
14030 free_pat(&new_pat);
14031 tcl_error++;
14034 else if(!(strcmp(patvar, "stat_boy"))){
14035 if(peRuleStatVal(tstr, &new_pat->patgrp->stat_boy)){
14036 free_pat(&new_pat);
14037 tcl_error++;
14040 else if(!(strcmp(patvar, "age"))){
14041 new_pat->patgrp->age = parse_intvl(tstr);
14043 else if(!(strcmp(patvar, "size"))){
14044 new_pat->patgrp->size = parse_intvl(tstr);
14046 else if(!(strcmp(patvar, "score"))){
14047 new_pat->patgrp->score = parse_intvl(tstr);
14049 else if(!(strcmp(patvar, "addrbook"))){
14050 if(tstr){
14051 if(!strcmp(tstr, "either"))
14052 new_pat->patgrp->inabook = IAB_EITHER;
14053 else if(!strcmp(tstr, "yes"))
14054 new_pat->patgrp->inabook = IAB_YES;
14055 else if(!strcmp(tstr, "no"))
14056 new_pat->patgrp->inabook = IAB_NO;
14057 else if(!strcmp(tstr, "yesspecific"))
14058 new_pat->patgrp->inabook = IAB_SPEC_YES;
14059 else if(!strcmp(tstr, "nospecific"))
14060 new_pat->patgrp->inabook = IAB_SPEC_NO;
14061 else
14062 tcl_error++;
14064 else
14065 tcl_error++;
14067 if(tcl_error)
14068 free_pat(&new_pat);
14070 else if(!(strcmp(patvar, "specificabook"))){
14071 new_pat->patgrp->abooks = string_to_pattern(tstr);
14073 else if(!(strcmp(patvar, "headers"))){
14074 ARBHDR_S **ahp;
14075 int nHdrList, nHdrPair, n;
14076 Tcl_Obj **objHdrList, **objHdrPair;
14078 Tcl_ListObjGetElements(interp, objPatEmnt[1], &nHdrList, &objHdrList);
14080 for(ahp = &new_pat->patgrp->arbhdr; *ahp; ahp = &(*ahp)->next)
14083 for (n = 0; n < nHdrList; n++){
14084 char *hdrfld;
14085 char *hdrval;
14087 Tcl_ListObjGetElements(interp, objHdrList[n], &nHdrPair, &objHdrPair);
14088 if(nHdrPair != 2)
14089 continue;
14091 hdrfld = Tcl_GetStringFromObj(objHdrPair[0], NULL);
14092 hdrval = Tcl_GetStringFromObj(objHdrPair[1], NULL);
14094 if(hdrfld){
14095 *ahp = (ARBHDR_S *) fs_get(sizeof(ARBHDR_S));
14096 memset(*ahp, 0, sizeof(ARBHDR_S));
14098 (*ahp)->field = cpystr(hdrfld);
14099 if(hdrval){
14100 (*ahp)->p = string_to_pattern(hdrval);
14102 else
14103 (*ahp)->isemptyval = 1;
14105 ahp = &(*ahp)->next;
14109 else{
14110 free_pat(&new_pat);
14111 tcl_error++;
14114 if(tstr)
14115 fs_give((void **) &tstr);
14117 if(tcl_error)
14118 return(TCL_ERROR);
14121 if((new_pat->patgrp->inabook & (IAB_SPEC_YES | IAB_SPEC_NO)) == 0
14122 && new_pat->patgrp->abooks)
14123 free_pattern(&new_pat->patgrp->abooks);
14125 if(new_pat->patgrp->fldr_type != FLDR_SPECIFIC && new_pat->patgrp->folder)
14126 free_pattern(&new_pat->patgrp->folder);
14128 /* set up the action */
14129 if(!(strcmp(rule, "filter")))
14130 new_pat->action->is_a_filter = 1;
14131 else if(!(strcmp(rule, "role")))
14132 new_pat->action->is_a_role = 1;
14133 else if(!(strcmp(rule, "score")))
14134 new_pat->action->is_a_score = 1;
14135 else if(!(strcmp(rule, "indexcolor")))
14136 new_pat->action->is_a_incol = 1;
14137 else{
14138 free_pat(&new_pat);
14139 return(TCL_ERROR);
14142 for(i = 0; i < nAct; i++){
14143 Tcl_ListObjGetElements(interp, objAct[i], &nActEmnt, &objActEmnt);
14144 if(nActEmnt !=2){
14145 free_pat(&new_pat);
14146 return(TCL_ERROR);
14149 actvar = Tcl_GetStringFromObj(objActEmnt[0], NULL);
14150 actval = Tcl_GetStringFromObj(objActEmnt[1], NULL);
14151 if(!actvar || !actval){
14152 free_pat(&new_pat);
14153 return(TCL_ERROR);
14156 if(new_pat->action->is_a_filter && !(strcmp(actvar, "action"))){
14157 if(!strcmp(actval, "delete"))
14158 new_pat->action->kill = 1;
14159 else if(!strcmp(actval, "move"))
14160 new_pat->action->kill = 0;
14161 else{
14162 free_pat(&new_pat);
14163 return(TCL_ERROR);
14166 else if(new_pat->action->is_a_filter && !(strcmp(actvar, "folder"))){
14167 tstr = cpystr(actval);
14168 removing_leading_and_trailing_white_space(tstr);
14169 if(!(*tstr)) fs_give((void **)&tstr);
14170 new_pat->action->folder = string_to_pattern(tstr);
14171 if(tstr) fs_give((void **)&tstr);
14173 else if(new_pat->action->is_a_filter && !(strcmp(actvar, "moind"))){
14174 if(!strcmp(actval, "1"))
14175 new_pat->action->move_only_if_not_deleted = 1;
14176 else if(!strcmp(actval, "0"))
14177 new_pat->action->move_only_if_not_deleted = 0;
14178 else{
14179 free_pat(&new_pat);
14180 return(TCL_ERROR);
14183 else if(new_pat->action->is_a_incol && !(strcmp(actvar, "fg"))){
14184 char asciicolor[256];
14186 if(ascii_colorstr(asciicolor, actval) == 0) {
14187 if(!new_pat->action->incol){
14188 new_pat->action->incol = new_color_pair(asciicolor,NULL);
14190 else
14191 snprintf(new_pat->action->incol->fg,
14192 sizeof(new_pat->action->incol->fg), "%s", asciicolor);
14195 else if(new_pat->action->is_a_incol && !(strcmp(actvar, "bg"))){
14196 char asciicolor[256];
14198 if(ascii_colorstr(asciicolor, actval) == 0) {
14199 if(!new_pat->action->incol){
14200 new_pat->action->incol = new_color_pair(NULL, asciicolor);
14202 else
14203 snprintf(new_pat->action->incol->bg,
14204 sizeof(new_pat->action->incol->bg), "%s", asciicolor);
14207 else if(new_pat->action->is_a_score && !(strcmp(actvar, "scoreval"))){
14208 long scoreval = (long) atoi(actval);
14210 if(scoreval >= SCORE_MIN && scoreval <= SCORE_MAX)
14211 new_pat->action->scoreval = scoreval;
14213 else if(new_pat->action->is_a_score && !(strcmp(actvar, "scorehdr"))){
14214 HEADER_TOK_S *hdrtok;
14216 if((hdrtok = stringform_to_hdrtok(actval)) != NULL)
14217 new_pat->action->scorevalhdrtok = hdrtok;
14219 else{
14220 free_pat(&new_pat);
14221 return(TCL_ERROR);
14225 if(new_pat->action->is_a_filter && new_pat->action->kill && new_pat->action->folder)
14226 fs_give((void **)&new_pat->action->folder);
14227 else if(new_pat->action->is_a_filter && new_pat->action->kill == 0 && new_pat->action->folder == 0){
14228 free_pat(&new_pat);
14229 Tcl_SetResult(interp, "No folder set for Move", TCL_VOLATILE);
14230 return(TCL_OK);
14234 if(aflags & RS_RULE_EDIT)
14235 rv = edit_pattern(new_pat, rno, rflags);
14236 else if(aflags & RS_RULE_ADD)
14237 rv = add_pattern(new_pat, rflags);
14238 else if(aflags & RS_RULE_DELETE)
14239 rv = delete_pattern(rno, rflags);
14240 else if(aflags & RS_RULE_SHUFFUP)
14241 rv = shuffle_pattern(rno, 1, rflags);
14242 else if(aflags & RS_RULE_SHUFFDOWN)
14243 rv = shuffle_pattern(rno, -1, rflags);
14244 else
14245 rv = 1;
14247 return(rv ? TCL_ERROR : TCL_OK);
14251 #if 0
14252 ADDRESS *
14253 peAEToAddress(AdrBk_Entry *ae)
14255 char *list, *l1, *l2;
14256 int length;
14257 BuildTo bldto;
14258 ADDRESS *addr = NULL;
14260 if(ae->tag == List){
14261 length = 0;
14262 for(l2 = ae->addr.list; *l2; l2++)
14263 length += (strlen(*l2) + 1);
14265 list = (char *) fs_get(length + 1);
14266 list[0] = '\0';
14267 l1 = list;
14268 for(l2 = ae->addr.list; *l2; l2++){
14269 if(l1 != list && l1-list < length+1)
14270 *l1++ = ',';
14272 strncpy(l1, *l2, length+1-(l1-list));
14273 l1 += strlen(l1);
14276 list[length] = '\0';
14278 bldto.type = Str;
14279 bldto.arg.str = list;
14280 adr2 = expand_address(bldto, userdomain, localdomain,
14281 loop_detected, fcc, did_set,
14282 lcc, error, 1, simple_verify,
14283 mangled);
14285 fs_give((void **) &list);
14287 else if(ae->tag == Single){
14288 if(strucmp(ae->addr.addr, a->mailbox)){
14289 bldto.type = Str;
14290 bldto.arg.str = ae->addr.addr;
14291 adr2 = expand_address(bldto, userdomain,
14292 localdomain, loop_detected,
14293 fcc, did_set, lcc,
14294 error, 1, simple_verify,
14295 mangled);
14297 else{
14299 * A loop within plain single entry is ignored.
14300 * Set up so later code thinks we expanded.
14302 adr2 = mail_newaddr();
14303 adr2->mailbox = cpystr(ae->addr.addr);
14304 adr2->host = cpystr(userdomain);
14305 adr2->adl = cpystr(a->adl);
14310 * Personal names: If the expanded address has a personal
14311 * name and the address book entry is a list with a fullname,
14312 * tack the full name from the address book on in front.
14313 * This mainly occurs with a distribution list where the
14314 * list has a full name, and the first person in the list also
14315 * has a full name.
14317 * This algorithm doesn't work very well if lists are
14318 * included within lists, but it's not clear what would
14319 * be better.
14321 if(ae->fullname && ae->fullname[0]){
14322 if(adr2->personal && adr2->personal[0]){
14323 if(ae->tag == List){
14324 /* combine list name and existing name */
14325 char *name;
14327 if(!simple_verify){
14328 size_t l;
14329 l = strlen(adr2->personal) + strlen(ae->fullname) + 4;
14330 name = (char *)fs_get((l+1) * sizeof(char));
14331 snprintf(name, l+1, "%s -- %s", ae->fullname,
14332 adr2->personal);
14333 fs_give((void **)&adr2->personal);
14334 adr2->personal = name;
14337 else{
14338 /* replace with nickname fullname */
14339 fs_give((void **)&adr2->personal);
14340 adr2->personal = adrbk_formatname(ae->fullname,
14341 NULL, NULL);
14344 else{
14345 if(abe-p>tag != List || !simple_verify){
14346 if(adr2->personal)
14347 fs_give((void **)&adr2->personal);
14349 adr2->personal = adrbk_formatname(abe->fullname,
14350 NULL, NULL);
14355 return(addr);
14360 char *
14361 peAEFcc(AdrBk_Entry *ae)
14363 char *fcc = NULL;
14365 if(ae->fcc && ae->fcc[0]){
14367 if(!strcmp(ae->fcc, "\"\""))
14368 fcc = cpystr("");
14369 else
14370 fcc = cpystr(ae->fcc);
14373 else if(ae->nickname && ae->nickname[0] &&
14374 (wps_global->fcc_rule == FCC_RULE_NICK ||
14375 wps_global->fcc_rule == FCC_RULE_NICK_RECIP)){
14377 * else if fcc-rule=fcc-by-nickname, use that
14380 fcc = cpystr(ae->nickname);
14383 return(fcc);
14385 #endif
14388 PINEFIELD *
14389 peCustomHdrs(void)
14391 extern PINEFIELD *parse_custom_hdrs(char **, CustomType);
14393 return(parse_custom_hdrs(wps_global->VAR_CUSTOM_HDRS, UseAsDef));
14399 * PEClistCmd - Collection list editing tools
14402 PEClistCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
14404 char *err = "Unknown PEClist request";
14406 dprint((2, "PEClistCmd"));
14408 if(objc == 1){
14409 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
14411 else{
14412 char *s1 = Tcl_GetStringFromObj(objv[1], NULL);
14414 if(s1){
14415 if(objc == 3){ /* delete */
14416 if(!strcmp(s1, "delete")){
14417 int cl, i, n, deln;
14418 char **newl;
14419 CONTEXT_S *del_ctxt, *tmp_ctxt, *new_ctxt;
14421 if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR){
14422 Tcl_SetResult(interp,
14423 "cledit malformed: first arg must be int",
14424 TCL_VOLATILE);
14425 return(TCL_ERROR);
14427 for(i = 0, del_ctxt = wps_global->context_list;
14428 del_ctxt && i < cl; i++, del_ctxt = del_ctxt->next);
14429 if(!del_ctxt) return(TCL_ERROR);
14430 for(n = 0; del_ctxt->var.v->current_val.l[n]; n++);
14431 n--;
14432 newl = (char **) fs_get((n + 1) * sizeof(char *));
14433 newl[n] = NULL;
14434 deln = del_ctxt->var.i;
14435 for(i = 0; del_ctxt->var.v->current_val.l[i]; i++){
14436 if(i < deln)
14437 newl[i] = cpystr(del_ctxt->var.v->current_val.l[i]);
14438 else if(i > deln)
14439 newl[i-1] = cpystr(del_ctxt->var.v->current_val.l[i]);
14441 n = set_variable_list(del_ctxt->var.v - wps_global->vars,
14442 *newl ? newl : NULL, TRUE, Main);
14443 free_list_array(&newl);
14444 set_current_val(del_ctxt->var.v, TRUE, FALSE);
14445 if(n){
14446 Tcl_SetResult(interp,
14447 "Error saving changes",
14448 TCL_VOLATILE);
14449 return TCL_OK;
14451 for(tmp_ctxt = del_ctxt->next; tmp_ctxt && tmp_ctxt->var.v ==
14452 del_ctxt->var.v; tmp_ctxt = tmp_ctxt->next)
14453 tmp_ctxt->var.i--;
14454 if((tmp_ctxt = del_ctxt->next) != NULL)
14455 tmp_ctxt->prev = del_ctxt->prev;
14456 if((tmp_ctxt = del_ctxt->prev) != NULL)
14457 tmp_ctxt->next= del_ctxt->next;
14458 if(!del_ctxt->prev && !del_ctxt->next){
14459 new_ctxt = new_context(del_ctxt->var.v->current_val.l[0], NULL);
14460 wps_global->context_list = new_ctxt;
14461 if(!new_ctxt->var.v)
14462 new_ctxt->var = del_ctxt->var;
14464 else if(wps_global->context_list == del_ctxt){
14465 wps_global->context_list = del_ctxt->next;
14466 if(!wps_global->context_list)
14467 return TCL_ERROR; /* this shouldn't happen */
14469 if(wps_global->context_last == del_ctxt)
14470 wps_global->context_last = NULL;
14471 if(wps_global->context_current == del_ctxt){
14472 strncpy(wps_global->cur_folder,
14473 wps_global->mail_stream->mailbox,
14474 sizeof(wps_global->cur_folder));
14475 wps_global->cur_folder[sizeof(wps_global->cur_folder)-1] = '\0';
14476 wps_global->context_current = wps_global->context_list;
14478 del_ctxt->prev = NULL;
14479 del_ctxt->next = NULL;
14480 free_context(&del_ctxt);
14481 init_inbox_mapping(wps_global->VAR_INBOX_PATH,
14482 wps_global->context_list);
14483 return TCL_OK;
14485 else if(!strcmp(s1, "shuffdown")){
14486 int cl, i, shn, n;
14487 CONTEXT_S *sh_ctxt, *nsh_ctxt, *tctxt;
14488 char **newl, *tmpch;
14490 if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR){
14491 Tcl_SetResult(interp,
14492 "cledit malformed: first arg must be int",
14493 TCL_VOLATILE);
14494 return(TCL_ERROR);
14496 for(sh_ctxt = wps_global->context_list, i = 0;
14497 sh_ctxt && i < cl ; i++, sh_ctxt = sh_ctxt->next);
14498 if(!sh_ctxt || !sh_ctxt->next){
14499 Tcl_SetResult(interp,
14500 "invalid context list number",
14501 TCL_VOLATILE);
14502 return TCL_ERROR;
14504 if(sh_ctxt->var.v == sh_ctxt->next->var.v){
14505 shn = sh_ctxt->var.i;
14506 for(n = 0; sh_ctxt->var.v->current_val.l[n]; n++);
14507 newl = (char **) fs_get((n + 1) * sizeof(char *));
14508 newl[n] = NULL;
14509 for(i = 0; sh_ctxt->var.v->current_val.l[i]; i++){
14510 if(i == shn)
14511 newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i+1]);
14512 else if(i == shn + 1)
14513 newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i-1]);
14514 else
14515 newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i]);
14517 n = set_variable_list(sh_ctxt->var.v - wps_global->vars,
14518 newl, TRUE, Main);
14519 free_list_array(&newl);
14520 set_current_val(sh_ctxt->var.v, TRUE, FALSE);
14521 if(n){
14522 Tcl_SetResult(interp,
14523 "Error saving changes",
14524 TCL_VOLATILE);
14525 return TCL_OK;
14527 nsh_ctxt = sh_ctxt->next;
14528 nsh_ctxt->var.i--;
14529 sh_ctxt->var.i++;
14531 else{
14532 nsh_ctxt = sh_ctxt->next;
14533 shn = sh_ctxt->var.i;
14534 tmpch = cpystr(sh_ctxt->var.v->current_val.l[shn]);
14535 for(n = 0; sh_ctxt->var.v->current_val.l[n]; n++);
14536 n--;
14537 newl = (char **) fs_get((n + 1) * sizeof(char *));
14538 newl[n] = NULL;
14539 for(i = 0; sh_ctxt->var.v->current_val.l[i+1]; i++)
14540 newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i]);
14541 n = set_variable_list(sh_ctxt->var.v - wps_global->vars,
14542 newl, FALSE, Main);
14543 free_list_array(&newl);
14544 set_current_val(sh_ctxt->var.v, TRUE, FALSE);
14545 for(n = 0; nsh_ctxt->var.v->current_val.l[n]; n++);
14546 n++;
14547 newl = (char **) fs_get((n + 1) * sizeof(char *));
14548 newl[n] = NULL;
14549 newl[0] = cpystr(nsh_ctxt->var.v->current_val.l[0]);
14550 newl[1] = tmpch;
14551 for(i = 2; nsh_ctxt->var.v->current_val.l[i-1]; i++)
14552 newl[i] = cpystr(nsh_ctxt->var.v->current_val.l[i-1]);
14553 n = set_variable_list(nsh_ctxt->var.v - wps_global->vars,
14554 newl, TRUE, Main);
14555 free_list_array(&newl);
14556 set_current_val(nsh_ctxt->var.v, TRUE, FALSE);
14557 sh_ctxt->var.v = nsh_ctxt->var.v;
14558 sh_ctxt->var.i = 1;
14559 /* this for loop assumes that there are only two variable lists,
14560 * folder-collections and news-collections, a little more will
14561 * have to be done if we want to accommodate for the INHERIT
14562 * option introduced in 4.30.
14564 for(tctxt = nsh_ctxt->next; tctxt; tctxt = tctxt->next)
14565 tctxt->var.i++;
14567 if(sh_ctxt->prev) sh_ctxt->prev->next = nsh_ctxt;
14568 nsh_ctxt->prev = sh_ctxt->prev;
14569 sh_ctxt->next = nsh_ctxt->next;
14570 nsh_ctxt->next = sh_ctxt;
14571 sh_ctxt->prev = nsh_ctxt;
14572 if(sh_ctxt->next) sh_ctxt->next->prev = sh_ctxt;
14573 if(wps_global->context_list == sh_ctxt)
14574 wps_global->context_list = nsh_ctxt;
14575 init_inbox_mapping(wps_global->VAR_INBOX_PATH,
14576 wps_global->context_list);
14577 return TCL_OK;
14579 else if(!strcmp(s1, "shuffup")){
14580 int cl, i, shn, n;
14581 CONTEXT_S *sh_ctxt, *psh_ctxt, *tctxt;
14582 char **newl, *tmpch;
14584 if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR){
14585 Tcl_SetResult(interp,
14586 "cledit malformed: first arg must be int",
14587 TCL_VOLATILE);
14588 return(TCL_ERROR);
14590 for(sh_ctxt = wps_global->context_list, i = 0;
14591 sh_ctxt && i < cl ; i++, sh_ctxt = sh_ctxt->next);
14592 if(!sh_ctxt || !sh_ctxt->prev){
14593 Tcl_SetResult(interp,
14594 "invalid context list number",
14595 TCL_VOLATILE);
14596 return TCL_ERROR;
14598 if(sh_ctxt->var.v == sh_ctxt->prev->var.v){
14599 shn = sh_ctxt->var.i;
14600 for(n = 0; sh_ctxt->var.v->current_val.l[n]; n++);
14601 newl = (char **) fs_get((n + 1) * sizeof(char *));
14602 newl[n] = NULL;
14603 for(i = 0; sh_ctxt->var.v->current_val.l[i]; i++){
14604 if(i == shn)
14605 newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i-1]);
14606 else if(i == shn - 1)
14607 newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i+1]);
14608 else
14609 newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i]);
14611 i = set_variable_list(sh_ctxt->var.v - wps_global->vars,
14612 newl, TRUE, Main);
14613 free_list_array(&newl);
14614 set_current_val(sh_ctxt->var.v, TRUE, FALSE);
14615 if(i){
14616 Tcl_SetResult(interp,
14617 "Error saving changes",
14618 TCL_VOLATILE);
14619 return TCL_OK;
14621 psh_ctxt = sh_ctxt->prev;
14622 psh_ctxt->var.i++;
14623 sh_ctxt->var.i--;
14625 else{
14626 psh_ctxt = sh_ctxt->prev;
14627 shn = sh_ctxt->var.i;
14628 tmpch = cpystr(sh_ctxt->var.v->current_val.l[shn]);
14629 for(n = 0; sh_ctxt->var.v->current_val.l[n]; n++);
14630 n--;
14631 newl = (char **) fs_get((n + 1) * sizeof(char *));
14632 newl[n] = NULL;
14633 for(i = 1; sh_ctxt->var.v->current_val.l[i]; i++)
14634 newl[i-1] = cpystr(sh_ctxt->var.v->current_val.l[i]);
14635 i = set_variable_list(sh_ctxt->var.v - wps_global->vars,
14636 newl, FALSE, Main);
14637 free_list_array(&newl);
14638 if(i){
14639 Tcl_SetResult(interp,
14640 "Error saving changes",
14641 TCL_VOLATILE);
14642 return TCL_OK;
14644 set_current_val(sh_ctxt->var.v, TRUE, FALSE);
14645 for(n = 0; psh_ctxt->var.v->current_val.l[n]; n++);
14646 n++;
14647 newl = (char **) fs_get((n + 1) * sizeof(char *));
14648 newl[n] = NULL;
14649 for(i = 0; psh_ctxt->var.v->current_val.l[i+1]; i++)
14650 newl[i] = cpystr(psh_ctxt->var.v->current_val.l[i]);
14651 newl[i++] = tmpch;
14652 newl[i] = cpystr(psh_ctxt->var.v->current_val.l[i-1]);
14653 i = set_variable_list(psh_ctxt->var.v - wps_global->vars,
14654 newl, TRUE, Main);
14655 free_list_array(&newl);
14656 if(i){
14657 Tcl_SetResult(interp,
14658 "Error saving changes",
14659 TCL_VOLATILE);
14660 return TCL_OK;
14662 set_current_val(psh_ctxt->var.v, TRUE, FALSE);
14663 for(tctxt = sh_ctxt->next ; tctxt; tctxt = tctxt->next)
14664 tctxt->var.i--;
14665 sh_ctxt->var.v = psh_ctxt->var.v;
14666 sh_ctxt->var.i = n - 2;
14667 /* There MUST be at least 2 collections in the list */
14668 psh_ctxt->var.i++;
14670 if(sh_ctxt->next) sh_ctxt->next->prev = psh_ctxt;
14671 psh_ctxt->next = sh_ctxt->next;
14672 sh_ctxt->prev = psh_ctxt->prev;
14673 psh_ctxt->prev = sh_ctxt;
14674 sh_ctxt->next = psh_ctxt;
14675 if(sh_ctxt->prev) sh_ctxt->prev->next = sh_ctxt;
14676 if(wps_global->context_list == psh_ctxt)
14677 wps_global->context_list = sh_ctxt;
14678 init_inbox_mapping(wps_global->VAR_INBOX_PATH,
14679 wps_global->context_list);
14680 return TCL_OK;
14683 else if(objc == 7){
14684 if(!strcmp(s1, "edit") || !strcmp(s1, "add")){
14685 int cl, quotes_needed = 0, i, add = 0, n = 0;
14686 char *nick, *server, *path, *view,
14687 context_buf[MAILTMPLEN*4], **newl;
14688 CONTEXT_S *new_ctxt, *tmp_ctxt;
14690 if(!strcmp(s1, "add")) add = 1;
14692 if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR){
14693 Tcl_SetResult(interp,
14694 "cledit malformed: first arg must be int",
14695 TCL_VOLATILE);
14696 return(TCL_ERROR);
14698 if(!(nick = Tcl_GetStringFromObj(objv[3], NULL))){
14699 Tcl_SetResult(interp,
14700 "Error1",
14701 TCL_VOLATILE);
14702 return TCL_ERROR;
14704 if(!(server = Tcl_GetStringFromObj(objv[4], NULL))){
14705 Tcl_SetResult(interp,
14706 "Error2",
14707 TCL_VOLATILE);
14708 return TCL_ERROR;
14710 if(!(path = Tcl_GetStringFromObj(objv[5], NULL))){
14711 Tcl_SetResult(interp,
14712 "Error3",
14713 TCL_VOLATILE);
14714 return TCL_ERROR;
14716 if(!(view = Tcl_GetStringFromObj(objv[6], NULL))){
14717 Tcl_SetResult(interp,
14718 "Error4",
14719 TCL_VOLATILE);
14720 return TCL_ERROR;
14722 removing_leading_and_trailing_white_space(nick);
14723 removing_leading_and_trailing_white_space(server);
14724 removing_leading_and_trailing_white_space(path);
14725 removing_leading_and_trailing_white_space(view);
14726 if(strchr(nick, ' '))
14727 quotes_needed = 1;
14728 if(strlen(nick)+strlen(server)+strlen(path)+strlen(view) >
14729 MAILTMPLEN * 4 - 20) { /* for good measure */
14730 Tcl_SetResult(interp,
14731 "info too long",
14732 TCL_VOLATILE);
14734 return TCL_ERROR;
14736 if(3 + strlen(nick) + strlen(server) + strlen(path) +
14737 strlen(view) > MAILTMPLEN + 4){
14738 Tcl_SetResult(interp,
14739 "collection fields too long",
14740 TCL_VOLATILE);
14741 return(TCL_OK);
14743 snprintf(context_buf, sizeof(context_buf), "%s%s%s%s%s%s[%s]", quotes_needed ?
14744 "\"" : "", nick, quotes_needed ? "\"" : "",
14745 strlen(nick) ? " " : "",
14746 server, path, view);
14747 new_ctxt = new_context(context_buf, NULL);
14748 if(!add){
14749 for(tmp_ctxt = wps_global->context_list, i = 0;
14750 tmp_ctxt && i < cl; i++, tmp_ctxt = tmp_ctxt->next);
14751 if(!tmp_ctxt){
14752 Tcl_SetResult(interp,
14753 "invalid context list number",
14754 TCL_VOLATILE);
14755 return TCL_ERROR;
14757 new_ctxt->next = tmp_ctxt->next;
14758 new_ctxt->prev = tmp_ctxt->prev;
14759 if(tmp_ctxt->prev && tmp_ctxt->prev->next == tmp_ctxt)
14760 tmp_ctxt->prev->next = new_ctxt;
14761 if(tmp_ctxt->next && tmp_ctxt->next->prev == tmp_ctxt)
14762 tmp_ctxt->next->prev = new_ctxt;
14763 if(wps_global->context_list == tmp_ctxt)
14764 wps_global->context_list = new_ctxt;
14765 if(wps_global->context_current == tmp_ctxt){
14766 strncpy(wps_global->cur_folder,
14767 wps_global->mail_stream->mailbox,
14768 sizeof(wps_global->cur_folder));
14769 wps_global->cur_folder[sizeof(wps_global->cur_folder)-1] = '\0';
14770 wps_global->context_current = new_ctxt;
14772 if(wps_global->context_last == tmp_ctxt)
14773 wps_global->context_last = new_ctxt;
14774 new_ctxt->var = tmp_ctxt->var;
14775 tmp_ctxt->next = tmp_ctxt->prev = NULL;
14776 free_context(&tmp_ctxt);
14778 else {
14779 for(tmp_ctxt = wps_global->context_list;
14780 tmp_ctxt->next; tmp_ctxt = tmp_ctxt->next);
14781 new_ctxt->prev = tmp_ctxt;
14782 tmp_ctxt->next = new_ctxt;
14783 new_ctxt->var.v = tmp_ctxt->var.v;
14784 new_ctxt->var.i = tmp_ctxt->var.i + 1;
14786 if(!new_ctxt->var.v){
14787 Tcl_SetResult(interp,
14788 "Error5",
14789 TCL_VOLATILE);
14790 return TCL_ERROR;
14792 for(n = 0; new_ctxt->var.v->current_val.l[n]; n++);
14793 if(add) n++;
14794 newl = (char **) fs_get((n + 1) * sizeof(char *));
14795 newl[n] = NULL;
14796 for(n = 0; new_ctxt->var.v->current_val.l[n]; n++)
14797 newl[n] = (n == new_ctxt->var.i)
14798 ? cpystr(context_buf)
14799 : cpystr(new_ctxt->var.v->current_val.l[n]);
14800 if(add) newl[n++] = cpystr(context_buf);
14801 n = set_variable_list(new_ctxt->var.v - wps_global->vars,
14802 newl, TRUE, Main);
14803 free_list_array(&newl);
14804 set_current_val(new_ctxt->var.v, TRUE, FALSE);
14805 init_inbox_mapping(wps_global->VAR_INBOX_PATH,
14806 wps_global->context_list);
14807 if(n){
14808 Tcl_SetResult(interp,
14809 "Error saving changes",
14810 TCL_VOLATILE);
14811 return TCL_OK;
14813 return TCL_OK;
14819 Tcl_SetResult(interp, err, TCL_STATIC);
14820 return(TCL_ERROR);
14825 * peTakeaddr - Take Address
14828 peTakeaddr(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
14830 TA_S *talist = NULL, *current, *head;
14831 Tcl_Obj *itemObj, *secObj = NULL, *resObj = NULL;
14832 int anum = 0;
14834 mn_set_cur(sp_msgmap(wps_global->mail_stream), peMessageNumber(uid));
14836 if(set_up_takeaddr('a', wps_global, sp_msgmap(wps_global->mail_stream),
14837 &talist, &anum, TA_NOPROMPT, NULL) < 0
14838 || (talist == NULL)){
14839 Tcl_SetResult(interp,
14840 "Take address failed to set up",
14841 TCL_VOLATILE);
14842 return(TCL_ERROR);
14845 for(head = talist ; head->prev; head = head->prev);
14847 * Return value will be of the form:
14849 * { "line to print",
14850 * {"personal", "mailbox", "host"} # addr
14851 * {"nick", "fullname", "fcc", "comment"} # suggested
14853 * ...
14856 * The two list items will be empty if that line is
14857 * just informational.
14859 itemObj = Tcl_NewListObj(0, NULL);
14860 for(current = head; current ; current = current->next){
14861 if(current->skip_it && !current->print) continue;
14862 secObj = Tcl_NewListObj(0, NULL);
14863 if(Tcl_ListObjAppendElement(interp, secObj,
14864 Tcl_NewStringObj(current->strvalue,-1)) != TCL_OK)
14865 return(TCL_ERROR);
14866 resObj = Tcl_NewListObj(0, NULL);
14867 /* append the address information */
14868 if(current->addr && !current->print){
14869 if(Tcl_ListObjAppendElement(interp, resObj,
14870 Tcl_NewStringObj(current->addr->personal
14871 ? current->addr->personal
14872 : "", -1)) != TCL_OK)
14873 return(TCL_ERROR);
14874 if(Tcl_ListObjAppendElement(interp, resObj,
14875 Tcl_NewStringObj(current->addr->mailbox
14876 ? current->addr->mailbox
14877 : "", -1)) != TCL_OK)
14878 return(TCL_ERROR);
14879 if(Tcl_ListObjAppendElement(interp, resObj,
14880 Tcl_NewStringObj(current->addr->host
14881 ? current->addr->host
14882 : "", -1)) != TCL_OK)
14883 return(TCL_ERROR);
14885 if(Tcl_ListObjAppendElement(interp, secObj,
14886 resObj) != TCL_OK)
14887 return(TCL_ERROR);
14888 resObj = Tcl_NewListObj(0, NULL);
14889 /* append the suggested possible entries */
14890 if(!current->print
14891 && (current->nickname || current->fullname
14892 || current->fcc || current->comment)){
14893 if(Tcl_ListObjAppendElement(interp, resObj,
14894 Tcl_NewStringObj(current->nickname
14895 ? current->nickname
14896 : "", -1)) != TCL_OK)
14897 return(TCL_ERROR);
14898 if(Tcl_ListObjAppendElement(interp, resObj,
14899 Tcl_NewStringObj(current->fullname
14900 ? current->fullname
14901 : "", -1)) != TCL_OK)
14902 return(TCL_ERROR);
14903 if(Tcl_ListObjAppendElement(interp, resObj,
14904 Tcl_NewStringObj(current->fcc
14905 ? current->fcc
14906 : "", -1)) != TCL_OK)
14907 return(TCL_ERROR);
14908 if(Tcl_ListObjAppendElement(interp, resObj,
14909 Tcl_NewStringObj(current->comment
14910 ? current->comment
14911 : "", -1)) != TCL_OK)
14912 return(TCL_ERROR);
14914 if(Tcl_ListObjAppendElement(interp, secObj, resObj) != TCL_OK)
14915 return(TCL_ERROR);
14916 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
14917 secObj) != TCL_OK)
14918 return(TCL_ERROR);
14921 free_talines(&talist);
14922 return(TCL_OK);
14927 * peTakeFrom - Take only From Address
14930 peTakeFrom(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv)
14932 char *err = NULL;
14933 Tcl_Obj *objItem;
14934 ADDRESS *ap;
14935 ENVELOPE *env;
14936 long rawno;
14939 * Return value will be of the form:
14941 * { "line to print",
14942 * {"personal", "mailbox", "host"} # addr
14943 * {"nick", "fullname", "fcc", "comment"} # suggested
14945 * ...
14948 * The two list items will be empty if that line is
14949 * just informational.
14952 if(uid){
14953 if((env = pine_mail_fetchstructure(wps_global->mail_stream,
14954 rawno = peSequenceNumber(uid),
14955 NULL))){
14956 /* append the address information */
14957 for(ap = env->from; ap; ap = ap->next){
14958 objItem = Tcl_NewListObj(0, NULL);
14959 /* append EMPTY "line to print" */
14960 if(Tcl_ListObjAppendElement(interp, objItem, Tcl_NewStringObj("",-1)) != TCL_OK)
14961 return(TCL_ERROR);
14963 /* append address info */
14964 peAppListF(interp, objItem, "%s%s%s",
14965 ap->personal ? (char *) rfc1522_decode_to_utf8((unsigned char *) wtmp_20k_buf, SIZEOF_20KBUF, ap->personal) : "",
14966 ap->mailbox ? ap->mailbox : "",
14967 ap->host ? ap->host : "");
14969 /* append suggested info */
14970 peAddSuggestedContactInfo(interp, objItem, ap);
14972 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objItem) != TCL_OK)
14973 return(TCL_ERROR);
14976 return(TCL_OK);
14978 else
14979 err = wps_global->last_error;
14981 else
14982 err = "Invalid UID";
14984 return(TCL_ERROR);
14989 peAddSuggestedContactInfo(Tcl_Interp *interp, Tcl_Obj *lobjp, ADDRESS *addr)
14991 char *nick = NULL, *full = NULL, *fcc = NULL, *comment = NULL;
14993 get_contactinfo_from_addr(addr, &nick, &full, &fcc, &comment);
14995 peAppListF(interp, lobjp, "%s%s%s%s",
14996 nick ? nick : "",
14997 full ? full : "",
14998 fcc ? fcc : "",
14999 comment ? comment : "");
15001 if(nick)
15002 fs_give((void **) &nick);
15004 if(full)
15005 fs_give((void **) &full);
15007 if(fcc)
15008 fs_give((void **) &fcc);
15010 if(comment)
15011 fs_give((void **) &comment);
15013 return 0;
15017 /* * * * * * * * * Status message ring management * * * * * * * * * * * * */
15019 STATMSG_S *
15020 sml_newmsg(int priority, char *text)
15022 static long id = 1;
15023 STATMSG_S *smp;
15025 smp = (STATMSG_S *) fs_get(sizeof(STATMSG_S));
15026 memset(smp, 0, sizeof(STATMSG_S));
15027 smp->id = id++;
15028 smp->posted = time(0);
15029 smp->type = priority;
15030 smp->text = cpystr(text);
15031 return(smp);
15035 void
15036 sml_addmsg(int priority, char *text)
15038 STATMSG_S *smp = sml_newmsg(priority, text);
15040 if(peStatList){
15041 smp->next = peStatList;
15042 peStatList = smp;
15044 else
15045 peStatList = smp;
15049 char **
15050 sml_getmsgs(void)
15052 int n;
15053 STATMSG_S *smp;
15054 char **retstrs = NULL, **tmpstrs;
15056 for(n = 0, smp = peStatList; smp && !smp->seen; n++, smp = smp->next)
15059 if(n == 0) return NULL;
15060 retstrs = (char **)fs_get((n+1)*sizeof(char *));
15061 for(tmpstrs = retstrs, smp = peStatList; smp && !smp->seen; smp = smp->next){
15062 *tmpstrs = smp->text;
15063 tmpstrs++;
15066 *tmpstrs = NULL;
15067 return(retstrs);
15071 char *
15072 sml_getmsg(void)
15074 return(peStatList ? peStatList->text : "");
15077 void
15078 sml_seen(void)
15080 STATMSG_S *smp;
15082 for(smp = peStatList; smp; smp = smp->next)
15083 smp->seen = 1;
15088 /* * * * * * * * * LDAP Support Routines * * * * * * * * * * * */
15092 * PELdapCmd - LDAP TCL interface
15095 PELdapCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
15097 #ifndef ENABLE_LDAP
15098 char *err = "Call to PELdap when LDAP not enabled";
15099 #else
15100 char *err = "Unknown PELdap request";
15101 char *s1;
15103 dprint((2, "PELdapCmd"));
15105 if(objc == 1){
15106 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
15107 Tcl_SetResult(interp, err, TCL_STATIC);
15108 return(TCL_ERROR);
15110 s1 = Tcl_GetStringFromObj(objv[1], NULL);
15112 if(s1){
15113 int qn;
15114 if(!strcmp(s1, "directories")){
15115 int i;
15116 LDAP_SERV_S *info;
15117 Tcl_Obj *secObj;
15119 if(objc != 2){
15120 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
15121 Tcl_SetResult(interp, err, TCL_STATIC);
15122 return(TCL_ERROR);
15124 if(wps_global->VAR_LDAP_SERVERS){
15125 for(i = 0; wps_global->VAR_LDAP_SERVERS[i] &&
15126 wps_global->VAR_LDAP_SERVERS[i][0]; i++){
15127 info = break_up_ldap_server(wps_global->VAR_LDAP_SERVERS[i]);
15128 secObj = Tcl_NewListObj(0, NULL);
15129 if(Tcl_ListObjAppendElement(interp, secObj,
15130 Tcl_NewStringObj(info->nick ? info->nick
15131 : "", -1)) != TCL_OK)
15132 return(TCL_ERROR);
15133 if(Tcl_ListObjAppendElement(interp, secObj,
15134 Tcl_NewStringObj(info->serv ? info->serv
15135 : "", -1)) != TCL_OK)
15136 return(TCL_ERROR);
15138 if(info)
15139 free_ldap_server_info(&info);
15140 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
15141 secObj) != TCL_OK)
15142 return(TCL_ERROR);
15145 else
15146 Tcl_SetResult(interp, "", TCL_STATIC);
15148 return(TCL_OK);
15150 else if(!strcmp(s1, "query")){
15151 int dir;
15152 char *srchstr, *filtstr;
15153 LDAP_CHOOSE_S *winning_e = NULL;
15154 LDAP_SERV_RES_S *results = NULL;
15155 WP_ERR_S wp_err;
15156 CUSTOM_FILT_S *filter = NULL;
15158 if(objc != 5){
15159 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
15160 Tcl_SetResult(interp, err, TCL_STATIC);
15161 return(TCL_ERROR);
15163 if(Tcl_GetIntFromObj(interp, objv[2], &dir) == TCL_ERROR){
15164 Tcl_SetResult(interp,
15165 "PELdap results malformed: first arg must be int",
15166 TCL_VOLATILE);
15167 return(TCL_ERROR);
15169 wpldap_global->query_no++;
15170 if(wpldap_global->ldap_search_list){
15171 wpldap_global->ldap_search_list =
15172 free_wpldapres(wpldap_global->ldap_search_list);
15174 srchstr = Tcl_GetStringFromObj(objv[3], NULL);
15175 filtstr = Tcl_GetStringFromObj(objv[4], NULL);
15176 if(!srchstr) return(TCL_ERROR);
15177 if(!filtstr) return(TCL_ERROR);
15178 if(*filtstr){
15179 filter = (CUSTOM_FILT_S *)fs_get(sizeof(CUSTOM_FILT_S));
15180 filter->filt = cpystr(filtstr);
15181 filter->combine = 0;
15183 memset(&wp_err, 0, sizeof(wp_err));
15184 ldap_lookup_all(srchstr, dir, 0, AlwaysDisplay, filter, &winning_e,
15185 &wp_err, &results);
15186 if(filter){
15187 fs_give((void **)&filter->filt);
15188 fs_give((void **)&filter);
15190 Tcl_SetResult(interp, int2string(wpldap_global->ldap_search_list
15191 ? wpldap_global->query_no : 0),
15192 TCL_VOLATILE);
15193 return(TCL_OK);
15196 * First argument has always got to be the query number for now.
15197 * Might need to rething that when setting up queries.
15199 if(objc == 2){
15200 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
15201 Tcl_SetResult(interp, err, TCL_STATIC);
15202 return(TCL_ERROR);
15204 if(Tcl_GetIntFromObj(interp, objv[2], &qn) == TCL_ERROR){
15205 Tcl_SetResult(interp,
15206 "PELdap results malformed: first arg must be int",
15207 TCL_VOLATILE);
15208 return(TCL_ERROR);
15210 if(qn != wpldap_global->query_no){
15211 Tcl_SetResult(interp,
15212 "Query is no longer valid", TCL_VOLATILE);
15213 return(TCL_ERROR);
15215 if(objc == 3){
15216 if(!strcmp(s1, "results")){
15217 return(peLdapQueryResults(interp));
15220 else if(objc == 4){
15221 if(!strcmp(s1, "ldapext")){
15223 * Returns a list of the form:
15224 * {"dn" {{attrib {val, ...}}, ...}}
15226 char *whichrec = Tcl_GetStringFromObj(objv[3], NULL);
15227 char *tmpstr, *tmp, *tmp2, *a;
15228 struct berval **vals;
15229 WPLDAPRES_S *curres;
15230 LDAP_CHOOSE_S *winning_e = NULL;
15231 LDAP_SERV_RES_S *trl;
15232 Tcl_Obj *secObj = NULL, *resObj = NULL, *itemObj;
15233 BerElement *ber;
15234 LDAPMessage *e;
15235 int i, j, whichi, whichj;
15237 if(whichrec == NULL){
15238 Tcl_SetResult(interp, "Ldap ldapext error 1", TCL_VOLATILE);
15239 return TCL_ERROR;
15241 tmpstr = cpystr(whichrec);
15242 tmp = tmpstr;
15243 for(tmp2 = tmp; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++);
15244 if(*tmp2 != '.'){
15245 Tcl_SetResult(interp, "Ldap ldapext error 2", TCL_VOLATILE);
15246 return TCL_ERROR;
15248 *tmp2 = '\0';
15249 whichi = atoi(tmp);
15250 *tmp2 = '.';
15251 tmp2++;
15252 for(tmp = tmp2; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++);
15253 if(*tmp2 != '\0'){
15254 Tcl_SetResult(interp, "Ldap ldapext error 3", TCL_VOLATILE);
15255 return TCL_ERROR;
15257 whichj = atoi(tmp);
15258 fs_give((void **)&tmpstr);
15259 for(curres = wpldap_global->ldap_search_list, i = 0;
15260 i < whichi && curres; i++, curres = curres->next);
15261 if(!curres){
15262 Tcl_SetResult(interp, "Ldap ldapext error 4", TCL_VOLATILE);
15263 return TCL_ERROR;
15265 for(trl = curres->reslist, j = 0; trl; trl = trl->next){
15266 for(e = ldap_first_entry(trl->ld, trl->res);
15267 e != NULL && j < whichj;
15268 e = ldap_next_entry(trl->ld, e), j++);
15269 if(e != NULL && j == whichj)
15270 break;
15272 if(e == NULL || trl == NULL){
15273 Tcl_SetResult(interp, "Ldap ldapext error 5", TCL_VOLATILE);
15274 return TCL_ERROR;
15276 winning_e = (LDAP_CHOOSE_S *)fs_get(sizeof(LDAP_CHOOSE_S));
15277 winning_e->ld = trl->ld;
15278 winning_e->selected_entry = e;
15279 winning_e->info_used = trl->info_used;
15280 winning_e->serv = trl->serv;
15281 a = ldap_get_dn(winning_e->ld, winning_e->selected_entry);
15282 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
15283 Tcl_NewStringObj(a ? a : "", -1)) != TCL_OK)
15284 return(TCL_ERROR);
15285 if(a)
15286 our_ldap_dn_memfree(a);
15288 itemObj = Tcl_NewListObj(0, NULL);
15289 for(a = ldap_first_attribute(winning_e->ld, winning_e->selected_entry, &ber);
15290 a != NULL;
15291 a = ldap_next_attribute(winning_e->ld, winning_e->selected_entry, ber)){
15292 if(a && *a){
15293 secObj = Tcl_NewListObj(0, NULL);
15294 if(Tcl_ListObjAppendElement(interp, secObj,
15295 Tcl_NewStringObj(ldap_translate(a,
15296 winning_e->info_used), -1)) != TCL_OK)
15297 return(TCL_ERROR);
15298 resObj = Tcl_NewListObj(0, NULL);
15299 vals = ldap_get_values_len(winning_e->ld, winning_e->selected_entry, a);
15300 if(vals){
15301 for(i = 0; vals[i]; i++){
15302 if(Tcl_ListObjAppendElement(interp, resObj,
15303 Tcl_NewStringObj(vals[i]->bv_val, -1)) != TCL_OK)
15304 return(TCL_ERROR);
15306 ldap_value_free_len(vals);
15307 if(Tcl_ListObjAppendElement(interp, secObj, resObj) != TCL_OK)
15308 return(TCL_ERROR);
15310 if(!strcmp(a,"objectclass")){
15311 if(Tcl_ListObjAppendElement(interp, secObj,
15312 Tcl_NewStringObj("objectclass", -1)) != TCL_OK)
15313 return(TCL_ERROR);
15315 if(Tcl_ListObjAppendElement(interp, itemObj, secObj) != TCL_OK)
15316 return(TCL_ERROR);
15318 our_ldap_memfree(a);
15321 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
15322 itemObj) != TCL_OK)
15323 return(TCL_ERROR);
15325 fs_give((void **)&winning_e);
15326 return(TCL_OK);
15329 else if(objc == 6){
15330 if(!strcmp(s1, "setaddrs")){
15331 char *listset = Tcl_GetStringFromObj(objv[3], NULL);
15332 char *addrstr = Tcl_GetStringFromObj(objv[4], NULL);
15333 char *tmp, *tmp2, *tmplistset, was_char, *ret_to,
15334 *tmpaddrstr;
15335 int **lset, noreplace = 0;
15336 ADDRESS *adr = NULL, *curadr, *prevadr, *newadr,
15337 *curnewadr, *newadrs;
15338 int curi, i, j, numsrchs, numset, setit;
15339 LDAP_CHOOSE_S *tres;
15340 LDAP_SERV_RES_S *trl;
15341 WPLDAPRES_S *curres;
15342 LDAPMessage *e;
15343 RFC822BUFFER rbuf;
15344 size_t len;
15346 if(Tcl_GetIntFromObj(interp, objv[5], &noreplace) == TCL_ERROR){
15347 Tcl_SetResult(interp,
15348 "PELdap results malformed: first arg must be int",
15349 TCL_VOLATILE);
15350 return(TCL_ERROR);
15352 if(listset == NULL || addrstr == NULL) return TCL_ERROR;
15353 tmpaddrstr = cpystr(addrstr);
15355 if(!noreplace){
15356 mail_parameters(NIL, SET_PARSEPHRASE, (void *)massage_phrase_addr);
15357 rfc822_parse_adrlist(&adr, tmpaddrstr, "@");
15358 mail_parameters(NIL, SET_PARSEPHRASE, NULL);
15361 tmplistset = cpystr(listset);
15362 for(curres = wpldap_global->ldap_search_list, numsrchs = 0;
15363 curres; curres = curres->next, numsrchs++);
15364 lset = (int **)fs_get((numsrchs+1)*sizeof(int *));
15365 for(i = 0; i < numsrchs; i++){
15366 for(tmp = tmplistset, numset = 0; *tmp;){
15367 for(tmp2 = tmp; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++);
15368 if(*tmp2 != '.'){
15369 Tcl_SetResult(interp, "Ldap error 1", TCL_VOLATILE);
15370 return TCL_ERROR;
15372 if(atoi(tmp) == i) numset++;
15373 tmp2++;
15374 for(tmp = tmp2; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++);
15375 if(*tmp2 != ',' && *tmp2 != '\0'){
15376 Tcl_SetResult(interp, "Ldap error 2", TCL_VOLATILE);
15377 return TCL_ERROR;
15379 if(*tmp2) tmp2++;
15380 tmp = tmp2;
15382 lset[i] = (int *)fs_get((numset+1)*sizeof(int));
15383 for(tmp = tmplistset, j = 0; *tmp && j < numset;){
15384 setit = 0;
15385 for(tmp2 = tmp; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++);
15386 if(*tmp2 != '.'){
15387 Tcl_SetResult(interp, "Ldap error 3", TCL_VOLATILE);
15388 return TCL_ERROR;
15390 *tmp2 = '\0';
15391 if(atoi(tmp) == i) setit++;
15392 *tmp2 = '.';
15393 tmp2++;
15394 for(tmp = tmp2; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++);
15395 if(*tmp2 != ',' && *tmp2 != '\0'){
15396 Tcl_SetResult(interp, "Ldap error 4", TCL_VOLATILE);
15397 return TCL_ERROR;
15399 if(setit){
15400 was_char = *tmp2;
15401 *tmp2 = '\0';
15402 lset[i][j++] = atoi(tmp);
15403 *tmp2 = was_char;
15405 if(*tmp2) tmp2++;
15406 tmp = tmp2;
15408 lset[i][j] = -1;
15410 lset[i] = NULL;
15411 for(i = 0, curres = wpldap_global->ldap_search_list;
15412 i < numsrchs && curres; i++, curres = curres->next){
15413 prevadr = NULL;
15414 for(curadr = adr; curadr; curadr = curadr->next){
15415 if(strcmp(curadr->mailbox, curres->str) == 0
15416 && curadr->host && *curadr->host == '@')
15417 break;
15418 prevadr = curadr;
15420 if(!curadr && !noreplace){
15421 Tcl_SetResult(interp, "Ldap error 5", TCL_VOLATILE);
15422 return TCL_ERROR;
15424 newadrs = newadr = curnewadr = NULL;
15425 for(trl = curres->reslist, j = 0, curi = 0; trl; trl = trl->next){
15426 for(e = ldap_first_entry(trl->ld, trl->res);
15427 e != NULL && lset[i][curi] != -1;
15428 e = ldap_next_entry(trl->ld, e), j++){
15429 if(j == lset[i][curi]){
15430 tres = (LDAP_CHOOSE_S *)fs_get(sizeof(LDAP_CHOOSE_S));
15431 tres->ld = trl->ld;
15432 tres->selected_entry = e;
15433 tres->info_used = trl->info_used;
15434 tres->serv = trl->serv;
15435 newadr = address_from_ldap(tres);
15436 fs_give((void **)&tres);
15438 if(newadrs == NULL){
15439 newadrs = curnewadr = newadr;
15441 else {
15442 curnewadr->next = newadr;
15443 curnewadr = newadr;
15445 curi++;
15449 if(newadrs == NULL || curnewadr == NULL){
15450 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "No Result Selected for \"%s\"", curadr->mailbox ? curadr->mailbox : "noname");
15451 q_status_message(SM_ORDER, 0, 3, wtmp_20k_buf);
15452 newadr = copyaddr(curadr);
15453 if(newadrs == NULL){
15454 newadrs = curnewadr = newadr;
15456 else {
15457 curnewadr->next = newadr;
15458 curnewadr = newadr;
15461 curnewadr->next = curadr ? curadr->next : NULL;
15462 if(curadr) curadr->next = NULL;
15463 if(curadr == adr)
15464 adr = newadrs;
15465 else{
15466 prevadr->next = newadrs;
15467 if(curadr)
15468 mail_free_address(&curadr);
15472 len = est_size(adr);
15473 ret_to = (char *)fs_get(len * sizeof(char));
15474 ret_to[0] = '\0';
15475 strip_personal_quotes(adr);
15476 rbuf.f = dummy_soutr;
15477 rbuf.s = NULL;
15478 rbuf.beg = ret_to;
15479 rbuf.cur = ret_to;
15480 rbuf.end = ret_to+len-1;
15481 rfc822_output_address_list(&rbuf, adr, 0L, NULL);
15482 *rbuf.cur = '\0';
15483 Tcl_SetResult(interp, ret_to, TCL_VOLATILE);
15484 fs_give((void **)&ret_to);
15485 fs_give((void **)&tmpaddrstr);
15486 fs_give((void **)&tmplistset);
15487 for(i = 0; lset[i]; i++)
15488 fs_give((void **)&lset[i]);
15489 fs_give((void **)&lset);
15490 if(adr)
15491 mail_free_address(&adr);
15493 return(TCL_OK);
15497 #endif /* ENABLE_LDAP */
15498 Tcl_SetResult(interp, err, TCL_STATIC);
15499 return(TCL_ERROR);
15503 #ifdef ENABLE_LDAP
15505 peLdapQueryResults(Tcl_Interp *interp)
15507 WPLDAPRES_S *tsl;
15508 Tcl_Obj *secObj = NULL, *resObj = NULL, *itemObj;
15509 LDAPMessage *e;
15510 LDAP_SERV_RES_S *trl;
15511 /* returned list will be of the form:
15514 * {search-string
15515 * {name, {title, ...}, {unit, ...},
15516 * {org, ...}, {email, ...}},
15517 * ...
15518 * },
15519 * ...
15523 for(tsl = wpldap_global->ldap_search_list;
15524 tsl; tsl = tsl->next){
15525 secObj = Tcl_NewListObj(0, NULL);
15526 if(Tcl_ListObjAppendElement(interp, secObj,
15527 Tcl_NewStringObj(tsl->str ? tsl->str
15528 : "", -1)) != TCL_OK)
15529 return(TCL_ERROR);
15530 resObj = Tcl_NewListObj(0, NULL);
15531 for(trl = tsl->reslist; trl; trl = trl->next){
15532 for(e = ldap_first_entry(trl->ld, trl->res);
15533 e != NULL;
15534 e = ldap_next_entry(trl->ld, e)){
15535 char *dn;
15536 struct berval **cn, **org, **unit, **title, **mail, **sn;
15538 dn = NULL;
15539 cn = org = title = unit = mail = sn = NULL;
15541 itemObj = Tcl_NewListObj(0, NULL);
15542 peLdapEntryParse(trl, e, &cn, &org, &unit, &title,
15543 &mail, &sn);
15544 if(cn){
15545 if(Tcl_ListObjAppendElement(interp, itemObj,
15546 Tcl_NewStringObj(cn[0]->bv_val, -1)) != TCL_OK)
15547 return(TCL_ERROR);
15548 ldap_value_free_len(cn);
15550 else if(sn){
15551 if(Tcl_ListObjAppendElement(interp, itemObj,
15552 Tcl_NewStringObj(sn[0]->bv_val, -1)) != TCL_OK)
15553 return(TCL_ERROR);
15554 ldap_value_free_len(sn);
15556 else{
15557 dn = ldap_get_dn(trl->ld, e);
15559 if(dn && !dn[0]){
15560 our_ldap_dn_memfree(dn);
15561 dn = NULL;
15564 if(Tcl_ListObjAppendElement(interp, itemObj,
15565 Tcl_NewStringObj(dn ? dn : "", -1)) != TCL_OK)
15566 return(TCL_ERROR);
15568 if(dn)
15569 our_ldap_dn_memfree(dn);
15571 if(peLdapStrlist(interp, itemObj, title) == TCL_ERROR)
15572 return(TCL_ERROR);
15573 if(peLdapStrlist(interp, itemObj, unit) == TCL_ERROR)
15574 return(TCL_ERROR);
15575 if(peLdapStrlist(interp, itemObj, org) == TCL_ERROR)
15576 return(TCL_ERROR);
15577 if(peLdapStrlist(interp, itemObj, mail) == TCL_ERROR)
15578 return(TCL_ERROR);
15579 if(Tcl_ListObjAppendElement(interp, resObj, itemObj) != TCL_OK)
15580 return(TCL_ERROR);
15581 if(title)
15582 ldap_value_free_len(title);
15583 if(unit)
15584 ldap_value_free_len(unit);
15585 if(org)
15586 ldap_value_free_len(org);
15587 if(mail)
15588 ldap_value_free_len(mail);
15591 if(Tcl_ListObjAppendElement(interp, secObj, resObj) != TCL_OK)
15592 return(TCL_ERROR);
15593 if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
15594 secObj) != TCL_OK)
15595 return(TCL_ERROR);
15597 return(TCL_OK);
15601 peLdapStrlist(Tcl_Interp *interp, Tcl_Obj *itemObj, struct berval **strl)
15603 Tcl_Obj *strlObj;
15604 int i;
15606 strlObj = Tcl_NewListObj(0, NULL);
15607 if(strl){
15608 for(i = 0; ALPINE_LDAP_usable(strl, i); i++){
15609 if(Tcl_ListObjAppendElement(interp, strlObj,
15610 Tcl_NewStringObj(strl[i]->bv_val, -1)) != TCL_OK)
15611 return(TCL_ERROR);
15614 if(Tcl_ListObjAppendElement(interp, itemObj, strlObj) != TCL_OK)
15615 return(TCL_ERROR);
15616 return(TCL_OK);
15621 init_ldap_pname(struct pine *ps)
15623 if(!wps_global->VAR_PERSONAL_NAME
15624 || wps_global->VAR_PERSONAL_NAME[0] == '\0'){
15625 char *pname;
15626 struct variable *vtmp;
15628 if(ps->maildomain && *ps->maildomain
15629 && ps->VAR_USER_ID && *ps->VAR_USER_ID){
15630 pname = peLdapPname(ps->VAR_USER_ID, ps->maildomain);
15631 if(pname){
15632 vtmp = &ps->vars[V_PERSONAL_NAME];
15633 if((vtmp->fixed_val.p && vtmp->fixed_val.p[0] == '\0')
15634 || (vtmp->is_fixed && !vtmp->fixed_val.p)){
15635 if(vtmp->fixed_val.p)
15636 fs_give((void **)&vtmp->fixed_val.p);
15637 vtmp->fixed_val.p = cpystr(pname);
15639 else {
15640 if(vtmp->global_val.p)
15641 fs_give((void **)&vtmp->global_val.p);
15642 vtmp->global_val.p = cpystr(pname);
15644 fs_give((void **)&pname);
15645 set_current_val(vtmp, FALSE, FALSE);
15649 return 0;
15651 #endif /* ENABLE_LDAP */
15654 * Note: this is taken straight out of pico/composer.c
15656 * strqchr - returns pointer to first non-quote-enclosed occurance of ch in
15657 * the given string. otherwise NULL.
15658 * s -- the string
15659 * ch -- the character we're looking for
15660 * q -- q tells us if we start out inside quotes on entry and is set
15661 * correctly on exit.
15662 * m -- max characters we'll check for ch (set to -1 for no check)
15664 char *
15665 strqchr(char *s, int ch, int *q, int m)
15667 int quoted = (q) ? *q : 0;
15669 for(; s && *s && m != 0; s++, m--){
15670 if(*s == '"'){
15671 quoted = !quoted;
15672 if(q)
15673 *q = quoted;
15676 if(!quoted && *s == ch)
15677 return(s);
15680 return(NULL);
15684 Tcl_Obj *
15685 wp_prune_folders(CONTEXT_S *ctxt,
15686 char *fcc,
15687 int cur_month,
15688 char *type,
15689 unsigned pr,
15690 int *ok,
15691 int moved_fldrs,
15692 Tcl_Interp *interp)
15694 Tcl_Obj *resObj = NULL, *secObj = NULL;
15695 char path2[MAXPATH+1], tmp[21];
15696 int exists, month_to_use;
15697 struct sm_folder *mail_list, *sm;
15699 mail_list = get_mail_list(ctxt, fcc);
15701 for(sm = mail_list; sm != NULL && sm->name != NULL; sm++)
15702 if(sm->month_num == cur_month - 1)
15703 break; /* matched a month */
15705 month_to_use = (sm == NULL || sm->name == NULL) ? cur_month - 1 : 0;
15707 if(!(month_to_use == 0 || pr == PRUNE_NO_AND_ASK || pr == PRUNE_NO_AND_NO)){
15708 strncpy(path2, fcc, sizeof(path2)-1);
15709 path2[sizeof(path2)-1] = '\0';
15710 strncpy(tmp, month_abbrev((month_to_use % 12)+1), sizeof(tmp)-1);
15711 tmp[sizeof(tmp)-1] = '\0';
15712 lcase((unsigned char *) tmp);
15713 snprintf(path2 + strlen(path2), sizeof(path2)-strlen(path2), "-%.20s-%d", tmp, month_to_use/12);
15715 if((exists = folder_exists(ctxt, fcc)) == FEX_ERROR){
15716 (*ok) = 0;
15717 return(NULL);
15719 else if(exists & FEX_ISFILE){
15720 if(pr == PRUNE_YES_AND_ASK || (pr == PRUNE_YES_AND_NO && !moved_fldrs)){
15721 prune_move_folder(fcc, path2, ctxt);
15722 } else {
15723 resObj = Tcl_NewListObj(0, NULL);
15724 Tcl_ListObjAppendElement(interp, resObj, Tcl_NewStringObj(type, -1));
15725 secObj = Tcl_NewListObj(0, NULL);
15726 Tcl_ListObjAppendElement(interp, secObj, Tcl_NewStringObj(fcc, -1));
15727 Tcl_ListObjAppendElement(interp, secObj, Tcl_NewStringObj(path2, -1));
15728 Tcl_ListObjAppendElement(interp, resObj, secObj);
15732 if(pr == PRUNE_ASK_AND_ASK || pr == PRUNE_YES_AND_ASK
15733 || pr == PRUNE_NO_AND_ASK){
15734 sm = mail_list;
15735 if(!resObj && sm && sm->name && sm->name[0] != '\0'){
15736 resObj = Tcl_NewListObj(0, NULL);
15737 Tcl_ListObjAppendElement(interp, resObj, Tcl_NewStringObj(type, -1));
15738 Tcl_ListObjAppendElement(interp, resObj, Tcl_NewListObj(0, NULL));
15740 if(resObj)
15741 secObj = Tcl_NewListObj(0, NULL);
15742 for(sm = mail_list; sm != NULL && sm->name != NULL; sm++){
15743 if(sm->name[0] == '\0') /* can't happen */
15744 continue;
15745 Tcl_ListObjAppendElement(interp, secObj, Tcl_NewStringObj(sm->name, -1));
15747 if(resObj)
15748 Tcl_ListObjAppendElement(interp, resObj, secObj);
15749 } else if(resObj)
15750 Tcl_ListObjAppendElement(interp, resObj, Tcl_NewListObj(0, NULL));
15752 free_folder_list(ctxt);
15754 if((sm = mail_list) != NULL){
15755 while(sm->name){
15756 fs_give((void **)&(sm->name));
15757 sm++;
15760 fs_give((void **)&mail_list);
15763 return(resObj);
15768 hex_colorstr(char *hexcolor, char *str)
15770 char *tstr, *p, *p2, tbuf[256];
15771 int i;
15773 strcpy(hexcolor, "000000");
15774 tstr = color_to_asciirgb(str);
15775 p = tstr;
15776 p2 = strindex(p, ',');
15777 if(p2 == NULL) return 0;
15778 strncpy(tbuf, p, min(50, p2-p));
15779 i = atoi(tbuf);
15780 sprintf(hexcolor, "%2.2x", i);
15781 p = p2+1;
15782 p2 = strindex(p, ',');
15783 if(p2 == NULL) return 0;
15784 strncpy(tbuf, p, min(50, p2-p));
15785 i = atoi(tbuf);
15786 sprintf(hexcolor+2, "%2.2x", i);
15787 p = p2+1;
15788 strncpy(tbuf, p, 50);
15789 i = atoi(tbuf);
15790 sprintf(hexcolor+4, "%2.2x", i);
15792 return 0;
15796 hexval(char ch)
15798 if(ch >= '0' && ch <= '9')
15799 return (ch - '0');
15800 else if (ch >= 'A' && ch <= 'F')
15801 return (10 + (ch - 'A'));
15802 else if (ch >= 'a' && ch <= 'f')
15803 return (10 + (ch - 'a'));
15804 return -1;
15808 ascii_colorstr(char *acolor, char *hexcolor)
15810 int i, hv;
15812 if(strlen(hexcolor) > 6) return 1;
15813 /* red value */
15814 if((hv = hexval(hexcolor[0])) == -1) return 1;
15815 i = 16 * hv;
15816 if((hv = hexval(hexcolor[1])) == -1) return 1;
15817 i += hv;
15818 sprintf(acolor, "%3.3d,", i);
15819 /* green value */
15820 if((hv = hexval(hexcolor[2])) == -1) return 1;
15821 i = 16 * hv;
15822 if((hv = hexval(hexcolor[3])) == -1) return 1;
15823 i += hv;
15824 sprintf(acolor+4, "%3.3d,", i);
15825 /* blue value */
15826 if((hv = hexval(hexcolor[4])) == -1) return 1;
15827 i = 16 * hv;
15828 if((hv = hexval(hexcolor[5])) == -1) return 1;
15829 i += hv;
15830 sprintf(acolor+8, "%3.3d", i);
15832 return 0;
15836 char *
15837 peRandomString(char *b, int l, int f)
15839 static char *kb = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
15840 char *s = b;
15841 int j;
15842 long n;
15844 while(1){
15845 n = random();
15846 for(j = 0; j < ((sizeof(long) * 8) / 5); j++){
15847 if(l-- <= 0){
15848 *s = '\0';
15849 return(b);
15852 switch(f){
15853 case PRS_LOWER_CASE :
15854 *s++ = (char) tolower((unsigned char) kb[(n & 0x1F)]);
15855 break;
15857 case PRS_MIXED_CASE :
15858 if(random() % 2){
15859 *s++ = (char) tolower((unsigned char) kb[(n & 0x1F)]);
15860 break;
15863 default :
15864 *s++ = kb[(n & 0x1F)];
15865 break;
15868 n = n >> 5;
15874 long
15875 peAppendMsg(MAILSTREAM *stream, void *data, char **flags, char **date, STRING **message)
15877 char *t,*t1,tmp[MAILTMPLEN];
15878 unsigned long u;
15879 MESSAGECACHE *elt;
15880 APPEND_PKG *ap = (APPEND_PKG *) data;
15881 *flags = *date = NIL; /* assume no flags or date */
15882 if (ap->flags) fs_give ((void **) &ap->flags);
15883 if (ap->date) fs_give ((void **) &ap->date);
15884 mail_gc (ap->stream,GC_TEXTS);
15885 if (++ap->msgno <= ap->msgmax) {
15886 /* initialize flag string */
15887 memset (t = tmp,0,MAILTMPLEN);
15888 /* output system flags */
15889 if ((elt = mail_elt (ap->stream,ap->msgno))->seen) {strncat (t," \\Seen", sizeof(tmp)-(t-tmp)-1); tmp[sizeof(tmp)-1] = '\0';}
15890 if (elt->deleted) {strncat (t," \\Deleted", sizeof(tmp)-(t-tmp)-1); tmp[sizeof(tmp)-1] = '\0';}
15891 if (elt->flagged) {strncat (t," \\Flagged", sizeof(tmp)-(t-tmp)-1); tmp[sizeof(tmp)-1] = '\0';}
15892 if (elt->answered) {strncat (t," \\Answered", sizeof(tmp)-(t-tmp)-1); tmp[sizeof(tmp)-1] = '\0';}
15893 if (elt->draft) {strncat (t," \\Draft", sizeof(tmp)-(t-tmp)-1); tmp[sizeof(tmp)-1] = '\0';}
15894 if ((u = elt->user_flags) != 0L) do /* any user flags? */
15895 if ((MAILTMPLEN - ((t += strlen (t)) - tmp)) > (long)
15896 (2 + strlen
15897 (t1 = ap->stream->user_flags[find_rightmost_bit (&u)]))) {
15898 if(t-tmp < sizeof(tmp))
15899 *t++ = ' '; /* space delimiter */
15900 strncpy (t,t1,sizeof(tmp)-(t-tmp)); /* copy the user flag */
15902 while (u); /* until no more user flags */
15903 tmp[sizeof(tmp)-1] = '\0';
15904 *flags = ap->flags = cpystr (tmp + 1);
15905 *date = ap->date = cpystr (mail_date (tmp,elt));
15906 *message = ap->message; /* message stringstruct */
15907 INIT (ap->message,mstring,(void *) ap,elt->rfc822_size);
15909 else *message = NIL; /* all done */
15910 return LONGT;
15914 /* Initialize file string structure for file stringstruct
15915 * Accepts: string structure
15916 * pointer to message data structure
15917 * size of string
15920 void
15921 ms_init(STRING *s, void *data, unsigned long size)
15923 APPEND_PKG *md = (APPEND_PKG *) data;
15924 s->data = data; /* note stream/msgno and header length */
15925 mail_fetchheader_full (md->stream,md->msgno,NIL,&s->data1,FT_PREFETCHTEXT);
15926 mail_fetchtext_full (md->stream,md->msgno,&s->size,NIL);
15927 s->size += s->data1; /* header + body size */
15928 SETPOS (s,0);
15932 /* Get next character from file stringstruct
15933 * Accepts: string structure
15934 * Returns: character, string structure chunk refreshed
15936 char
15937 ms_next(STRING *s)
15939 char c = *s->curpos++; /* get next byte */
15940 SETPOS (s,GETPOS (s)); /* move to next chunk */
15941 return c; /* return the byte */
15945 /* Set string pointer position for file stringstruct
15946 * Accepts: string structure
15947 * new position
15949 void
15950 ms_setpos(STRING *s, unsigned long i)
15952 APPEND_PKG *md = (APPEND_PKG *) s->data;
15953 if (i < s->data1) { /* want header? */
15954 s->chunk = mail_fetchheader (md->stream,md->msgno);
15955 s->chunksize = s->data1; /* header length */
15956 s->offset = 0; /* offset is start of message */
15958 else if (i < s->size) { /* want body */
15959 s->chunk = mail_fetchtext (md->stream,md->msgno);
15960 s->chunksize = s->size - s->data1;
15961 s->offset = s->data1; /* offset is end of header */
15963 else { /* off end of message */
15964 s->chunk = NIL; /* make sure that we crack on this then */
15965 s->chunksize = 1; /* make sure SNX cracks the right way... */
15966 s->offset = i;
15968 /* initial position and size */
15969 s->curpos = s->chunk + (i -= s->offset);
15970 s->cursize = s->chunksize - i;
15975 remote_pinerc_failure(void)
15977 snprintf(wps_global->last_error, sizeof(wps_global->last_error), "%s",
15978 wps_global->c_client_error[0]
15979 ? wps_global->c_client_error
15980 : _("Unable to read remote configuration"));
15982 return(TRUE);
15985 char *
15986 peWebAlpinePrefix(void)
15988 return("Web ");
15992 void peNewMailAnnounce(MAILSTREAM *stream, long n, long t_nm_count){
15993 char subject[MAILTMPLEN+1], subjtext[MAILTMPLEN+1], from[MAILTMPLEN+1],
15994 *folder = NULL, intro[MAILTMPLEN+1];
15995 long number;
15996 ENVELOPE *e = NULL;
15997 Tcl_Obj *resObj;
15999 if(n && (resObj = Tcl_NewListObj(0, NULL)) != NULL){
16001 Tcl_ListObjAppendElement(peED.interp, resObj, Tcl_NewLongObj(number = sp_mail_since_cmd(stream)));
16002 Tcl_ListObjAppendElement(peED.interp, resObj, Tcl_NewLongObj(mail_uid(stream, n)));
16004 if(stream){
16005 e = pine_mail_fetchstructure(stream, n, NULL);
16007 if(sp_flagged(stream, SP_INBOX))
16008 folder = NULL;
16009 else{
16010 folder = STREAMNAME(stream);
16011 if(folder[0] == '?' && folder[1] == '\0')
16012 folder = NULL;
16016 format_new_mail_msg(folder, number, e, intro, from, subject, subjtext, sizeof(intro));
16018 snprintf(wtmp_20k_buf, SIZEOF_20KBUF,
16019 "%s%s%s%.80s%.80s", intro,
16020 from ? ((number > 1L) ? " Most recent f" : " F") : "",
16021 from ? "rom " : "",
16022 from ? from : "",
16023 subjtext);
16025 Tcl_ListObjAppendElement(peED.interp, resObj, Tcl_NewStringObj(wtmp_20k_buf,-1));
16027 Tcl_ListObjAppendElement(peED.interp, Tcl_GetObjResult(peED.interp), resObj);
16032 /* * * * * * * * * RSS 2.0 Support Routines * * * * * * * * * * * */
16035 * PERssCmd - RSS TCL interface
16038 PERssCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
16040 char *s1;
16042 dprint((2, "PERssCmd"));
16044 if(objc == 1){
16045 Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?");
16046 return(TCL_ERROR);
16048 s1 = Tcl_GetStringFromObj(objv[1], NULL);
16050 if(s1){
16051 if(!strcmp(s1, "news")){
16052 return(peRssReturnFeed(interp, "news", wps_global->VAR_RSS_NEWS));
16054 else if(!strcmp(s1, "weather")){
16055 return(peRssReturnFeed(interp, "weather", wps_global->VAR_RSS_WEATHER));
16059 Tcl_SetResult(interp, "Unknown PERss command", TCL_STATIC);
16060 return(TCL_ERROR);
16064 * peRssReturnFeed - fetch feed contents and package Tcl response
16067 peRssReturnFeed(Tcl_Interp *interp, char *type, char *link)
16069 RSS_FEED_S *feed;
16070 char *errstr = "UNKNOWN";
16072 if(link){
16073 wps_global->c_client_error[0] = '\0';
16075 if((feed = peRssFeed(interp, type, link)) != NULL)
16076 return(peRssPackageFeed(interp, feed));
16078 if(wps_global->mm_log_error)
16079 errstr = wps_global->c_client_error;
16081 else
16082 errstr = "missing setting";
16084 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "%s feed fail: %s", type, errstr);
16085 Tcl_SetResult(interp, wtmp_20k_buf, TCL_VOLATILE);
16086 return(TCL_ERROR);
16090 * peRssPackageFeed - build a list of feed item elements
16092 * LIST ORDER: {title} {link} {description} {image}
16095 peRssPackageFeed(Tcl_Interp *interp, RSS_FEED_S *feed)
16097 RSS_ITEM_S *item;
16099 for(item = feed->items; item; item = item->next)
16100 if(peAppListF(interp, Tcl_GetObjResult(interp), "%s %s %s %s",
16101 (item->title && *item->title)? item->title : "Feed Provided No Title",
16102 item->link ? item->link : "",
16103 item->description ? item->description : "",
16104 feed->image ? feed->image : "") != TCL_OK)
16105 return(TCL_ERROR);
16107 return(TCL_OK);
16112 * peRssFeed - return cached feed struct or fetch a new one
16114 RSS_FEED_S *
16115 peRssFeed(Tcl_Interp *interp, char *type, char *link)
16117 int i, cache_l, cp_ref;
16118 time_t now = time(0);
16119 RSS_FEED_S *feed = NULL;
16120 RSS_CACHE_S *cache, *cp;
16121 static RSS_CACHE_S news_cache[RSS_NEWS_CACHE_SIZE], weather_cache[RSS_WEATHER_CACHE_SIZE];
16123 if(!strucmp(type,"news")){
16124 cache = &news_cache[0];
16125 cache_l = RSS_NEWS_CACHE_SIZE;
16127 else{
16128 cache = &weather_cache[0];
16129 cache_l = RSS_WEATHER_CACHE_SIZE;
16132 /* search/purge cache */
16133 for(i = 0; i < cache_l; i++)
16134 if(cache[i].link){
16135 if(now > cache[i].stale){
16136 peRssClearCacheEntry(&cache[i]);
16138 else if(!strcmp(link, cache[i].link)){
16139 cache[i].referenced++;
16140 return(cache[i].feed); /* HIT! */
16144 if((feed = peRssFetch(interp, link)) != NULL){
16145 /* find cache slot, and insert feed into cache */
16146 for(i = 0, cp_ref = 0; i < cache_l; i++)
16147 if(!cache[i].feed){
16148 cp = &cache[i];
16149 break;
16151 else if(cache[i].referenced >= cp_ref)
16152 cp = &cache[i];
16154 if(!cp)
16155 cp = &cache[0]; /* failsafe */
16157 peRssClearCacheEntry(cp); /* make sure */
16159 cp->link = cpystr(link);
16160 cp->feed = feed;
16161 cp->referenced = 0;
16162 cp->stale = now + (((feed->ttl > 0) ? feed->ttl : 60) * 60);
16165 return(feed);
16169 * peRssFetch - follow the provided link an return the resulting struct
16171 RSS_FEED_S *
16172 peRssFetch(Tcl_Interp *interp, char *link)
16174 char *scheme = NULL, *loc = NULL, *path = NULL, *parms = NULL, *query = NULL, *frag = NULL;
16175 char *buffer = NULL, *bp, *p, *q;
16176 int ttl = 60;
16177 unsigned long port = 0L, buffer_len = 0L;
16178 time_t theirdate = 0;
16179 STORE_S *feed_so = NULL;
16180 TCPSTREAM *tcp_stream;
16182 if(link){
16183 /* grok url */
16184 rfc1808_tokens(link, &scheme, &loc, &path, &parms, &query, &frag);
16185 if(scheme && loc && path){
16186 if((p = strchr(loc,':')) != NULL){
16187 *p++ = '\0';
16188 while(*p && isdigit((unsigned char) *p))
16189 port = ((port * 10) + (*p++ - '0'));
16191 if(*p){
16192 Tcl_SetResult(interp, "Bad RSS port number", TCL_STATIC);
16193 peRssComponentFree(&scheme,&loc,&path,&parms,&query,&frag);
16194 return(NULL);
16198 if(scheme && !strucmp(scheme, "feed")){
16199 fs_give((void **) &scheme);
16200 scheme = cpystr("http");
16203 mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long) 5);
16204 tcp_stream = tcp_open (loc, scheme, port | NET_NOOPENTIMEOUT);
16205 mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long) 30);
16207 if(tcp_stream != NULL){
16208 char rev[128];
16210 snprintf(wtmp_20k_buf, SIZEOF_20KBUF, "GET /%s%s%s%s%s HTTP/1.1\r\nHost: %s\r\nAccept: application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nUser-Agent: Web-Alpine/%s (%s %s)\r\n\r\n",
16211 path, parms ? ":" : "", parms ? parms : "",
16212 query ? "?" : "", query ? query : "", loc,
16213 ALPINE_VERSION, SYSTYPE, get_alpine_revision_string(rev, sizeof(rev)));
16215 mail_parameters(NULL, SET_WRITETIMEOUT, (void *)(long) 5);
16216 mail_parameters(NULL, SET_READTIMEOUT, (void *)(long) 5);
16218 if(tcp_sout(tcp_stream, wtmp_20k_buf, strlen(wtmp_20k_buf))){
16219 int ok = 0, chunked = FALSE;
16221 while((p = tcp_getline(tcp_stream)) != NULL){
16222 if(!ok){
16223 ok++;
16224 if(strucmp(p,"HTTP/1.1 200 OK")){
16225 fs_give((void **) &p);
16226 break; /* bail */
16229 else if(*p == '\0'){ /* first blank line, start of body */
16230 if(buffer || feed_so){
16231 fs_give((void **) &p);
16232 break; /* bail */
16235 if(buffer_len){
16236 buffer = fs_get(buffer_len + 16);
16237 if(!tcp_getbuffer(tcp_stream, buffer_len, buffer))
16238 fs_give((void **) &buffer);
16240 fs_give((void **) &p);
16241 break; /* bail */
16243 else if((feed_so = so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){
16244 fs_give((void **) &p);
16245 break; /* bail */
16248 else if(feed_so){ /* collect body */
16249 if(chunked){
16250 int chunk_len = 0, gotbuf;
16252 /* first line is chunk size in hex */
16253 for(q = p; *q && isxdigit((unsigned char) *q); q++)
16254 chunk_len = (chunk_len * 16) + XDIGIT2C(*q);
16256 if(chunk_len > 0){ /* collect chunk */
16257 char *tbuf = fs_get(chunk_len + 16);
16258 gotbuf = tcp_getbuffer(tcp_stream, chunk_len, tbuf);
16259 if(gotbuf)
16260 so_nputs(feed_so, tbuf, chunk_len);
16262 fs_give((void **) &tbuf);
16264 if(!gotbuf){
16265 fs_give((void **) &p);
16266 break; /* bail */
16270 /* collect trailing CRLF */
16271 gotbuf = ((q = tcp_getline(tcp_stream)) != NULL && *q == '\0');
16272 if(q)
16273 fs_give((void **) &q);
16275 if(chunk_len == 0 || !gotbuf){
16276 fs_give((void **) &p);
16277 break; /* bail */
16280 else
16281 so_puts(feed_so, p);
16283 else{ /* in header, grok fields */
16284 if((q = strchr(p,':')) != NULL){
16285 int l = q - p;
16287 *q++ = '\0';
16288 while(isspace((unsigned char ) *q))
16289 q++;
16291 /* content-length */
16292 if(l == 4 && !strucmp(p, "date")){
16293 theirdate = date_to_local_time_t(q);
16295 else if(l == 7 && !strucmp(p, "expires")){
16296 time_t expires = date_to_local_time_t(q) - ((theirdate > 0) ? theirdate : time(0));
16298 if(expires > 0 && expires < (8 * 60 * 60))
16299 ttl = expires;
16301 else if(l == 12 && !strucmp(p, "content-type")
16302 && struncmp(q,"text/xml", 8)
16303 && struncmp(q,"application/xhtml+xml", 21)
16304 && struncmp(q,"application/rss+xml", 19)
16305 && struncmp(q,"application/xml", 15)){
16306 fs_give((void **) &p);
16307 break; /* bail */
16309 else if(l == 13 && !strucmp(p, "cache-control")){
16310 if(!struncmp(q,"max-age=",8)){
16311 int secs = 0;
16313 for(q += 8; *q && isdigit((unsigned char) *q); q++)
16314 secs = ((secs * 10) + (*q - '0'));
16316 if(secs > 0)
16317 ttl = secs;
16320 else if(l == 14 && !strucmp(p,"content-length")){
16321 while(*q && isdigit((unsigned char) *q))
16322 buffer_len = ((buffer_len * 10) + (*q++ - '0'));
16324 if(*q){
16325 fs_give((void **) &p);
16326 break; /* bail */
16329 else if(l == 17 && !strucmp(p, "transfer-encoding")){
16330 if(!struncmp(q,"chunked", 7)){
16331 chunked = TRUE;
16333 else{ /* unknown encoding */
16334 fs_give((void **) &p);
16335 break; /* bail */
16341 fs_give((void **) &p);
16344 else{
16345 Tcl_SetResult(interp, "RSS send failure", TCL_STATIC);
16346 peRssComponentFree(&scheme,&loc,&path,&parms,&query,&frag);
16349 tcp_close(tcp_stream);
16350 mail_parameters(NULL, SET_READTIMEOUT, (void *)(long) 60);
16351 mail_parameters(NULL, SET_WRITETIMEOUT, (void *)(long) 60);
16352 peRssComponentFree(&scheme,&loc,&path,&parms,&query,&frag);
16354 if(feed_so){
16355 buffer = (char *) so_text(feed_so);
16356 buffer_len = (int) so_tell(feed_so);
16359 if(buffer && buffer_len){
16360 RSS_FEED_S *feed;
16361 char *err;
16362 STORE_S *bucket;
16363 gf_io_t gc, pc;
16365 /* grok response */
16366 bucket = so_get(CharStar, NULL, EDIT_ACCESS);
16367 gf_set_readc(&gc, buffer, buffer_len, CharStar, 0);
16368 gf_set_so_writec(&pc, bucket);
16369 gf_filter_init();
16370 gf_link_filter(gf_html2plain, gf_html2plain_rss_opt(&feed,0));
16371 if((err = gf_pipe(gc, pc)) != NULL){
16372 gf_html2plain_rss_free(&feed);
16373 Tcl_SetResult(interp, "RSS connection failure", TCL_STATIC);
16376 so_give(&bucket);
16378 if(feed_so)
16379 so_give(&feed_so);
16380 else
16381 fs_give((void **) &buffer);
16383 return(feed);
16385 else
16386 Tcl_SetResult(interp, "RSS response error", TCL_STATIC);
16388 else
16389 Tcl_SetResult(interp, "RSS connection failure", TCL_STATIC);
16391 else
16392 Tcl_SetResult(interp, "RSS feed missing scheme", TCL_STATIC);
16394 else
16395 Tcl_SetResult(interp, "No RSS Feed Defined", TCL_STATIC);
16397 return(NULL);
16401 void
16402 peRssComponentFree(char **scheme,char **loc,char **path,char **parms,char **query,char **frag)
16404 if(scheme) fs_give((void **) scheme);
16405 if(loc) fs_give((void **) loc);
16406 if(path) fs_give((void **) path);
16407 if(parms) fs_give((void **) parms);
16408 if(query) fs_give((void **) query);
16409 if(frag) fs_give((void **) frag);
16412 void
16413 peRssClearCacheEntry(RSS_CACHE_S *entry)
16415 if(entry){
16416 if(entry->link)
16417 fs_give((void **) &entry->link);
16419 gf_html2plain_rss_free(&entry->feed);
16420 memset(entry, 0, sizeof(RSS_CACHE_S));