1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1 |
#if !defined(lint) && !defined(DOS)
|
1.1.8
by Asheesh Laroia
Import upstream version 2.02 |
2 |
static char rcsid[] = "$Id: send.c 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $"; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3 |
#endif
|
4 |
||
5 |
/*
|
|
6 |
* ========================================================================
|
|
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
7 |
* Copyright 2006-2008 University of Washington
|
1.1.10
by Asheesh Laroia
Import upstream version 2.10+dfsg |
8 |
* Copyright 2013 Eduardo Chappa
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
9 |
*
|
10 |
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
11 |
* you may not use this file except in compliance with the License.
|
|
12 |
* You may obtain a copy of the License at
|
|
13 |
*
|
|
14 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
15 |
*
|
|
16 |
* ========================================================================
|
|
17 |
*/
|
|
18 |
||
19 |
#include "../pith/headers.h" |
|
20 |
#include "../pith/send.h" |
|
21 |
#include "../pith/state.h" |
|
22 |
#include "../pith/conf.h" |
|
23 |
#include "../pith/store.h" |
|
24 |
#include "../pith/mimedesc.h" |
|
25 |
#include "../pith/context.h" |
|
26 |
#include "../pith/status.h" |
|
27 |
#include "../pith/folder.h" |
|
28 |
#include "../pith/bldaddr.h" |
|
29 |
#include "../pith/pipe.h" |
|
30 |
#include "../pith/mailview.h" |
|
31 |
#include "../pith/mailindx.h" |
|
32 |
#include "../pith/list.h" |
|
33 |
#include "../pith/filter.h" |
|
34 |
#include "../pith/reply.h" |
|
35 |
#include "../pith/addrstring.h" |
|
36 |
#include "../pith/rfc2231.h" |
|
37 |
#include "../pith/stream.h" |
|
38 |
#include "../pith/util.h" |
|
39 |
#include "../pith/adrbklib.h" |
|
40 |
#include "../pith/options.h" |
|
41 |
#include "../pith/busy.h" |
|
42 |
#include "../pith/text.h" |
|
43 |
#include "../pith/imap.h" |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
44 |
#include "../pith/ablookup.h" |
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
45 |
#include "../pith/sort.h" |
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
46 |
#include "../pith/smime.h" |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
47 |
|
48 |
#include "../c-client/smtp.h" |
|
49 |
#include "../c-client/nntp.h" |
|
50 |
||
51 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
52 |
/* this is used in pine_send and pine_simple_send */
|
53 |
/* name::type::canedit::writehdr::localcopy::rcptto */
|
|
54 |
PINEFIELD pf_template[] = { |
|
55 |
{"X-Auth-Received", FreeText, 0, 1, 1, 0}, /* N_AUTHRCVD */ |
|
56 |
{"From", Address, 0, 1, 1, 0}, |
|
57 |
{"Reply-To", Address, 0, 1, 1, 0}, |
|
58 |
{TONAME, Address, 1, 1, 1, 1}, |
|
59 |
{CCNAME, Address, 1, 1, 1, 1}, |
|
60 |
{"bcc", Address, 1, 0, 1, 1}, |
|
61 |
{"Newsgroups", FreeText, 1, 1, 1, 0}, |
|
62 |
{"Fcc", Fcc, 1, 0, 0, 0}, |
|
63 |
{"Lcc", Address, 1, 0, 1, 1}, |
|
64 |
{"Attchmnt", Attachment, 1, 1, 1, 0}, |
|
65 |
{SUBJNAME, Subject, 1, 1, 1, 0}, |
|
66 |
{"References", FreeText, 0, 1, 1, 0}, |
|
67 |
{"Date", FreeText, 0, 1, 1, 0}, |
|
68 |
{"In-Reply-To", FreeText, 0, 1, 1, 0}, |
|
69 |
{"Message-ID", FreeText, 0, 1, 1, 0}, |
|
70 |
{PRIORITYNAME, FreeText, 0, 1, 1, 0}, |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
71 |
{"User-Agent", FreeText, 0, 1, 1, 0}, |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
72 |
{"To", Address, 0, 0, 0, 0}, /* N_NOBODY */ |
73 |
{"X-Post-Error",FreeText, 0, 0, 0, 0}, /* N_POSTERR */ |
|
74 |
{"X-Reply-UID", FreeText, 0, 0, 0, 0}, /* N_RPLUID */ |
|
75 |
{"X-Reply-Mbox",FreeText, 0, 0, 0, 0}, /* N_RPLMBOX */ |
|
76 |
{"X-SMTP-Server",FreeText, 0, 0, 0, 0}, /* N_SMTP */ |
|
77 |
{"X-NNTP-Server",FreeText, 0, 0, 0, 0}, /* N_NNTP */ |
|
78 |
{"X-Cursor-Pos",FreeText, 0, 0, 0, 0}, /* N_CURPOS */ |
|
79 |
{"X-Our-ReplyTo",FreeText, 0, 0, 0, 0}, /* N_OURREPLYTO */ |
|
80 |
{OUR_HDRS_LIST, FreeText, 0, 0, 0, 0}, /* N_OURHDRS */ |
|
81 |
#if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
|
|
82 |
{"X-X-Sender", Address, 0, 1, 1, 0}, |
|
83 |
#endif
|
|
84 |
{NULL, FreeText} |
|
85 |
};
|
|
86 |
||
87 |
||
88 |
PRIORITY_S priorities[] = { |
|
89 |
{1, "Highest"}, |
|
90 |
{2, "High"}, |
|
91 |
{3, "Normal"}, |
|
92 |
{4, "Low"}, |
|
93 |
{5, "Lowest"}, |
|
94 |
{0, NULL} |
|
95 |
};
|
|
96 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
97 |
|
98 |
#define ctrl(c) ((c) & 0x1f)
|
|
99 |
||
100 |
/* which message part to test for xliteration */
|
|
101 |
typedef enum {MsgBody, HdrText} MsgPart; |
|
102 |
||
103 |
||
104 |
/*
|
|
105 |
* Internal prototypes
|
|
106 |
*/
|
|
107 |
long post_rfc822_output(char *, ENVELOPE *, BODY *, soutr_t, TCPSTREAM *, long); |
|
108 |
int l_flush_net(int); |
|
109 |
int l_putc(int); |
|
110 |
int pine_write_header_line(char *, char *, STORE_S *); |
|
111 |
int pine_write_params(PARAMETER *, STORE_S *); |
|
112 |
char *tidy_smtp_mess(char *, char *, char *, size_t); |
|
113 |
int lmc_body_header_line(char *, int); |
|
114 |
int lmc_body_header_finish(void); |
|
115 |
int pwbh_finish(int, STORE_S *); |
|
116 |
int sent_percent(void); |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
117 |
unsigned short *setup_avoid_table(void); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
118 |
#ifndef _WINDOWS
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
119 |
int mta_handoff(METAENV *, BODY *, char *, size_t, void (*)(char *, int), |
120 |
void (*)(PIPE_S *, int, void *)); |
|
121 |
char *post_handoff(METAENV *, BODY *, char *, size_t, void (*)(char *, int), |
|
122 |
void (*)(PIPE_S *, int, void *)); |
|
123 |
char *mta_parse_post(METAENV *, BODY *, char *, char *, size_t, void (*)(char *, int), |
|
124 |
void (*)(PIPE_S *, int, void *)); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
125 |
long pine_pipe_soutr_nl(void *, char *); |
126 |
#endif
|
|
127 |
char *smtp_command(char *, size_t); |
|
128 |
void *piped_smtp_open(char *, char *, unsigned long); |
|
129 |
void *piped_aopen(NETMBX *, char *, char *); |
|
130 |
long piped_soutr(void *, char *); |
|
131 |
long piped_sout(void *, char *, unsigned long); |
|
132 |
char *piped_getline(void *); |
|
133 |
void piped_close(void *); |
|
134 |
void piped_abort(void *); |
|
135 |
char *piped_host(void *); |
|
136 |
unsigned long piped_port(void *); |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
137 |
char *posting_characterset(void *, char *, MsgPart); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
138 |
int body_is_translatable(void *, char *); |
139 |
int text_is_translatable(void *, char *); |
|
140 |
int dummy_putc(int); |
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
141 |
unsigned long *init_charsetchecker(char *); |
142 |
int representable_in_charset(unsigned long, char *); |
|
143 |
char *most_preferred_charset(unsigned long); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
144 |
|
145 |
/*
|
|
146 |
* Storage object where the FCC (or postponed msg) is to be written.
|
|
147 |
* This is amazingly bogus. Much work was done to put messages
|
|
148 |
* together and encode them as they went to the tmp file for sendmail
|
|
149 |
* or into the SMTP slot (especially for for DOS, to prevent a temporary
|
|
150 |
* file (and needlessly copying the message).
|
|
151 |
*
|
|
152 |
* HOWEVER, since there's no piping into c-client routines
|
|
153 |
* (particularly mail_append() which copies the fcc), the fcc will have
|
|
154 |
* to be copied to disk. This global tells pine's copy of the rfc822
|
|
155 |
* output functions where to also write the message bytes for the fcc.
|
|
156 |
* With piping in the c-client we could just have two pipes to shove
|
|
157 |
* down rather than messing with damn copies. FIX THIS!
|
|
158 |
*
|
|
159 |
* The function open_fcc, locates the actual folder and creates it if
|
|
160 |
* requested before any mailing or posting is done.
|
|
161 |
*/
|
|
162 |
struct local_message_copy lmc; |
|
163 |
||
164 |
||
165 |
/*
|
|
166 |
* Locally global pointer to stream used for sending/posting.
|
|
167 |
* It's also used to indicate when/if we write the Bcc: field in
|
|
168 |
* the header.
|
|
169 |
*/
|
|
170 |
static SENDSTREAM *sending_stream = NULL; |
|
171 |
||
172 |
||
173 |
static struct hooks { |
|
174 |
void *rfc822_out; /* Message outputter */ |
|
175 |
} sending_hooks; |
|
176 |
||
177 |
||
178 |
static FILE *verbose_send_output = NULL; |
|
179 |
static long send_bytes_sent, send_bytes_to_send; |
|
180 |
static METAENV *send_header = NULL; |
|
181 |
||
182 |
/*
|
|
183 |
* Hooks for prompts and confirmations
|
|
184 |
*/
|
|
185 |
int (*pith_opt_daemon_confirm)(void); |
|
186 |
||
187 |
||
188 |
static NETDRIVER piped_io = { |
|
189 |
piped_smtp_open, /* open a connection */ |
|
190 |
piped_aopen, /* open an authenticated connection */ |
|
191 |
piped_getline, /* get a line */ |
|
192 |
NULL, /* get a buffer */ |
|
193 |
piped_soutr, /* output pushed data */ |
|
194 |
piped_sout, /* output string */ |
|
195 |
piped_close, /* close connection */ |
|
196 |
piped_host, /* return host name */ |
|
197 |
piped_host, /* remotehost */ |
|
198 |
piped_port, /* return port number */ |
|
199 |
piped_host /* return local host (NOTE: same as host!) */ |
|
200 |
};
|
|
201 |
||
202 |
||
203 |
/*
|
|
204 |
* Since c-client preallocates, it's necessary here to define a limit
|
|
205 |
* such that we don't blow up in c-client (see rfc822_address_line()).
|
|
206 |
*/
|
|
207 |
#define MAX_SINGLE_ADDR MAILTMPLEN
|
|
208 |
||
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
209 |
#define AVOID_2022_JP_FOR_PUNC "AVOID_2022_JP_FOR_PUNC"
|
210 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
211 |
|
212 |
/*
|
|
213 |
* Phone home hash controls
|
|
214 |
*/
|
|
215 |
#define PH_HASHBITS 24
|
|
216 |
#define PH_MAXHASH (1<<(PH_HASHBITS))
|
|
217 |
||
218 |
||
219 |
/*
|
|
220 |
* postponed_stream - return stream associated with postponed messages
|
|
221 |
* in argument.
|
|
222 |
*/
|
|
223 |
int
|
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
224 |
postponed_stream(MAILSTREAM **streamp, char *mbox, char *type, int checknmsgs) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
225 |
{
|
226 |
MAILSTREAM *stream = NULL; |
|
227 |
CONTEXT_S *p_cntxt = NULL; |
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
228 |
char *p, *q, tmp[MAILTMPLEN], *fullname = NULL; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
229 |
int exists; |
230 |
||
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
231 |
if(!(streamp && mbox)) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
232 |
return(0); |
233 |
||
234 |
*streamp = NULL; |
|
235 |
||
236 |
/*
|
|
237 |
* find default context to look for folder...
|
|
238 |
*
|
|
239 |
* The "mbox" is assumed to be local if we're given what looks
|
|
240 |
* like an absolute path. This is different from Goto/Save
|
|
241 |
* where we do alot of work to interpret paths relative to the
|
|
242 |
* server. This reason is to support all the pre-4.00 pinerc'
|
|
243 |
* that specified a path and because there's yet to be a way
|
|
244 |
* in c-client to specify otherwise in the face of a remote
|
|
245 |
* context.
|
|
246 |
*/
|
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
247 |
if(!is_absolute_path(mbox) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
248 |
&& !(p_cntxt = default_save_context(ps_global->context_list))) |
249 |
p_cntxt = ps_global->context_list; |
|
250 |
||
251 |
/* check to see if the folder exists, the user wants to continue
|
|
252 |
* and that we can actually read something in...
|
|
253 |
*/
|
|
254 |
exists = folder_name_exists(p_cntxt, mbox, &fullname); |
|
255 |
if(fullname) |
|
256 |
mbox = fullname; |
|
257 |
||
258 |
if(exists & FEX_ISFILE){ |
|
259 |
context_apply(tmp, p_cntxt, mbox, sizeof(tmp)); |
|
260 |
if(!(IS_REMOTE(tmp) || is_absolute_path(tmp))){ |
|
261 |
/*
|
|
262 |
* The mbox is relative to the home directory.
|
|
263 |
* Make it absolute so we can compare it to
|
|
264 |
* stream->mailbox.
|
|
265 |
*/
|
|
266 |
build_path(tmp_20k_buf, ps_global->ui.homedir, tmp, |
|
267 |
SIZEOF_20KBUF); |
|
268 |
strncpy(tmp, tmp_20k_buf, sizeof(tmp)); |
|
269 |
tmp[sizeof(tmp)-1] = '\0'; |
|
270 |
}
|
|
271 |
||
272 |
if((stream = ps_global->mail_stream) |
|
273 |
&& !(stream->mailbox |
|
274 |
&& ((*tmp != '{' && !strcmp(tmp, stream->mailbox)) |
|
275 |
|| (*tmp == '{' |
|
276 |
&& same_stream(tmp, stream) |
|
277 |
&& (p = strchr(tmp, '}')) |
|
278 |
&& (q = strchr(stream->mailbox,'}')) |
|
279 |
&& !strcmp(p + 1, q + 1))))) |
|
280 |
stream = NULL; |
|
281 |
||
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
282 |
if(!stream){ |
283 |
stream = context_open(p_cntxt, NULL, mbox, |
|
284 |
SP_USEPOOL|SP_TEMPUSE, NULL); |
|
285 |
if(stream && !stream->halfopen){ |
|
286 |
if(stream->nmsgs > 0) |
|
287 |
refresh_sort(stream, sp_msgmap(stream), SRT_NON); |
|
288 |
||
289 |
if(checknmsgs && stream->nmsgs < 1){ |
|
290 |
pine_mail_close(stream); |
|
291 |
exists = 0; |
|
292 |
stream = NULL; |
|
293 |
}
|
|
294 |
}
|
|
295 |
else{ |
|
296 |
q_status_message2(SM_ORDER | SM_DING, 3, 3, |
|
297 |
_("Can't open %s mailbox: %s"), type, mbox); |
|
298 |
if(stream) |
|
299 |
pine_mail_close(stream); |
|
300 |
||
301 |
exists = 0; |
|
302 |
stream = NULL; |
|
303 |
}
|
|
304 |
}
|
|
305 |
}
|
|
306 |
else{ |
|
307 |
if(F_ON(F_ALT_COMPOSE_MENU, ps_global)){ |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
308 |
q_status_message1(SM_ORDER | SM_DING, 3, 3, |
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
309 |
_("%s message folder doesn't exist!"), type); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
310 |
}
|
311 |
}
|
|
312 |
||
313 |
if(fullname) |
|
314 |
fs_give((void **) &fullname); |
|
315 |
||
316 |
*streamp = stream; |
|
317 |
||
318 |
return(exists); |
|
319 |
}
|
|
320 |
||
321 |
||
322 |
int
|
|
323 |
redraft_work(MAILSTREAM **streamp, long int cont_msg, ENVELOPE **outgoing, |
|
324 |
struct mail_bodystruct **body, char **fcc, char **lcc, |
|
325 |
REPLY_S **reply, REDRAFT_POS_S **redraft_pos, PINEFIELD **custom, |
|
326 |
ACTION_S **role, int flags, STORE_S *so) |
|
327 |
{
|
|
328 |
MAILSTREAM *stream; |
|
329 |
ENVELOPE *e = NULL; |
|
330 |
BODY *b; |
|
331 |
PART *part; |
|
332 |
PINEFIELD *pf; |
|
333 |
gf_io_t pc; |
|
334 |
char *extras, **fields, **values, *p; |
|
335 |
char *hdrs[2], *h, *charset; |
|
336 |
char **smtp_servers = NULL, **nntp_servers = NULL; |
|
337 |
int i, pine_generated = 0, our_replyto = 0; |
|
338 |
int added_to_role = 0; |
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
339 |
unsigned gbpt_flags = GBPT_NONE; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
340 |
MESSAGECACHE *mc; |
341 |
||
342 |
if(!(streamp && *streamp)) |
|
343 |
return(redraft_cleanup(streamp, TRUE, flags)); |
|
344 |
||
345 |
stream = *streamp; |
|
346 |
||
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
347 |
if(flags & REDRAFT_HTML) |
348 |
gbpt_flags |= GBPT_HTML_OK; |
|
349 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
350 |
/* grok any user-defined or non-c-client headers */
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
351 |
if((e = pine_mail_fetchstructure(stream, cont_msg, &b)) != NULL){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
352 |
|
353 |
/*
|
|
354 |
* The custom headers to look for in the suspended message should
|
|
355 |
* have been stored in the X-Our-Headers header. So first we get
|
|
356 |
* that list. If we can't find it (version that stored the
|
|
357 |
* message < 4.30) then we use the global custom list.
|
|
358 |
*/
|
|
359 |
hdrs[0] = OUR_HDRS_LIST; |
|
360 |
hdrs[1] = NULL; |
|
361 |
if((h = pine_fetchheader_lines(stream, cont_msg, NULL, hdrs)) != NULL){ |
|
362 |
int commas = 0; |
|
363 |
char **list; |
|
364 |
char *hdrval = NULL; |
|
365 |
||
366 |
if((hdrval = strindex(h, ':')) != NULL){ |
|
367 |
for(hdrval++; *hdrval && isspace((unsigned char)*hdrval); |
|
368 |
hdrval++) |
|
369 |
;
|
|
370 |
}
|
|
371 |
||
372 |
/* count elements in list */
|
|
373 |
for(p = hdrval; p && *p; p++) |
|
374 |
if(*p == ',') |
|
375 |
commas++; |
|
376 |
||
377 |
if(hdrval && (list = parse_list(hdrval,commas+1,0,NULL)) != NULL){ |
|
378 |
||
379 |
*custom = parse_custom_hdrs(list, Replace); |
|
380 |
add_defaults_from_list(*custom, |
|
381 |
ps_global->VAR_CUSTOM_HDRS); |
|
382 |
free_list_array(&list); |
|
383 |
}
|
|
384 |
||
385 |
if(*custom && !(*custom)->name){ |
|
386 |
free_customs(*custom); |
|
387 |
*custom = NULL; |
|
388 |
}
|
|
389 |
||
390 |
fs_give((void **)&h); |
|
391 |
}
|
|
392 |
||
393 |
if(!*custom) |
|
394 |
*custom = parse_custom_hdrs(ps_global->VAR_CUSTOM_HDRS, UseAsDef); |
|
395 |
||
396 |
#define INDEX_FCC 0
|
|
397 |
#define INDEX_POSTERR 1
|
|
398 |
#define INDEX_REPLYUID 2
|
|
399 |
#define INDEX_REPLYMBOX 3
|
|
400 |
#define INDEX_SMTP 4
|
|
401 |
#define INDEX_NNTP 5
|
|
402 |
#define INDEX_CURSORPOS 6
|
|
403 |
#define INDEX_OUR_REPLYTO 7
|
|
404 |
#define INDEX_LCC 8 /* MUST REMAIN LAST FIELD DECLARED */ |
|
405 |
#define FIELD_COUNT 9
|
|
406 |
||
407 |
i = count_custom_hdrs_pf(*custom,1) + FIELD_COUNT + 1; |
|
408 |
||
409 |
/*
|
|
410 |
* Having these two fields separated isn't the slickest, but
|
|
411 |
* converting the pointer array for fetchheader_lines() to
|
|
412 |
* a list of structures or some such for simple_header_parse()
|
|
413 |
* is too goonie. We could do something like re-use c-client's
|
|
414 |
* PARAMETER struct which is a simple char * pairing, but that
|
|
415 |
* doesn't make sense to pass to fetchheader_lines()...
|
|
416 |
*/
|
|
417 |
fields = (char **) fs_get((size_t) i * sizeof(char *)); |
|
418 |
values = (char **) fs_get((size_t) i * sizeof(char *)); |
|
419 |
memset(fields, 0, (size_t) i * sizeof(char *)); |
|
420 |
memset(values, 0, (size_t) i * sizeof(char *)); |
|
421 |
||
422 |
fields[i = INDEX_FCC] = "Fcc"; /* Fcc: special case */ |
|
423 |
fields[++i] = "X-Post-Error"; /* posting errors too */ |
|
424 |
fields[++i] = "X-Reply-UID"; /* Reply'd to msg's UID */ |
|
425 |
fields[++i] = "X-Reply-Mbox"; /* Reply'd to msg's Mailbox */ |
|
426 |
fields[++i] = "X-SMTP-Server";/* SMTP server to use */ |
|
427 |
fields[++i] = "X-NNTP-Server";/* NNTP server to use */ |
|
428 |
fields[++i] = "X-Cursor-Pos"; /* Cursor position */ |
|
429 |
fields[++i] = "X-Our-ReplyTo"; /* ReplyTo is real */ |
|
430 |
fields[++i] = "Lcc"; /* Lcc: too... */ |
|
431 |
if(++i != FIELD_COUNT) |
|
432 |
panic("Fix FIELD_COUNT"); |
|
433 |
||
434 |
for(pf = *custom; pf && pf->name; pf = pf->next) |
|
435 |
if(!pf->standard) |
|
436 |
fields[i++] = pf->name; /* assign custom fields */ |
|
437 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
438 |
if((extras = pine_fetchheader_lines(stream, cont_msg, NULL,fields)) != NULL){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
439 |
simple_header_parse(extras, fields, values); |
440 |
fs_give((void **) &extras); |
|
441 |
||
442 |
/*
|
|
443 |
* translate RFC 1522 strings,
|
|
444 |
* starting with "Lcc" field
|
|
445 |
*/
|
|
446 |
for(i = INDEX_LCC; fields[i]; i++) |
|
447 |
if(values[i]){ |
|
448 |
size_t len; |
|
449 |
char *bufp, *biggerbuf = NULL; |
|
450 |
||
451 |
if((len=4*strlen(values[i])) > SIZEOF_20KBUF-1){ |
|
452 |
len++; |
|
453 |
biggerbuf = (char *)fs_get(len * sizeof(char)); |
|
454 |
bufp = biggerbuf; |
|
455 |
}
|
|
456 |
else{ |
|
457 |
bufp = tmp_20k_buf; |
|
458 |
len = SIZEOF_20KBUF; |
|
459 |
}
|
|
460 |
||
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
461 |
p = (char *)rfc1522_decode_to_utf8((unsigned char*)bufp, len, values[i]); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
462 |
|
463 |
if(p == tmp_20k_buf){ |
|
464 |
fs_give((void **)&values[i]); |
|
465 |
values[i] = cpystr(p); |
|
466 |
}
|
|
467 |
||
468 |
if(biggerbuf) |
|
469 |
fs_give((void **)&biggerbuf); |
|
470 |
}
|
|
471 |
||
472 |
for(pf = *custom, i = FIELD_COUNT; |
|
473 |
pf && pf->name; |
|
474 |
pf = pf->next){ |
|
475 |
if(pf->standard){ |
|
476 |
/*
|
|
477 |
* Because the value is already in the envelope.
|
|
478 |
*/
|
|
479 |
pf->cstmtype = NoMatch; |
|
480 |
continue; |
|
481 |
}
|
|
482 |
||
483 |
if(values[i]){ /* use this instead of default */ |
|
484 |
if(pf->textbuf) |
|
485 |
fs_give((void **)&pf->textbuf); |
|
486 |
||
487 |
pf->textbuf = values[i]; /* freed in pine_send! */ |
|
488 |
}
|
|
489 |
else if(pf->textbuf) /* was erased before postpone */ |
|
490 |
fs_give((void **)&pf->textbuf); |
|
491 |
||
492 |
i++; |
|
493 |
}
|
|
494 |
||
495 |
if(values[INDEX_FCC]) /* If "Fcc:" was there... */ |
|
496 |
pine_generated = 1; /* we put it there? */ |
|
497 |
||
498 |
/*
|
|
499 |
* Since c-client fills in the reply_to field in the envelope
|
|
500 |
* even if there isn't a Reply-To header in the message we
|
|
501 |
* have to work around that. When we postpone we add
|
|
502 |
* a second header that has value "Empty" if there really
|
|
503 |
* was a Reply-To and it was empty. It has the
|
|
504 |
* value "Full" if we put the Reply-To contents there
|
|
505 |
* intentionally (and it isn't empty).
|
|
506 |
*/
|
|
507 |
if(values[INDEX_OUR_REPLYTO]){ |
|
508 |
if(values[INDEX_OUR_REPLYTO][0] == 'E') |
|
509 |
our_replyto = 'E'; /* we put an empty one there */ |
|
510 |
else if(values[INDEX_OUR_REPLYTO][0] == 'F') |
|
511 |
our_replyto = 'F'; /* we put it there */ |
|
512 |
||
513 |
fs_give((void **) &values[INDEX_OUR_REPLYTO]); |
|
514 |
}
|
|
515 |
||
516 |
if(fcc) /* fcc: special case... */ |
|
517 |
*fcc = values[INDEX_FCC] ? values[INDEX_FCC] : cpystr(""); |
|
518 |
else if(values[INDEX_FCC]) |
|
519 |
fs_give((void **) &values[INDEX_FCC]); |
|
520 |
||
521 |
if(values[INDEX_POSTERR]){ /* x-post-error?!?1 */ |
|
522 |
q_status_message(SM_ORDER|SM_DING, 4, 4, |
|
523 |
values[INDEX_POSTERR]); |
|
524 |
fs_give((void **) &values[INDEX_POSTERR]); |
|
525 |
}
|
|
526 |
||
527 |
if(values[INDEX_REPLYUID]){ |
|
528 |
if(reply) |
|
529 |
*reply = build_reply_uid(values[INDEX_REPLYUID]); |
|
530 |
||
531 |
fs_give((void **) &values[INDEX_REPLYUID]); |
|
532 |
||
533 |
if(values[INDEX_REPLYMBOX] && reply && *reply) |
|
534 |
(*reply)->origmbox = cpystr(values[INDEX_REPLYMBOX]); |
|
535 |
||
536 |
if(reply && *reply && !(*reply)->origmbox && (*reply)->mailbox) |
|
537 |
(*reply)->origmbox = cpystr((*reply)->mailbox); |
|
538 |
}
|
|
539 |
||
540 |
if(values[INDEX_REPLYMBOX]) |
|
541 |
fs_give((void **) &values[INDEX_REPLYMBOX]); |
|
542 |
||
543 |
if(values[INDEX_SMTP]){ |
|
544 |
char *q; |
|
545 |
size_t cnt = 0; |
|
546 |
||
547 |
/*
|
|
548 |
* Turn the space delimited list of smtp servers into
|
|
549 |
* a char ** list.
|
|
550 |
*/
|
|
551 |
p = values[INDEX_SMTP]; |
|
552 |
do{ |
|
553 |
if(!*p || isspace((unsigned char) *p)) |
|
554 |
cnt++; |
|
555 |
} while(*p++); |
|
556 |
||
557 |
smtp_servers = (char **) fs_get((cnt+1) * sizeof(char *)); |
|
558 |
memset(smtp_servers, 0, (cnt+1) * sizeof(char *)); |
|
559 |
||
560 |
cnt = 0; |
|
561 |
q = p = values[INDEX_SMTP]; |
|
562 |
do{ |
|
563 |
if(!*p || isspace((unsigned char) *p)){ |
|
564 |
if(*p){ |
|
565 |
*p = '\0'; |
|
566 |
smtp_servers[cnt++] = cpystr(q); |
|
567 |
*p = ' '; |
|
568 |
q = p+1; |
|
569 |
}
|
|
570 |
else
|
|
571 |
smtp_servers[cnt++] = cpystr(q); |
|
572 |
}
|
|
573 |
} while(*p++); |
|
574 |
||
575 |
fs_give((void **) &values[INDEX_SMTP]); |
|
576 |
}
|
|
577 |
||
578 |
if(values[INDEX_NNTP]){ |
|
579 |
char *q; |
|
580 |
size_t cnt = 0; |
|
581 |
||
582 |
/*
|
|
583 |
* Turn the space delimited list of smtp nntp into
|
|
584 |
* a char ** list.
|
|
585 |
*/
|
|
586 |
p = values[INDEX_NNTP]; |
|
587 |
do{ |
|
588 |
if(!*p || isspace((unsigned char) *p)) |
|
589 |
cnt++; |
|
590 |
} while(*p++); |
|
591 |
||
592 |
nntp_servers = (char **) fs_get((cnt+1) * sizeof(char *)); |
|
593 |
memset(nntp_servers, 0, (cnt+1) * sizeof(char *)); |
|
594 |
||
595 |
cnt = 0; |
|
596 |
q = p = values[INDEX_NNTP]; |
|
597 |
do{ |
|
598 |
if(!*p || isspace((unsigned char) *p)){ |
|
599 |
if(*p){ |
|
600 |
*p = '\0'; |
|
601 |
nntp_servers[cnt++] = cpystr(q); |
|
602 |
*p = ' '; |
|
603 |
q = p+1; |
|
604 |
}
|
|
605 |
else
|
|
606 |
nntp_servers[cnt++] = cpystr(q); |
|
607 |
}
|
|
608 |
} while(*p++); |
|
609 |
||
610 |
fs_give((void **) &values[INDEX_NNTP]); |
|
611 |
}
|
|
612 |
||
613 |
if(values[INDEX_CURSORPOS]){ |
|
614 |
/*
|
|
615 |
* The redraft cursor position is written as two fields
|
|
616 |
* separated by a space. First comes the name of the
|
|
617 |
* header field we're in, or just a ":" if we're in the
|
|
618 |
* body. Then comes the offset into that header or into
|
|
619 |
* the body.
|
|
620 |
*/
|
|
621 |
if(redraft_pos){ |
|
622 |
char *q1, *q2; |
|
623 |
||
624 |
*redraft_pos |
|
625 |
= (REDRAFT_POS_S *)fs_get(sizeof(REDRAFT_POS_S)); |
|
626 |
(*redraft_pos)->offset = 0L; |
|
627 |
||
628 |
q1 = skip_white_space(values[INDEX_CURSORPOS]); |
|
629 |
if(*q1 && (q2 = strindex(q1, SPACE))){ |
|
630 |
*q2 = '\0'; |
|
631 |
(*redraft_pos)->hdrname = cpystr(q1); |
|
632 |
q1 = skip_white_space(q2+1); |
|
633 |
if(*q1) |
|
634 |
(*redraft_pos)->offset = atol(q1); |
|
635 |
}
|
|
636 |
else
|
|
637 |
(*redraft_pos)->hdrname = cpystr(":"); |
|
638 |
}
|
|
639 |
||
640 |
fs_give((void **) &values[INDEX_CURSORPOS]); |
|
641 |
}
|
|
642 |
||
643 |
if(lcc) |
|
644 |
*lcc = values[INDEX_LCC]; |
|
645 |
else
|
|
646 |
fs_give((void **) &values[INDEX_LCC]); |
|
647 |
}
|
|
648 |
||
649 |
fs_give((void **)&fields); |
|
650 |
fs_give((void **)&values); |
|
651 |
||
652 |
*outgoing = copy_envelope(e); |
|
653 |
||
654 |
/*
|
|
655 |
* If the postponed message has a From which is different from
|
|
656 |
* the default, it is either because allow-changing-from is on
|
|
657 |
* or because there was a role with a from that allowed it to happen.
|
|
658 |
* If allow-changing-from is not on, put this back in a role
|
|
659 |
* so that it will be allowed again in pine_send.
|
|
660 |
*/
|
|
661 |
if(role && *role == NULL && |
|
662 |
!ps_global->never_allow_changing_from && |
|
663 |
*outgoing){ |
|
664 |
/*
|
|
665 |
* Now check to see if the from is different from default from.
|
|
666 |
*/
|
|
667 |
ADDRESS *deffrom; |
|
668 |
||
669 |
deffrom = generate_from(); |
|
670 |
if(!((*outgoing)->from && |
|
671 |
address_is_same(deffrom, (*outgoing)->from) && |
|
672 |
((!(deffrom->personal && deffrom->personal[0]) && |
|
673 |
!((*outgoing)->from->personal && |
|
674 |
(*outgoing)->from->personal[0])) || |
|
675 |
(deffrom->personal && (*outgoing)->from->personal && |
|
676 |
!strcmp(deffrom->personal, (*outgoing)->from->personal))))){ |
|
677 |
||
678 |
*role = (ACTION_S *)fs_get(sizeof(**role)); |
|
679 |
memset((void *)*role, 0, sizeof(**role)); |
|
680 |
if(!(*outgoing)->from) |
|
681 |
(*outgoing)->from = mail_newaddr(); |
|
682 |
||
683 |
(*role)->from = (*outgoing)->from; |
|
684 |
(*outgoing)->from = NULL; |
|
685 |
added_to_role++; |
|
686 |
}
|
|
687 |
||
688 |
mail_free_address(&deffrom); |
|
689 |
}
|
|
690 |
||
691 |
/*
|
|
692 |
* Look at each empty address and see if the user has specified
|
|
693 |
* a default for that field or not. If they have, that means
|
|
694 |
* they have erased it before postponing, so they won't want
|
|
695 |
* the default to come back. If they haven't specified a default,
|
|
696 |
* then the default should be generated in pine_send. We prevent
|
|
697 |
* the default from being assigned by assigning an empty address
|
|
698 |
* to the variable here.
|
|
699 |
*
|
|
700 |
* BUG: We should do this for custom Address headers, too, but
|
|
701 |
* there isn't such a thing yet.
|
|
702 |
*/
|
|
703 |
if(!(*outgoing)->to && hdr_is_in_list("to", *custom)) |
|
704 |
(*outgoing)->to = mail_newaddr(); |
|
705 |
if(!(*outgoing)->cc && hdr_is_in_list("cc", *custom)) |
|
706 |
(*outgoing)->cc = mail_newaddr(); |
|
707 |
if(!(*outgoing)->bcc && hdr_is_in_list("bcc", *custom)) |
|
708 |
(*outgoing)->bcc = mail_newaddr(); |
|
709 |
||
710 |
if(our_replyto == 'E'){ |
|
711 |
/* user erased reply-to before postponing */
|
|
712 |
if((*outgoing)->reply_to) |
|
713 |
mail_free_address(&(*outgoing)->reply_to); |
|
714 |
||
715 |
/*
|
|
716 |
* If empty is not the normal default, make the outgoing
|
|
717 |
* reply_to be an emtpy address. If it is default, leave it
|
|
718 |
* as NULL and the default will be used.
|
|
719 |
*/
|
|
720 |
if(hdr_is_in_list("reply-to", *custom)){ |
|
721 |
PINEFIELD pf; |
|
722 |
||
723 |
pf.name = "reply-to"; |
|
724 |
set_default_hdrval(&pf, *custom); |
|
725 |
if(pf.textbuf){ |
|
726 |
if(pf.textbuf[0]) /* empty is not default */ |
|
727 |
(*outgoing)->reply_to = mail_newaddr(); |
|
728 |
||
729 |
fs_give((void **)&pf.textbuf); |
|
730 |
}
|
|
731 |
}
|
|
732 |
}
|
|
733 |
else if(our_replyto == 'F'){ |
|
734 |
int add_to_role = 0; |
|
735 |
||
736 |
/*
|
|
737 |
* The reply-to is real. If it is different from the default
|
|
738 |
* reply-to, put it in the role so that it will show up when
|
|
739 |
* the user edits.
|
|
740 |
*/
|
|
741 |
if(hdr_is_in_list("reply-to", *custom)){ |
|
742 |
PINEFIELD pf; |
|
743 |
char *str; |
|
744 |
||
745 |
pf.name = "reply-to"; |
|
746 |
set_default_hdrval(&pf, *custom); |
|
747 |
if(pf.textbuf && pf.textbuf[0]){ |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
748 |
if((str = addr_list_string((*outgoing)->reply_to,NULL,1)) != NULL){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
749 |
if(!strcmp(str, pf.textbuf)){ |
750 |
/* standard value, leave it alone */
|
|
751 |
;
|
|
752 |
}
|
|
753 |
else /* not standard, put in role */ |
|
754 |
add_to_role++; |
|
755 |
||
756 |
fs_give((void **)&str); |
|
757 |
}
|
|
758 |
}
|
|
759 |
else /* not standard, put in role */ |
|
760 |
add_to_role++; |
|
761 |
||
762 |
if(pf.textbuf) |
|
763 |
fs_give((void **)&pf.textbuf); |
|
764 |
}
|
|
765 |
else /* not standard, put in role */ |
|
766 |
add_to_role++; |
|
767 |
||
768 |
if(add_to_role && role && (*role == NULL || added_to_role)){ |
|
769 |
if(*role == NULL){ |
|
770 |
added_to_role++; |
|
771 |
*role = (ACTION_S *)fs_get(sizeof(**role)); |
|
772 |
memset((void *)*role, 0, sizeof(**role)); |
|
773 |
}
|
|
774 |
||
775 |
(*role)->replyto = (*outgoing)->reply_to; |
|
776 |
(*outgoing)->reply_to = NULL; |
|
777 |
}
|
|
778 |
}
|
|
779 |
else{ |
|
780 |
/* this is a bogus c-client generated replyto */
|
|
781 |
if((*outgoing)->reply_to) |
|
782 |
mail_free_address(&(*outgoing)->reply_to); |
|
783 |
}
|
|
784 |
||
785 |
if((smtp_servers || nntp_servers) |
|
786 |
&& role && (*role == NULL || added_to_role)){ |
|
787 |
if(*role == NULL){ |
|
788 |
*role = (ACTION_S *)fs_get(sizeof(**role)); |
|
789 |
memset((void *)*role, 0, sizeof(**role)); |
|
790 |
}
|
|
791 |
||
792 |
if(smtp_servers) |
|
793 |
(*role)->smtp = smtp_servers; |
|
794 |
if(nntp_servers) |
|
795 |
(*role)->nntp = nntp_servers; |
|
796 |
}
|
|
797 |
||
798 |
if(!(*outgoing)->subject && hdr_is_in_list("subject", *custom)) |
|
799 |
(*outgoing)->subject = cpystr(""); |
|
800 |
||
801 |
if(!pine_generated){ |
|
802 |
/*
|
|
803 |
* Now, this is interesting. We should have found
|
|
804 |
* the "fcc:" field if pine wrote the message being
|
|
805 |
* redrafted. Hence, we probably can't trust the
|
|
806 |
* "originator" type fields, so we'll blast them and let
|
|
807 |
* them get set later in pine_send. This should allow
|
|
808 |
* folks with custom or edited From's and such to still
|
|
809 |
* use redraft reasonably, without inadvertently sending
|
|
810 |
* messages that appear to be "From" others...
|
|
811 |
*/
|
|
812 |
if((*outgoing)->from) |
|
813 |
mail_free_address(&(*outgoing)->from); |
|
814 |
||
815 |
/*
|
|
816 |
* Ditto for Reply-To and Sender...
|
|
817 |
*/
|
|
818 |
if((*outgoing)->reply_to) |
|
819 |
mail_free_address(&(*outgoing)->reply_to); |
|
820 |
||
821 |
if((*outgoing)->sender) |
|
822 |
mail_free_address(&(*outgoing)->sender); |
|
823 |
}
|
|
824 |
||
825 |
if(!pine_generated || !(flags & REDRAFT_DEL)){ |
|
826 |
||
827 |
/*
|
|
828 |
* Generate a fresh message id for pretty much the same
|
|
829 |
* reason From and such got wacked...
|
|
830 |
* Also, if we're coming from a form letter, we need to
|
|
831 |
* generate a different id each time.
|
|
832 |
*/
|
|
833 |
if((*outgoing)->message_id) |
|
834 |
fs_give((void **)&(*outgoing)->message_id); |
|
835 |
||
836 |
(*outgoing)->message_id = generate_message_id(); |
|
837 |
}
|
|
838 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
839 |
if(b && b->type != TYPETEXT){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
840 |
if(b->type == TYPEMULTIPART){ |
841 |
if(strucmp(b->subtype, "mixed")){ |
|
842 |
q_status_message1(SM_INFO, 3, 4, |
|
843 |
"Converting Multipart/%s to Multipart/Mixed", |
|
844 |
b->subtype); |
|
845 |
fs_give((void **)&b->subtype); |
|
846 |
b->subtype = cpystr("mixed"); |
|
847 |
}
|
|
848 |
}
|
|
849 |
else{ |
|
850 |
q_status_message2(SM_ORDER | SM_DING, 3, 4, |
|
851 |
"Unable to resume type %s/%s message", |
|
852 |
body_types[b->type], b->subtype); |
|
853 |
return(redraft_cleanup(streamp, TRUE, flags)); |
|
854 |
}
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
855 |
}
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
856 |
|
857 |
gf_set_so_writec(&pc, so); |
|
858 |
||
859 |
if(b && b->type != TYPETEXT){ /* already TYPEMULTIPART */ |
|
860 |
*body = copy_body(NULL, b); |
|
861 |
part = (*body)->nested.part; |
|
862 |
part->body.contents.text.data = (void *)so; |
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
863 |
set_mime_type_by_grope(&part->body); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
864 |
if(part->body.type != TYPETEXT){ |
865 |
q_status_message2(SM_ORDER | SM_DING, 3, 4, |
|
866 |
"Unable to resume; first part is non-text: %s/%s", |
|
867 |
body_types[part->body.type], |
|
868 |
part->body.subtype); |
|
869 |
return(redraft_cleanup(streamp, TRUE, flags)); |
|
870 |
}
|
|
871 |
||
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
872 |
if((charset = parameter_val(part->body.parameter,"charset")) != NULL){ |
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
873 |
/* let outgoing routines decide on charset */
|
874 |
if(!strucmp(charset, "US-ASCII") || !strucmp(charset, "UTF-8")) |
|
875 |
set_parameter(&part->body.parameter, "charset", NULL); |
|
876 |
||
877 |
fs_give((void **) &charset); |
|
878 |
}
|
|
879 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
880 |
ps_global->postpone_no_flow = 1; |
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
881 |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
882 |
get_body_part_text(stream, &b->nested.part->body, |
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
883 |
cont_msg, "1", 0L, pc, NULL, NULL, gbpt_flags); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
884 |
ps_global->postpone_no_flow = 0; |
885 |
||
886 |
if(!fetch_contents(stream, cont_msg, NULL, *body)) |
|
887 |
q_status_message(SM_ORDER | SM_DING, 3, 4, |
|
888 |
_("Error including all message parts")); |
|
889 |
}
|
|
890 |
else{ |
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
891 |
*body = mail_newbody(); |
892 |
(*body)->type = TYPETEXT; |
|
893 |
if(b->subtype) |
|
894 |
(*body)->subtype = cpystr(b->subtype); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
895 |
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
896 |
if((charset = parameter_val(b->parameter,"charset")) != NULL){ |
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
897 |
/* let outgoing routines decide on charset */
|
898 |
if(!strucmp(charset, "US-ASCII") || !strucmp(charset, "UTF-8")) |
|
899 |
fs_give((void **) &charset); |
|
900 |
else{ |
|
901 |
(*body)->parameter = mail_newbody_parameter(); |
|
902 |
(*body)->parameter->attribute = cpystr("charset"); |
|
903 |
if(utf8_charset(charset)){ |
|
904 |
fs_give((void **) &charset); |
|
905 |
(*body)->parameter->value = cpystr("UTF-8"); |
|
906 |
}
|
|
907 |
else
|
|
908 |
(*body)->parameter->value = charset; |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
909 |
}
|
910 |
}
|
|
911 |
||
912 |
(*body)->contents.text.data = (void *)so; |
|
913 |
ps_global->postpone_no_flow = 1; |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
914 |
get_body_part_text(stream, b, cont_msg, "1", 0L, pc, |
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
915 |
NULL, NULL, gbpt_flags); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
916 |
ps_global->postpone_no_flow = 0; |
917 |
}
|
|
918 |
||
919 |
gf_clear_so_writec(so); |
|
920 |
||
921 |
/* We have what we want, blast this message... */
|
|
922 |
if((flags & REDRAFT_DEL) |
|
923 |
&& cont_msg > 0L && stream && cont_msg <= stream->nmsgs |
|
924 |
&& (mc = mail_elt(stream, cont_msg)) && !mc->deleted) |
|
925 |
mail_flag(stream, long2string(cont_msg), "\\DELETED", ST_SET); |
|
926 |
}
|
|
927 |
else
|
|
928 |
return(redraft_cleanup(streamp, TRUE, flags)); |
|
929 |
||
930 |
return(redraft_cleanup(streamp, FALSE, flags)); |
|
931 |
}
|
|
932 |
||
933 |
||
934 |
/*----------------------------------------------------------------------
|
|
935 |
Clear deleted messages from given stream and expunge if necessary
|
|
936 |
||
937 |
Args: stream --
|
|
938 |
problem --
|
|
939 |
||
940 |
----*/
|
|
941 |
int
|
|
942 |
redraft_cleanup(MAILSTREAM **streamp, int problem, int flags) |
|
943 |
{
|
|
944 |
MAILSTREAM *stream; |
|
945 |
||
946 |
if(!(streamp && *streamp)) |
|
947 |
return(0); |
|
948 |
||
949 |
if(!problem && streamp && (stream = *streamp)){ |
|
950 |
if(stream->nmsgs){ |
|
951 |
ps_global->expunge_in_progress = 1; |
|
952 |
mail_expunge(stream); /* clean out deleted */ |
|
953 |
ps_global->expunge_in_progress = 0; |
|
954 |
}
|
|
955 |
||
956 |
if(!stream->nmsgs){ /* close and delete folder */ |
|
957 |
int do_the_broach = 0; |
|
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
958 |
char *mbox = NULL; |
959 |
||
960 |
if(stream){ |
|
961 |
if(stream->original_mailbox && stream->original_mailbox[0]) |
|
962 |
mbox = cpystr(stream->original_mailbox); |
|
963 |
else if(stream->mailbox && stream->mailbox[0]) |
|
964 |
mbox = cpystr(stream->mailbox); |
|
965 |
}
|
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
966 |
|
967 |
/* if it is current, we have to change folders */
|
|
968 |
if(stream == ps_global->mail_stream) |
|
969 |
do_the_broach++; |
|
970 |
||
971 |
/*
|
|
972 |
* This is the stream to the empty postponed-msgs folder.
|
|
973 |
* We are going to delete the folder in a second. It is
|
|
974 |
* probably preferable to unselect the mailbox and leave
|
|
975 |
* this stream open for re-use instead of actually closing it,
|
|
976 |
* so we do that if possible.
|
|
977 |
*/
|
|
978 |
if(is_imap_stream(stream) && LEVELUNSELECT(stream)){ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
979 |
/*
|
980 |
* This does the UNSELECT on the stream. A NULL
|
|
981 |
* return should mean that something went wrong and
|
|
982 |
* a mail_close already happened, so that should have
|
|
983 |
* cleaned things up in the callback.
|
|
984 |
*/
|
|
985 |
if((stream=mail_open(stream, stream->mailbox, |
|
986 |
OP_HALFOPEN | (stream->debug ? OP_DEBUG : NIL))) != NULL){ |
|
987 |
/* now close it so it is put into the stream cache */
|
|
988 |
sp_set_flags(stream, sp_flags(stream) | SP_TEMPUSE); |
|
989 |
pine_mail_close(stream); |
|
990 |
}
|
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
991 |
}
|
992 |
else
|
|
993 |
pine_mail_actually_close(stream); |
|
994 |
||
995 |
*streamp = NULL; |
|
996 |
||
997 |
if(do_the_broach){ |
|
998 |
ps_global->mail_stream = NULL; /* already closed above */ |
|
999 |
}
|
|
1000 |
||
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
1001 |
if(mbox && !pine_mail_delete(NULL, mbox)) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1002 |
q_status_message1(SM_ORDER|SM_DING, 3, 3, |
1003 |
/* TRANSLATORS: Arg is a mailbox name */
|
|
1004 |
_("Can't delete %s"), mbox); |
|
1005 |
||
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
1006 |
if(mbox) |
1007 |
fs_give((void **) &mbox); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1008 |
}
|
1009 |
}
|
|
1010 |
||
1011 |
return(!problem); |
|
1012 |
}
|
|
1013 |
||
1014 |
||
1015 |
/*----------------------------------------------------------------------
|
|
1016 |
Parse the given header text for any given fields
|
|
1017 |
||
1018 |
Args: text -- Text to parse for fcc and attachments refs
|
|
1019 |
fields -- array of field names to look for
|
|
1020 |
values -- array of pointer to save values to, returned NULL if
|
|
1021 |
fields isn't in text.
|
|
1022 |
||
1023 |
This function simply looks for the given fields in the given header
|
|
1024 |
text string.
|
|
1025 |
NOTE: newlines are expected CRLF, and we'll ignore continuations
|
|
1026 |
----*/
|
|
1027 |
void
|
|
1028 |
simple_header_parse(char *text, char **fields, char **values) |
|
1029 |
{
|
|
1030 |
int i, n; |
|
1031 |
char *p, *t; |
|
1032 |
||
1033 |
for(i = 0; fields[i]; i++) |
|
1034 |
values[i] = NULL; /* clear values array */ |
|
1035 |
||
1036 |
/*---- Loop until the end of the header ----*/
|
|
1037 |
for(p = text; *p; ){ |
|
1038 |
for(i = 0; fields[i]; i++) /* find matching field? */ |
|
1039 |
if(!struncmp(p, fields[i], (n=strlen(fields[i]))) && p[n] == ':'){ |
|
1040 |
for(p += n + 1; *p; p++){ /* find start of value */ |
|
1041 |
if(*p == '\015' && *(p+1) == '\012' |
|
1042 |
&& !isspace((unsigned char) *(p+2))) |
|
1043 |
break; |
|
1044 |
||
1045 |
if(!isspace((unsigned char) *p)) |
|
1046 |
break; /* order here is key... */ |
|
1047 |
}
|
|
1048 |
||
1049 |
if(!values[i]){ /* if we haven't already */ |
|
1050 |
values[i] = fs_get(strlen(text) + 1); |
|
1051 |
values[i][0] = '\0'; /* alloc space for it */ |
|
1052 |
}
|
|
1053 |
||
1054 |
if(*p && *p != '\015'){ /* non-blank value. */ |
|
1055 |
t = values[i] + (values[i][0] ? strlen(values[i]) : 0); |
|
1056 |
while(*p){ /* check for cont'n lines */ |
|
1057 |
if(*p == '\015' && *(p+1) == '\012'){ |
|
1058 |
if(isspace((unsigned char) *(p+2))){ |
|
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
1059 |
p += 2; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1060 |
continue; |
1061 |
}
|
|
1062 |
else
|
|
1063 |
break; |
|
1064 |
}
|
|
1065 |
||
1066 |
*t++ = *p++; |
|
1067 |
}
|
|
1068 |
||
1069 |
*t = '\0'; |
|
1070 |
}
|
|
1071 |
||
1072 |
break; |
|
1073 |
}
|
|
1074 |
||
1075 |
/* Skip to end of line, what ever it was */
|
|
1076 |
for(; *p ; p++) |
|
1077 |
if(*p == '\015' && *(p+1) == '\012'){ |
|
1078 |
p += 2; |
|
1079 |
break; |
|
1080 |
}
|
|
1081 |
}
|
|
1082 |
}
|
|
1083 |
||
1084 |
||
1085 |
/*----------------------------------------------------------------------
|
|
1086 |
build a fresh REPLY_S from the given string (see pine_send for format)
|
|
1087 |
||
1088 |
Args: s -- "X-Reply-UID" header value
|
|
1089 |
||
1090 |
Returns: filled in REPLY_S or NULL on parse error
|
|
1091 |
----*/
|
|
1092 |
REPLY_S * |
|
1093 |
build_reply_uid(char *s) |
|
1094 |
{
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1095 |
char *p, *prefix = NULL, *val, *seq, *mbox; |
1096 |
int i, nseq, forwarded = 0; |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1097 |
REPLY_S *reply = NULL; |
1098 |
||
1099 |
/* FORMAT: (n prefix)(n validity uidlist)mailbox */
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1100 |
/* if 'n prefix' is empty, uid list represents forwarded msgs */
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1101 |
if(*s == '('){ |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1102 |
if(*(p = s + 1) == ')'){ |
1103 |
forwarded = 1; |
|
1104 |
}
|
|
1105 |
else{ |
|
1106 |
for(; isdigit(*p); p++) |
|
1107 |
;
|
|
1108 |
||
1109 |
if(*p == ' '){ |
|
1110 |
*p++ = '\0'; |
|
1111 |
||
1112 |
if((i = atoi(s+1)) && i < strlen(p)){ |
|
1113 |
prefix = p; |
|
1114 |
*(p += i) = '\0'; |
|
1115 |
}
|
|
1116 |
}
|
|
1117 |
else
|
|
1118 |
return(NULL); |
|
1119 |
}
|
|
1120 |
||
1121 |
if(*++p == '(' && *++p){ |
|
1122 |
for(seq = p; isdigit(*p); p++) |
|
1123 |
;
|
|
1124 |
||
1125 |
if(*p == ' '){ |
|
1126 |
*p++ = '\0'; |
|
1127 |
for(val = p; isdigit(*p); p++) |
|
1128 |
;
|
|
1129 |
||
1130 |
if(*p == ' '){ |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1131 |
*p++ = '\0'; |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1132 |
|
1133 |
if((nseq = atoi(seq)) && isdigit(*(seq = p)) |
|
1134 |
&& (p = strchr(p, ')')) && *(mbox = ++p)){ |
|
1135 |
imapuid_t *uidl; |
|
1136 |
||
1137 |
uidl = (imapuid_t *) fs_get ((nseq+1)*sizeof(imapuid_t)); |
|
1138 |
for(i = 0; i < nseq; i++) |
|
1139 |
if((p = strchr(seq,',')) != NULL){ |
|
1140 |
*p = '\0'; |
|
1141 |
if((uidl[i]= strtoul(seq,NULL,10)) != 0) |
|
1142 |
seq = ++p; |
|
1143 |
else
|
|
1144 |
break; |
|
1145 |
}
|
|
1146 |
else if((p = strchr(seq, ')')) != NULL){ |
|
1147 |
if((uidl[i] = strtoul(seq,NULL,10)) != 0) |
|
1148 |
i++; |
|
1149 |
||
1150 |
break; |
|
1151 |
}
|
|
1152 |
||
1153 |
if(i == nseq){ |
|
1154 |
reply = (REPLY_S *)fs_get(sizeof(REPLY_S)); |
|
1155 |
memset(reply, 0, sizeof(REPLY_S)); |
|
1156 |
reply->uid = 1; |
|
1157 |
reply->data.uid.validity = strtoul(val, NULL, 10); |
|
1158 |
if(forwarded) |
|
1159 |
reply->forwarded = 1; |
|
1160 |
else
|
|
1161 |
reply->prefix = cpystr(prefix); |
|
1162 |
||
1163 |
reply->mailbox = cpystr(mbox); |
|
1164 |
uidl[nseq] = 0; |
|
1165 |
reply->data.uid.msgs = uidl; |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1166 |
}
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1167 |
else
|
1168 |
fs_give((void **) &uidl); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1169 |
}
|
1170 |
}
|
|
1171 |
}
|
|
1172 |
}
|
|
1173 |
}
|
|
1174 |
||
1175 |
return(reply); |
|
1176 |
}
|
|
1177 |
||
1178 |
||
1179 |
/*
|
|
1180 |
* pine_new_env - allocate a new METAENV and fill it in.
|
|
1181 |
*/
|
|
1182 |
METAENV * |
|
1183 |
pine_new_env(ENVELOPE *outgoing, char **fccp, char ***tobufpp, PINEFIELD *custom) |
|
1184 |
{
|
|
1185 |
int cnt, i, stdcnt; |
|
1186 |
char *p; |
|
1187 |
PINEFIELD *pfields, *pf, **sending_order; |
|
1188 |
METAENV *header; |
|
1189 |
||
1190 |
header = (METAENV *) fs_get(sizeof(METAENV)); |
|
1191 |
||
1192 |
/* how many fields are there? */
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1193 |
for(cnt = 0; pf_template && pf_template[cnt].name; cnt++) |
1194 |
;
|
|
1195 |
||
1196 |
stdcnt = cnt; |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1197 |
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
1198 |
for(pf = custom; pf; pf = pf->next) |
1199 |
cnt++; |
|
1200 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1201 |
/* temporary PINEFIELD array */
|
1202 |
i = (cnt + 1) * sizeof(PINEFIELD); |
|
1203 |
pfields = (PINEFIELD *)fs_get((size_t) i); |
|
1204 |
memset(pfields, 0, (size_t) i); |
|
1205 |
||
1206 |
i = (cnt + 1) * sizeof(PINEFIELD *); |
|
1207 |
sending_order = (PINEFIELD **)fs_get((size_t) i); |
|
1208 |
memset(sending_order, 0, (size_t) i); |
|
1209 |
||
1210 |
header->env = outgoing; |
|
1211 |
header->local = pfields; |
|
1212 |
header->custom = custom; |
|
1213 |
header->sending_order = sending_order; |
|
1214 |
||
1215 |
#if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
|
|
1216 |
# define NN 4
|
|
1217 |
#else
|
|
1218 |
# define NN 3
|
|
1219 |
#endif
|
|
1220 |
||
1221 |
/* initialize pfield */
|
|
1222 |
pf = pfields; |
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
1223 |
for(i=0; i < stdcnt; i++, pf++){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1224 |
|
1225 |
pf->name = cpystr(pf_template[i].name); |
|
1226 |
if(i == N_SENDER && F_ON(F_USE_SENDER_NOT_X, ps_global)) |
|
1227 |
/* slide string over so it is Sender instead of X-X-Sender */
|
|
1228 |
for(p=pf->name; *(p+1); p++) |
|
1229 |
*p = *(p+4); |
|
1230 |
||
1231 |
pf->type = pf_template[i].type; |
|
1232 |
pf->canedit = pf_template[i].canedit; |
|
1233 |
pf->rcptto = pf_template[i].rcptto; |
|
1234 |
pf->writehdr = pf_template[i].writehdr; |
|
1235 |
pf->localcopy = pf_template[i].localcopy; |
|
1236 |
pf->extdata = NULL; /* unused */ |
|
1237 |
pf->next = pf + 1; |
|
1238 |
||
1239 |
switch(pf->type){ |
|
1240 |
case FreeText: |
|
1241 |
switch(i){ |
|
1242 |
case N_AUTHRCVD: |
|
1243 |
sending_order[0] = pf; |
|
1244 |
break; |
|
1245 |
||
1246 |
case N_NEWS: |
|
1247 |
pf->text = &outgoing->newsgroups; |
|
1248 |
sending_order[1] = pf; |
|
1249 |
break; |
|
1250 |
||
1251 |
case N_DATE: |
|
1252 |
pf->text = (char **) &outgoing->date; |
|
1253 |
sending_order[2] = pf; |
|
1254 |
break; |
|
1255 |
||
1256 |
case N_INREPLY: |
|
1257 |
pf->text = &outgoing->in_reply_to; |
|
1258 |
sending_order[NN+9] = pf; |
|
1259 |
break; |
|
1260 |
||
1261 |
case N_MSGID: |
|
1262 |
pf->text = &outgoing->message_id; |
|
1263 |
sending_order[NN+10] = pf; |
|
1264 |
break; |
|
1265 |
||
1266 |
case N_REF: /* won't be used here */ |
|
1267 |
sending_order[NN+11] = pf; |
|
1268 |
break; |
|
1269 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1270 |
case N_PRIORITY: |
1271 |
sending_order[NN+12] = pf; |
|
1272 |
break; |
|
1273 |
||
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1274 |
case N_USERAGENT: |
1275 |
pf->text = &pf->textbuf; |
|
1276 |
pf->textbuf = generate_user_agent(); |
|
1277 |
sending_order[NN+13] = pf; |
|
1278 |
break; |
|
1279 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1280 |
case N_POSTERR: /* won't be used here */ |
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1281 |
sending_order[NN+14] = pf; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1282 |
break; |
1283 |
||
1284 |
case N_RPLUID: /* won't be used here */ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1285 |
sending_order[NN+15] = pf; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1286 |
break; |
1287 |
||
1288 |
case N_RPLMBOX: /* won't be used here */ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1289 |
sending_order[NN+16] = pf; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1290 |
break; |
1291 |
||
1292 |
case N_SMTP: /* won't be used here */ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1293 |
sending_order[NN+17] = pf; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1294 |
break; |
1295 |
||
1296 |
case N_NNTP: /* won't be used here */ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1297 |
sending_order[NN+18] = pf; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1298 |
break; |
1299 |
||
1300 |
case N_CURPOS: /* won't be used here */ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1301 |
sending_order[NN+19] = pf; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1302 |
break; |
1303 |
||
1304 |
case N_OURREPLYTO: /* won't be used here */ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1305 |
sending_order[NN+20] = pf; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1306 |
break; |
1307 |
||
1308 |
case N_OURHDRS: /* won't be used here */ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1309 |
sending_order[NN+21] = pf; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1310 |
break; |
1311 |
||
1312 |
default: |
|
1313 |
q_status_message1(SM_ORDER,3,3, |
|
1314 |
"Internal error: 1)FreeText header %s", comatose(i)); |
|
1315 |
break; |
|
1316 |
}
|
|
1317 |
||
1318 |
break; |
|
1319 |
||
1320 |
case Attachment: |
|
1321 |
break; |
|
1322 |
||
1323 |
case Address: |
|
1324 |
switch(i){ |
|
1325 |
case N_FROM: |
|
1326 |
sending_order[3] = pf; |
|
1327 |
pf->addr = &outgoing->from; |
|
1328 |
break; |
|
1329 |
||
1330 |
case N_TO: |
|
1331 |
sending_order[NN+2] = pf; |
|
1332 |
pf->addr = &outgoing->to; |
|
1333 |
if(tobufpp) |
|
1334 |
(*tobufpp) = &pf->scratch; |
|
1335 |
||
1336 |
break; |
|
1337 |
||
1338 |
case N_CC: |
|
1339 |
sending_order[NN+3] = pf; |
|
1340 |
pf->addr = &outgoing->cc; |
|
1341 |
break; |
|
1342 |
||
1343 |
case N_BCC: |
|
1344 |
sending_order[NN+4] = pf; |
|
1345 |
pf->addr = &outgoing->bcc; |
|
1346 |
break; |
|
1347 |
||
1348 |
case N_REPLYTO: |
|
1349 |
sending_order[NN+1] = pf; |
|
1350 |
pf->addr = &outgoing->reply_to; |
|
1351 |
break; |
|
1352 |
||
1353 |
case N_LCC: /* won't be used here */ |
|
1354 |
sending_order[NN+7] = pf; |
|
1355 |
break; |
|
1356 |
||
1357 |
#if !(defined(DOS) || defined(OS2)) || defined(NOAUTH)
|
|
1358 |
case N_SENDER: |
|
1359 |
sending_order[4] = pf; |
|
1360 |
pf->addr = &outgoing->sender; |
|
1361 |
break; |
|
1362 |
#endif
|
|
1363 |
||
1364 |
case N_NOBODY: /* won't be used here */ |
|
1365 |
sending_order[NN+5] = pf; |
|
1366 |
break; |
|
1367 |
||
1368 |
default: |
|
1369 |
q_status_message1(SM_ORDER,3,3, |
|
1370 |
"Internal error: Address header %s", comatose(i)); |
|
1371 |
break; |
|
1372 |
}
|
|
1373 |
break; |
|
1374 |
||
1375 |
case Fcc: |
|
1376 |
sending_order[NN+8] = pf; |
|
1377 |
pf->text = fccp; |
|
1378 |
break; |
|
1379 |
||
1380 |
case Subject: |
|
1381 |
sending_order[NN+6] = pf; |
|
1382 |
pf->text = &outgoing->subject; |
|
1383 |
break; |
|
1384 |
||
1385 |
default: |
|
1386 |
q_status_message1(SM_ORDER,3,3, |
|
1387 |
"Unknown header type %d in pine_new_send", (void *)pf->type); |
|
1388 |
break; |
|
1389 |
}
|
|
1390 |
}
|
|
1391 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1392 |
if(((--pf)->next = custom) != NULL){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1393 |
i--; |
1394 |
||
1395 |
/*
|
|
1396 |
* NOTE: "i" is assumed to now index first custom field in sending
|
|
1397 |
* order.
|
|
1398 |
*/
|
|
1399 |
for(pf = pf->next; pf && pf->name; pf = pf->next){ |
|
1400 |
if(pf->standard) |
|
1401 |
continue; |
|
1402 |
||
1403 |
pf->canedit = 1; |
|
1404 |
pf->rcptto = 0; |
|
1405 |
pf->writehdr = 1; |
|
1406 |
pf->localcopy = 1; |
|
1407 |
||
1408 |
switch(pf->type){ |
|
1409 |
case Address: |
|
1410 |
if(pf->addr){ /* better be set */ |
|
1411 |
char *addr = NULL; |
|
1412 |
BuildTo bldto; |
|
1413 |
||
1414 |
bldto.type = Str; |
|
1415 |
bldto.arg.str = pf->textbuf; |
|
1416 |
||
1417 |
sending_order[i++] = pf; |
|
1418 |
/* change default text into an ADDRESS */
|
|
1419 |
/* strip quotes around whole default */
|
|
1420 |
removing_trailing_white_space(pf->textbuf); |
|
1421 |
(void)removing_double_quotes(pf->textbuf); |
|
1422 |
build_address_internal(bldto, &addr, NULL, NULL, NULL, NULL, NULL, 0, NULL); |
|
1423 |
rfc822_parse_adrlist(pf->addr, addr, ps_global->maildomain); |
|
1424 |
fs_give((void **)&addr); |
|
1425 |
if(pf->textbuf) |
|
1426 |
fs_give((void **)&pf->textbuf); |
|
1427 |
}
|
|
1428 |
||
1429 |
break; |
|
1430 |
||
1431 |
case FreeText: |
|
1432 |
sending_order[i++] = pf; |
|
1433 |
pf->text = &pf->textbuf; |
|
1434 |
break; |
|
1435 |
||
1436 |
default: |
|
1437 |
q_status_message1(SM_ORDER,0,7,"Unknown custom header type %d", |
|
1438 |
(void *)pf->type); |
|
1439 |
break; |
|
1440 |
}
|
|
1441 |
}
|
|
1442 |
}
|
|
1443 |
||
1444 |
||
1445 |
return(header); |
|
1446 |
}
|
|
1447 |
||
1448 |
||
1449 |
void
|
|
1450 |
pine_free_env(METAENV **menv) |
|
1451 |
{
|
|
1452 |
int cnt; |
|
1453 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1454 |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1455 |
if((*menv)->local){ |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1456 |
for(cnt = 0; pf_template && pf_template[cnt].name; cnt++) |
1457 |
;
|
|
1458 |
||
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1459 |
for(; cnt >= 0; cnt--){ |
1460 |
if((*menv)->local[cnt].textbuf) |
|
1461 |
fs_give((void **) &(*menv)->local[cnt].textbuf); |
|
1462 |
||
1463 |
fs_give((void **) &(*menv)->local[cnt].name); |
|
1464 |
}
|
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1465 |
|
1466 |
fs_give((void **) &(*menv)->local); |
|
1467 |
}
|
|
1468 |
||
1469 |
if((*menv)->sending_order) |
|
1470 |
fs_give((void **) &(*menv)->sending_order); |
|
1471 |
||
1472 |
fs_give((void **) menv); |
|
1473 |
}
|
|
1474 |
||
1475 |
||
1476 |
/*----------------------------------------------------------------------
|
|
1477 |
Check for addresses the user is not permitted to send to, or probably
|
|
1478 |
doesn't want to send to
|
|
1479 |
|
|
1480 |
Returns: 0 if OK
|
|
1481 |
1 if there are only empty groups
|
|
1482 |
-1 if the message shouldn't be sent
|
|
1483 |
||
1484 |
Queues a message indicating what happened
|
|
1485 |
---*/
|
|
1486 |
int
|
|
1487 |
check_addresses(METAENV *header) |
|
1488 |
{
|
|
1489 |
PINEFIELD *pf; |
|
1490 |
ADDRESS *a; |
|
1491 |
int send_daemon = 0, rv = CA_EMPTY; |
|
1492 |
||
1493 |
/*---- Is he/she trying to send mail to the mailer-daemon ----*/
|
|
1494 |
for(pf = header->local; pf && pf->name; pf = pf->next) |
|
1495 |
if(pf->type == Address && pf->rcptto && pf->addr && *pf->addr) |
|
1496 |
for(a = *pf->addr; a != NULL; a = a->next){ |
|
1497 |
if(a->host && (a->host[0] == '.' |
|
1498 |
|| (F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global) |
|
1499 |
&& a->host[0] == '@'))){ |
|
1500 |
q_status_message2(SM_ORDER, 4, 7, |
|
1501 |
/* TRANSLATORS: First arg is the address we can't
|
|
1502 |
send to, second arg is "not in addressbook". */
|
|
1503 |
_("Can't send to address %s: %s"), |
|
1504 |
a->mailbox, |
|
1505 |
(a->host[0] == '.') |
|
1506 |
? a->host |
|
1507 |
: _("not in addressbook")); |
|
1508 |
return(CA_BAD); |
|
1509 |
}
|
|
1510 |
else if(ps_global->restricted |
|
1511 |
&& !address_is_us(*pf->addr, ps_global)){ |
|
1512 |
q_status_message(SM_ORDER, 3, 3, |
|
1513 |
"Restricted demo version of Alpine. You may only send mail to yourself"); |
|
1514 |
return(CA_BAD); |
|
1515 |
}
|
|
1516 |
else if(a->mailbox && strucmp(a->mailbox, "mailer-daemon") == 0 && !send_daemon){ |
|
1517 |
send_daemon = 1; |
|
1518 |
rv = (pith_opt_daemon_confirm && (*pith_opt_daemon_confirm)()) ? CA_OK : CA_BAD; |
|
1519 |
}
|
|
1520 |
else if(a->mailbox && a->host){ |
|
1521 |
rv = CA_OK; |
|
1522 |
}
|
|
1523 |
}
|
|
1524 |
||
1525 |
return(rv); |
|
1526 |
}
|
|
1527 |
||
1528 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1529 |
/*
|
1530 |
* If this isn't general enough we can modify it. The value passed in
|
|
1531 |
* is expected to be one of the desc settings from the priorities array,
|
|
1532 |
* like "High". The header value is X-Priority: 2 (High)
|
|
1533 |
* or something similar. If value doesn't match any of the values then
|
|
1534 |
* the actual value is used instead.
|
|
1535 |
*/
|
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
1536 |
PINEFIELD * |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1537 |
set_priority_header(METAENV *header, char *value) |
1538 |
{
|
|
1539 |
PINEFIELD *pf; |
|
1540 |
||
1541 |
for(pf = header->local; pf && pf->name; pf = pf->next) |
|
1542 |
if(pf->type == FreeText && !strcmp(pf->name, PRIORITYNAME)) |
|
1543 |
break; |
|
1544 |
||
1545 |
if(pf){ |
|
1546 |
if(pf->textbuf) |
|
1547 |
fs_give((void **) &pf->textbuf); |
|
1548 |
||
1549 |
if(value){ |
|
1550 |
PRIORITY_S *p; |
|
1551 |
||
1552 |
for(p = priorities; p && p->desc; p++) |
|
1553 |
if(!strcmp(p->desc, value)) |
|
1554 |
break; |
|
1555 |
||
1556 |
if(p && p->desc){ |
|
1557 |
char buf[100]; |
|
1558 |
||
1559 |
snprintf(buf, sizeof(buf), "%d (%s)", p->val, p->desc); |
|
1560 |
pf->textbuf = cpystr(buf); |
|
1561 |
}
|
|
1562 |
else
|
|
1563 |
pf->textbuf = cpystr(value); |
|
1564 |
}
|
|
1565 |
}
|
|
1566 |
}
|
|
1567 |
||
1568 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1569 |
/*----------------------------------------------------------------------
|
1570 |
Set answered flags for messages specified by reply structure
|
|
1571 |
|
|
1572 |
Args: reply --
|
|
1573 |
||
1574 |
Returns: with appropriate flags set and index cache entries suitably tweeked
|
|
1575 |
----*/
|
|
1576 |
void
|
|
1577 |
update_answered_flags(REPLY_S *reply) |
|
1578 |
{
|
|
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
1579 |
char *seq = NULL, *p; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1580 |
long i, ourstream = 0, we_cancel = 0; |
1581 |
MAILSTREAM *stream = NULL; |
|
1582 |
||
1583 |
/* nothing to flip in a pseudo reply */
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1584 |
if(reply && (reply->msgno || reply->uid)){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1585 |
int j; |
1586 |
MAILSTREAM *m; |
|
1587 |
||
1588 |
/*
|
|
1589 |
* If an established stream will do, use it, else
|
|
1590 |
* build one unless we have an array of msgno's...
|
|
1591 |
*
|
|
1592 |
* I was just mimicking what was already here. I don't really
|
|
1593 |
* understand why we use strcmp instead of same_stream_and_mailbox().
|
|
1594 |
* Or sp_stream_get(reply->mailbox, SP_MATCH).
|
|
1595 |
* Hubert 2003-07-09
|
|
1596 |
*/
|
|
1597 |
for(j = 0; !stream && j < ps_global->s_pool.nstream; j++){ |
|
1598 |
m = ps_global->s_pool.streams[j]; |
|
1599 |
if(m && reply->mailbox && m->mailbox |
|
1600 |
&& !strcmp(reply->mailbox, m->mailbox)) |
|
1601 |
stream = m; |
|
1602 |
}
|
|
1603 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1604 |
if(!stream && reply->msgno) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1605 |
return; |
1606 |
||
1607 |
/*
|
|
1608 |
* This is here only for people who ran pine4.42 and are
|
|
1609 |
* processing postponed mail from 4.42 now. Pine4.42 saved the
|
|
1610 |
* original mailbox name in the canonical name's position in
|
|
1611 |
* the postponed-msgs folder so it won't match the canonical
|
|
1612 |
* name from the stream.
|
|
1613 |
*/
|
|
1614 |
if(!stream && (!reply->origmbox || |
|
1615 |
(reply->mailbox && |
|
1616 |
!strcmp(reply->origmbox, reply->mailbox)))) |
|
1617 |
stream = sp_stream_get(reply->mailbox, SP_MATCH); |
|
1618 |
||
1619 |
/* TRANSLATORS: program is busy updating the Answered flags so warns user */
|
|
1620 |
we_cancel = busy_cue(_("Updating \"Answered\" Flags"), NULL, 0); |
|
1621 |
if(!stream){ |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1622 |
if((stream = pine_mail_open(NULL, |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1623 |
reply->origmbox ? reply->origmbox |
1624 |
: reply->mailbox, |
|
1625 |
OP_SILENT | SP_USEPOOL | SP_TEMPUSE, |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1626 |
NULL)) != NULL){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1627 |
ourstream++; |
1628 |
}
|
|
1629 |
else{ |
|
1630 |
if(we_cancel) |
|
1631 |
cancel_busy_cue(0); |
|
1632 |
||
1633 |
return; |
|
1634 |
}
|
|
1635 |
}
|
|
1636 |
||
1637 |
if(stream->uid_validity == reply->data.uid.validity){ |
|
1638 |
for(i = 0L, p = tmp_20k_buf; reply->data.uid.msgs[i]; i++){ |
|
1639 |
if(i){ |
|
1640 |
sstrncpy(&p, ",", SIZEOF_20KBUF-(p-tmp_20k_buf)); |
|
1641 |
tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; |
|
1642 |
}
|
|
1643 |
||
1644 |
sstrncpy(&p, ulong2string(reply->data.uid.msgs[i]), |
|
1645 |
SIZEOF_20KBUF-(p-tmp_20k_buf)); |
|
1646 |
tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; |
|
1647 |
}
|
|
1648 |
||
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
1649 |
if(reply->forwarded){ |
1650 |
/*
|
|
1651 |
* $Forwarded is a regular keyword so we only try to
|
|
1652 |
* set it if the stream allows keywords.
|
|
1653 |
* We could mess up if the stream has keywords but just
|
|
1654 |
* isn't allowing anymore and $Forwarded already exists,
|
|
1655 |
* but what are the odds?
|
|
1656 |
*/
|
|
1657 |
if(stream && stream->kwd_create) |
|
1658 |
mail_flag(stream, seq = cpystr(tmp_20k_buf), |
|
1659 |
FORWARDED_FLAG, |
|
1660 |
ST_SET | ((reply->uid) ? ST_UID : 0L)); |
|
1661 |
}
|
|
1662 |
else
|
|
1663 |
mail_flag(stream, seq = cpystr(tmp_20k_buf), |
|
1664 |
"\\ANSWERED", |
|
1665 |
ST_SET | ((reply->uid) ? ST_UID : 0L)); |
|
1666 |
||
1667 |
if(seq) |
|
1668 |
fs_give((void **)&seq); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1669 |
}
|
1670 |
||
1671 |
if(ourstream) |
|
1672 |
pine_mail_close(stream); /* clean up dangling stream */ |
|
1673 |
||
1674 |
if(we_cancel) |
|
1675 |
cancel_busy_cue(0); |
|
1676 |
}
|
|
1677 |
}
|
|
1678 |
||
1679 |
||
1680 |
/*----------------------------------------------------------------------
|
|
1681 |
Call the mailer, SMTP, sendmail or whatever
|
|
1682 |
|
|
1683 |
Args: header -- full header (envelope and local parts) of message to send
|
|
1684 |
body -- The full body of the message including text
|
|
1685 |
alt_smtp_servers --
|
|
1686 |
verbosefile -- non-null means caller wants verbose interaction and the resulting
|
|
1687 |
output file name to be returned
|
|
1688 |
||
1689 |
Returns: -1 if failed, 1 if succeeded
|
|
1690 |
----*/
|
|
1691 |
int
|
|
1692 |
call_mailer(METAENV *header, struct mail_bodystruct *body, char **alt_smtp_servers, |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1693 |
int flags, void (*bigresult_f)(char *, int), |
1694 |
void (*pipecb_f)(PIPE_S *, int, void *)) |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1695 |
{
|
1696 |
char error_buf[200], *error_mess = NULL, *postcmd; |
|
1697 |
ADDRESS *a; |
|
1698 |
ENVELOPE *fake_env = NULL; |
|
1699 |
int addr_error_count, we_cancel = 0; |
|
1700 |
long smtp_opts = 0L; |
|
1701 |
char *verbose_file = NULL; |
|
1702 |
BODY *bp = NULL; |
|
1703 |
PINEFIELD *pf; |
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
1704 |
BODY *origBody = body; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1705 |
|
1706 |
dprint((4, "Sending mail...\n")); |
|
1707 |
||
1708 |
/* Check for any recipients */
|
|
1709 |
for(pf = header->local; pf && pf->name; pf = pf->next) |
|
1710 |
if(pf->type == Address && pf->rcptto && pf->addr && *pf->addr) |
|
1711 |
break; |
|
1712 |
||
1713 |
if(!pf){ |
|
1714 |
q_status_message(SM_ORDER,3,3, |
|
1715 |
_("Can't send message. No recipients specified!")); |
|
1716 |
return(0); |
|
1717 |
}
|
|
1718 |
||
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
1719 |
#ifdef SMIME
|
1720 |
if(ps_global->smime && (ps_global->smime->do_encrypt || ps_global->smime->do_sign)){ |
|
1721 |
int result; |
|
1722 |
||
1723 |
STORE_S *so = lmc.so; |
|
1724 |
lmc.so = NULL; |
|
1725 |
||
1726 |
result = 1; |
|
1727 |
||
1728 |
if(ps_global->smime->do_encrypt) |
|
1729 |
result = encrypt_outgoing_message(header, &body); |
|
1730 |
||
1731 |
/* need to free new body from encrypt if sign fails? */
|
|
1732 |
if(result && ps_global->smime->do_sign) |
|
1733 |
result = sign_outgoing_message(header, &body, ps_global->smime->do_encrypt); |
|
1734 |
||
1735 |
lmc.so = so; |
|
1736 |
||
1737 |
if(!result) |
|
1738 |
return 0; |
|
1739 |
}
|
|
1740 |
#endif
|
|
1741 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1742 |
/* set up counts and such to keep track sent percentage */
|
1743 |
send_bytes_sent = 0; |
|
1744 |
gf_filter_init(); /* zero piped byte count, 'n */ |
|
1745 |
send_bytes_to_send = send_body_size(body); /* count body bytes */ |
|
1746 |
ps_global->c_client_error[0] = error_buf[0] = '\0'; |
|
1747 |
we_cancel = busy_cue(_("Sending mail"), |
|
1748 |
send_bytes_to_send ? sent_percent : NULL, 0); |
|
1749 |
||
1750 |
#ifndef _WINDOWS
|
|
1751 |
||
1752 |
/* try posting via local "<mta> <-t>" if specified */
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1753 |
if(mta_handoff(header, body, error_buf, sizeof(error_buf), bigresult_f, pipecb_f)){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1754 |
if(error_buf[0]) |
1755 |
error_mess = error_buf; |
|
1756 |
||
1757 |
goto done; |
|
1758 |
}
|
|
1759 |
||
1760 |
#endif
|
|
1761 |
||
1762 |
/*
|
|
1763 |
* If the user's asked for it, and we find that the first text
|
|
1764 |
* part (attachments all get b64'd) is non-7bit, ask for 8BITMIME.
|
|
1765 |
*/
|
|
1766 |
if(F_ON(F_ENABLE_8BIT, ps_global) && (bp = first_text_8bit(body))) |
|
1767 |
smtp_opts |= SOP_8BITMIME; |
|
1768 |
||
1769 |
#ifdef DEBUG
|
|
1770 |
#ifndef DEBUGJOURNAL
|
|
1771 |
if(debug > 5 || (flags & CM_VERBOSE)) |
|
1772 |
#endif
|
|
1773 |
smtp_opts |= SOP_DEBUG; |
|
1774 |
#endif
|
|
1775 |
||
1776 |
if(flags & (CM_DSN_NEVER | CM_DSN_DELAY | CM_DSN_SUCCESS | CM_DSN_FULL)){ |
|
1777 |
smtp_opts |= SOP_DSN; |
|
1778 |
if(!(flags & CM_DSN_NEVER)){ /* if never, don't turn others on */ |
|
1779 |
if(flags & CM_DSN_DELAY) |
|
1780 |
smtp_opts |= SOP_DSN_NOTIFY_DELAY; |
|
1781 |
if(flags & CM_DSN_SUCCESS) |
|
1782 |
smtp_opts |= SOP_DSN_NOTIFY_SUCCESS; |
|
1783 |
||
1784 |
/*
|
|
1785 |
* If it isn't Never, then we're always going to let them
|
|
1786 |
* know about failures. This means we don't allow for the
|
|
1787 |
* possibility of setting delay or success without failure.
|
|
1788 |
*/
|
|
1789 |
smtp_opts |= SOP_DSN_NOTIFY_FAILURE; |
|
1790 |
||
1791 |
if(flags & CM_DSN_FULL) |
|
1792 |
smtp_opts |= SOP_DSN_RETURN_FULL; |
|
1793 |
}
|
|
1794 |
}
|
|
1795 |
||
1796 |
||
1797 |
/*
|
|
1798 |
* Set global header pointer so post_rfc822_output can get at it when
|
|
1799 |
* it's called back from c-client's sending routine...
|
|
1800 |
*/
|
|
1801 |
send_header = header; |
|
1802 |
||
1803 |
/*
|
|
1804 |
* Fabricate a fake ENVELOPE to hand c-client's SMTP engine.
|
|
1805 |
* The purpose is to give smtp_mail the list for SMTP RCPT when
|
|
1806 |
* there are recipients in pine's METAENV that are outside c-client's
|
|
1807 |
* envelope.
|
|
1808 |
*
|
|
1809 |
* NOTE: If there aren't any, don't bother. Dealt with it below.
|
|
1810 |
*/
|
|
1811 |
for(pf = header->local; pf && pf->name; pf = pf->next) |
|
1812 |
if(pf->type == Address && pf->rcptto && pf->addr && *pf->addr |
|
1813 |
&& !(*pf->addr == header->env->to || *pf->addr == header->env->cc |
|
1814 |
|| *pf->addr == header->env->bcc)) |
|
1815 |
break; |
|
1816 |
||
1817 |
if(pf && pf->name){ |
|
1818 |
ADDRESS **tail; |
|
1819 |
||
1820 |
fake_env = (ENVELOPE *)fs_get(sizeof(ENVELOPE)); |
|
1821 |
memset(fake_env, 0, sizeof(ENVELOPE)); |
|
1822 |
fake_env->return_path = rfc822_cpy_adr(header->env->return_path); |
|
1823 |
tail = &(fake_env->to); |
|
1824 |
for(pf = header->local; pf && pf->name; pf = pf->next) |
|
1825 |
if(pf->type == Address && pf->rcptto && pf->addr && *pf->addr){ |
|
1826 |
*tail = rfc822_cpy_adr(*pf->addr); |
|
1827 |
while(*tail) |
|
1828 |
tail = &((*tail)->next); |
|
1829 |
}
|
|
1830 |
}
|
|
1831 |
||
1832 |
/*
|
|
1833 |
* Install our rfc822 output routine
|
|
1834 |
*/
|
|
1835 |
sending_hooks.rfc822_out = mail_parameters(NULL, GET_RFC822OUTPUT, NULL); |
|
1836 |
(void)mail_parameters(NULL, SET_RFC822OUTPUT, (void *)post_rfc822_output); |
|
1837 |
||
1838 |
/*
|
|
1839 |
* Allow for verbose posting
|
|
1840 |
*/
|
|
1841 |
(void) mail_parameters(NULL, SET_SMTPVERBOSE, |
|
1842 |
(void *) pine_smtp_verbose_out); |
|
1843 |
||
1844 |
/*
|
|
1845 |
* We do this because we want mm_log to put the error message into
|
|
1846 |
* c_client_error instead of showing it itself.
|
|
1847 |
*/
|
|
1848 |
ps_global->noshow_error = 1; |
|
1849 |
||
1850 |
/*
|
|
1851 |
* OK, who posts what? We tried an mta_handoff above, but there
|
|
1852 |
* was either none specified or we decided not to use it. So,
|
|
1853 |
* if there's an smtp-server defined anywhere,
|
|
1854 |
*/
|
|
1855 |
if(alt_smtp_servers && alt_smtp_servers[0] && alt_smtp_servers[0][0]){ |
|
1856 |
/*---------- SMTP ----------*/
|
|
1857 |
dprint((4, "call_mailer: via TCP (%s)\n", |
|
1858 |
alt_smtp_servers[0])); |
|
1859 |
TIME_STAMP("smtp-open start (tcp)", 1); |
|
1860 |
sending_stream = smtp_open(alt_smtp_servers, smtp_opts); |
|
1861 |
}
|
|
1862 |
else if(ps_global->VAR_SMTP_SERVER && ps_global->VAR_SMTP_SERVER[0] |
|
1863 |
&& ps_global->VAR_SMTP_SERVER[0][0]){ |
|
1864 |
/*---------- SMTP ----------*/
|
|
1865 |
dprint((4, "call_mailer: via TCP\n")); |
|
1866 |
TIME_STAMP("smtp-open start (tcp)", 1); |
|
1867 |
sending_stream = smtp_open(ps_global->VAR_SMTP_SERVER, smtp_opts); |
|
1868 |
}
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1869 |
else if((postcmd = smtp_command(ps_global->c_client_error, sizeof(ps_global->c_client_error))) != NULL){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1870 |
char *cmdlist[2]; |
1871 |
||
1872 |
/*----- Send via LOCAL SMTP agent ------*/
|
|
1873 |
dprint((4, "call_mailer: via \"%s\"\n", postcmd)); |
|
1874 |
||
1875 |
TIME_STAMP("smtp-open start (pipe)", 1); |
|
1876 |
fs_give((void **) &postcmd); |
|
1877 |
cmdlist[0] = "localhost"; |
|
1878 |
cmdlist[1] = NULL; |
|
1879 |
sending_stream = smtp_open_full(&piped_io, cmdlist, "smtp", |
|
1880 |
SMTPTCPPORT, smtp_opts); |
|
1881 |
/* BUG: should provide separate stderr output! */
|
|
1882 |
}
|
|
1883 |
||
1884 |
ps_global->noshow_error = 0; |
|
1885 |
||
1886 |
TIME_STAMP("smtp open", 1); |
|
1887 |
if(sending_stream){ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1888 |
unsigned short save_encoding, added_encoding; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1889 |
|
1890 |
dprint((1, "Opened SMTP server \"%s\"\n", |
|
1891 |
net_host(sending_stream->netstream) |
|
1892 |
? net_host(sending_stream->netstream) : "?")); |
|
1893 |
||
1894 |
if(flags & CM_VERBOSE){ |
|
1895 |
TIME_STAMP("verbose start", 1); |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1896 |
if((verbose_file = temp_nam(NULL, "sd")) != NULL){ |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
1897 |
if((verbose_send_output = our_fopen(verbose_file, "w")) != NULL){ |
1898 |
if(!smtp_verbose(sending_stream)){ |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1899 |
snprintf(error_mess = error_buf, sizeof(error_buf), |
1900 |
"Mail not sent. VERBOSE mode error%s%.50s.", |
|
1901 |
(sending_stream && sending_stream->reply) |
|
1902 |
? ": ": "", |
|
1903 |
(sending_stream && sending_stream->reply) |
|
1904 |
? sending_stream->reply : ""); |
|
1905 |
error_buf[sizeof(error_buf)-1] = '\0'; |
|
1906 |
}
|
|
1907 |
}
|
|
1908 |
else{ |
|
1909 |
our_unlink(verbose_file); |
|
1910 |
strncpy(error_mess = error_buf, |
|
1911 |
"Can't open tmp file for VERBOSE mode.", sizeof(error_buf)); |
|
1912 |
error_buf[sizeof(error_buf)-1] = '\0'; |
|
1913 |
}
|
|
1914 |
}
|
|
1915 |
else{ |
|
1916 |
strncpy(error_mess = error_buf, |
|
1917 |
"Can't create tmp file name for VERBOSE mode.", sizeof(error_buf)); |
|
1918 |
error_buf[sizeof(error_buf)-1] = '\0'; |
|
1919 |
}
|
|
1920 |
||
1921 |
TIME_STAMP("verbose end", 1); |
|
1922 |
}
|
|
1923 |
||
1924 |
/*
|
|
1925 |
* Before we actually send data, see if we have to protect
|
|
1926 |
* the first text body part from getting encoded. We protect
|
|
1927 |
* it from getting encoded in "pine_rfc822_output_body" by
|
|
1928 |
* temporarily inventing a synonym for ENC8BIT...
|
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
1929 |
* This works like so:
|
1930 |
* Suppose bp->encoding is set to ENC8BIT.
|
|
1931 |
* We change that here to some unused value (added_encoding) and
|
|
1932 |
* set body_encodings[added_encoding] to "8BIT".
|
|
1933 |
* Then post_rfc822_output is called which calls
|
|
1934 |
* pine_rfc822_output_body. Inside that routine
|
|
1935 |
* pine_write_body_header writes out the encoding for the
|
|
1936 |
* part. Normally it would see encoding == ENC8BIT and it would
|
|
1937 |
* change that to QUOTED-PRINTABLE, but since encoding has been
|
|
1938 |
* set to added_encoding it uses body_encodings[added_encoding]
|
|
1939 |
* which is "8BIT" instead. Then the actual body is written by
|
|
1940 |
* pine_write_body_header which does not do the gf_8bit_qp
|
|
1941 |
* filtering because encoding != ENC8BIT (instead it's equal
|
|
1942 |
* to added_encoding).
|
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1943 |
*/
|
1944 |
if(bp && sending_stream->protocol.esmtp.eightbit.ok |
|
1945 |
&& sending_stream->protocol.esmtp.eightbit.want){ |
|
1946 |
int i; |
|
1947 |
||
1948 |
for(i = 0; (i <= ENCMAX) && body_encodings[i]; i++) |
|
1949 |
;
|
|
1950 |
||
1951 |
if(i > ENCMAX){ /* no empty encoding slots! */ |
|
1952 |
bp = NULL; |
|
1953 |
}
|
|
1954 |
else { |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1955 |
added_encoding = i; |
1956 |
body_encodings[added_encoding] = body_encodings[ENC8BIT]; |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1957 |
save_encoding = bp->encoding; |
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
1958 |
bp->encoding = added_encoding; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
1959 |
}
|
1960 |
}
|
|
1961 |
||
1962 |
if(sending_stream->protocol.esmtp.ok |
|
1963 |
&& sending_stream->protocol.esmtp.dsn.want |
|
1964 |
&& !sending_stream->protocol.esmtp.dsn.ok) |
|
1965 |
q_status_message(SM_ORDER,3,3, |
|
1966 |
_("Delivery Status Notification not available from this server.")); |
|
1967 |
||
1968 |
TIME_STAMP("smtp start", 1); |
|
1969 |
if(!error_mess && !smtp_mail(sending_stream, "MAIL", |
|
1970 |
fake_env ? fake_env : header->env, body)){ |
|
1971 |
||
1972 |
snprintf(error_buf, sizeof(error_buf), |
|
1973 |
_("Mail not sent. Sending error%s%s"), |
|
1974 |
(sending_stream && sending_stream->reply) ? ": ": ".", |
|
1975 |
(sending_stream && sending_stream->reply) |
|
1976 |
? sending_stream->reply : ""); |
|
1977 |
error_buf[sizeof(error_buf)-1] = '\0'; |
|
1978 |
dprint((1, error_buf)); |
|
1979 |
addr_error_count = 0; |
|
1980 |
if(fake_env){ |
|
1981 |
for(a = fake_env->to; a != NULL; a = a->next) |
|
1982 |
if(a->error != NULL){ |
|
1983 |
if(addr_error_count++ < MAX_ADDR_ERROR){ |
|
1984 |
||
1985 |
/*
|
|
1986 |
* Too complicated to figure out which header line
|
|
1987 |
* has the error in the fake_env case, so just
|
|
1988 |
* leave cursor at default.
|
|
1989 |
*/
|
|
1990 |
||
1991 |
||
1992 |
if(error_mess) /* previous error? */ |
|
1993 |
q_status_message(SM_ORDER, 4, 7, error_mess); |
|
1994 |
||
1995 |
error_mess = tidy_smtp_mess(a->error, |
|
1996 |
_("Mail not sent: %.80s"), |
|
1997 |
error_buf, sizeof(error_buf)); |
|
1998 |
}
|
|
1999 |
||
2000 |
dprint((1, "Send Error: \"%s\"\n", |
|
2001 |
a->error)); |
|
2002 |
}
|
|
2003 |
}
|
|
2004 |
else{ |
|
2005 |
for(pf = header->local; pf && pf->name; pf = pf->next) |
|
2006 |
if(pf->type == Address && pf->rcptto && pf->addr && *pf->addr) |
|
2007 |
for(a = *pf->addr; a != NULL; a = a->next) |
|
2008 |
if(a->error != NULL){ |
|
2009 |
if(addr_error_count++ < MAX_ADDR_ERROR){ |
|
2010 |
||
2011 |
if(error_mess) /* previous error? */ |
|
2012 |
q_status_message(SM_ORDER, 4, 7, error_mess); |
|
2013 |
||
2014 |
error_mess = tidy_smtp_mess(a->error, |
|
2015 |
_("Mail not sent: %.80s"), |
|
2016 |
error_buf, sizeof(error_buf)); |
|
2017 |
}
|
|
2018 |
||
2019 |
dprint((1, "Send Error: \"%s\"\n", |
|
2020 |
a->error)); |
|
2021 |
}
|
|
2022 |
}
|
|
2023 |
||
2024 |
if(!error_mess) |
|
2025 |
error_mess = error_buf; |
|
2026 |
}
|
|
2027 |
||
2028 |
/* repair modified "body_encodings" array? */
|
|
2029 |
if(bp && sending_stream->protocol.esmtp.eightbit.ok |
|
2030 |
&& sending_stream->protocol.esmtp.eightbit.want){ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
2031 |
body_encodings[added_encoding] = NULL; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2032 |
bp->encoding = save_encoding; |
2033 |
}
|
|
2034 |
||
2035 |
TIME_STAMP("smtp closing", 1); |
|
2036 |
smtp_close(sending_stream); |
|
2037 |
sending_stream = NULL; |
|
2038 |
TIME_STAMP("smtp done", 1); |
|
2039 |
}
|
|
2040 |
else if(!error_mess){ |
|
2041 |
snprintf(error_mess = error_buf, sizeof(error_buf), _("Error sending%.2s%.80s"), |
|
2042 |
ps_global->c_client_error[0] ? ": " : "", |
|
2043 |
ps_global->c_client_error); |
|
2044 |
error_buf[sizeof(error_buf)-1] = '\0'; |
|
2045 |
}
|
|
2046 |
||
2047 |
if(verbose_file){ |
|
2048 |
if(verbose_send_output){ |
|
2049 |
TIME_STAMP("verbose start", 1); |
|
2050 |
fclose(verbose_send_output); |
|
2051 |
verbose_send_output = NULL; |
|
2052 |
q_status_message(SM_ORDER, 0, 3, "Verbose SMTP output received"); |
|
2053 |
||
2054 |
if(bigresult_f) |
|
2055 |
(*bigresult_f)(verbose_file, CM_BR_VERBOSE); |
|
2056 |
||
2057 |
TIME_STAMP("verbose end", 1); |
|
2058 |
}
|
|
2059 |
||
2060 |
fs_give((void **)&verbose_file); |
|
2061 |
}
|
|
2062 |
||
2063 |
/*
|
|
2064 |
* Restore original 822 emitter...
|
|
2065 |
*/
|
|
2066 |
(void) mail_parameters(NULL, SET_RFC822OUTPUT, sending_hooks.rfc822_out); |
|
2067 |
||
2068 |
if(fake_env) |
|
2069 |
mail_free_envelope(&fake_env); |
|
2070 |
||
2071 |
done: |
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
2072 |
|
2073 |
#ifdef SMIME
|
|
2074 |
/* Free replacement encrypted body */
|
|
2075 |
if(F_OFF(F_DONT_DO_SMIME, ps_global) && body != origBody){ |
|
2076 |
||
2077 |
if(body->type == TYPEMULTIPART){ |
|
2078 |
/* Just get rid of first part, it's actually origBody */
|
|
2079 |
void *x = body->nested.part; |
|
2080 |
||
2081 |
body->nested.part = body->nested.part->next; |
|
2082 |
||
2083 |
fs_give(&x); |
|
2084 |
}
|
|
2085 |
||
2086 |
pine_free_body(&body); |
|
2087 |
}
|
|
2088 |
#endif
|
|
2089 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2090 |
if(we_cancel) |
2091 |
cancel_busy_cue(0); |
|
2092 |
||
2093 |
TIME_STAMP("call_mailer done", 1); |
|
2094 |
/*-------- Did message make it ? ----------*/
|
|
2095 |
if(error_mess){ |
|
2096 |
/*---- Error sending mail -----*/
|
|
2097 |
if(lmc.so && !lmc.all_written) |
|
2098 |
so_give(&lmc.so); |
|
2099 |
||
2100 |
if(error_mess){ |
|
2101 |
q_status_message(SM_ORDER | SM_DING, 4, 7, error_mess); |
|
2102 |
dprint((1, "call_mailer ERROR: %s\n", error_mess)); |
|
2103 |
}
|
|
2104 |
||
2105 |
return(-1); |
|
2106 |
}
|
|
2107 |
else{ |
|
2108 |
lmc.all_written = 1; |
|
2109 |
return(1); |
|
2110 |
}
|
|
2111 |
}
|
|
2112 |
||
2113 |
||
2114 |
/*
|
|
2115 |
* write_postponed - exported method to write the given message
|
|
2116 |
* to the postponed folder
|
|
2117 |
*/
|
|
2118 |
int
|
|
2119 |
write_postponed(METAENV *header, struct mail_bodystruct *body) |
|
2120 |
{
|
|
2121 |
char **pp, *folder; |
|
2122 |
int rv = 0, sz; |
|
2123 |
CONTEXT_S *fcc_cntxt = NULL; |
|
2124 |
PINEFIELD *pf; |
|
2125 |
static char *writem[] = {"To", "References", "Fcc", "X-Reply-UID", NULL}; |
|
2126 |
||
2127 |
if(!ps_global->VAR_POSTPONED_FOLDER |
|
2128 |
|| !ps_global->VAR_POSTPONED_FOLDER[0]){ |
|
2129 |
q_status_message(SM_ORDER | SM_DING, 3, 3, |
|
2130 |
_("No postponed file defined")); |
|
2131 |
return(-1); |
|
2132 |
}
|
|
2133 |
||
2134 |
folder = cpystr(ps_global->VAR_POSTPONED_FOLDER); |
|
2135 |
||
2136 |
lmc.all_written = lmc.text_written = lmc.text_only = 0; |
|
2137 |
||
2138 |
lmc.so = open_fcc(folder, &fcc_cntxt, 1, NULL, NULL); |
|
2139 |
||
2140 |
if(lmc.so){ |
|
2141 |
/* BUG: writem sufficient ? */
|
|
2142 |
for(pf = header->local; pf && pf->name; pf = pf->next) |
|
2143 |
for(pp = writem; *pp; pp++) |
|
2144 |
if(!strucmp(pf->name, *pp)){ |
|
2145 |
pf->localcopy = 1; |
|
2146 |
pf->writehdr = 1; |
|
2147 |
break; |
|
2148 |
}
|
|
2149 |
||
2150 |
/*
|
|
2151 |
* Work around c-client reply-to bug. C-client will
|
|
2152 |
* return a reply_to in an envelope even if there is
|
|
2153 |
* no reply-to header field. We want to note here whether
|
|
2154 |
* the reply-to is real or not.
|
|
2155 |
*/
|
|
2156 |
if(header->env->reply_to || hdr_is_in_list("reply-to", header->custom)) |
|
2157 |
for(pf = header->local; pf; pf = pf->next) |
|
2158 |
if(!strcmp(pf->name, "Reply-To")){ |
|
2159 |
pf->writehdr = 1; |
|
2160 |
pf->localcopy = 1; |
|
2161 |
if(header->env->reply_to) |
|
2162 |
pf->textbuf = cpystr("Full"); |
|
2163 |
else
|
|
2164 |
pf->textbuf = cpystr("Empty"); |
|
2165 |
}
|
|
2166 |
||
2167 |
/*
|
|
2168 |
* Write the list of custom headers to the
|
|
2169 |
* X-Our-Headers header so that we can recover the
|
|
2170 |
* list in redraft.
|
|
2171 |
*/
|
|
2172 |
sz = 0; |
|
2173 |
for(pf = header->custom; pf && pf->name; pf = pf->next) |
|
2174 |
sz += strlen(pf->name) + 1; |
|
2175 |
||
2176 |
if(sz){ |
|
2177 |
int i; |
|
1.1.8
by Asheesh Laroia
Import upstream version 2.02 |
2178 |
char *pstart, *pend; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2179 |
|
2180 |
for(i = 0, pf = header->local; i != N_OURHDRS; i++, pf = pf->next) |
|
2181 |
;
|
|
2182 |
||
2183 |
pf->writehdr = 1; |
|
2184 |
pf->localcopy = 1; |
|
1.1.8
by Asheesh Laroia
Import upstream version 2.02 |
2185 |
pf->textbuf = pstart = pend = (char *) fs_get(sz + 1); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2186 |
pf->text = &pf->textbuf; |
1.1.8
by Asheesh Laroia
Import upstream version 2.02 |
2187 |
pf->textbuf[sz] = '\0'; /* tie off overflow */ |
2188 |
/* note: "pf" overloaded */
|
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2189 |
for(pf = header->custom; pf && pf->name; pf = pf->next){ |
1.1.8
by Asheesh Laroia
Import upstream version 2.02 |
2190 |
int r = sz - (pend - pstart); /* remaining buffer */ |
2191 |
||
2192 |
if(r > 0 && r != sz){ |
|
2193 |
r--; |
|
2194 |
*pend++ = ','; |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2195 |
}
|
2196 |
||
1.1.8
by Asheesh Laroia
Import upstream version 2.02 |
2197 |
sstrncpy(&pend, pf->name, r); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2198 |
}
|
2199 |
}
|
|
2200 |
||
2201 |
if(pine_rfc822_output(header, body, NULL, NULL) < 0 |
|
2202 |
|| write_fcc(folder, fcc_cntxt, lmc.so, NULL, "postponed message", NULL) < 0) |
|
2203 |
rv = -1; |
|
2204 |
||
2205 |
so_give(&lmc.so); |
|
2206 |
}
|
|
2207 |
else { |
|
2208 |
q_status_message1(SM_ORDER | SM_DING, 3, 3, |
|
2209 |
"Can't allocate internal storage: %s ", |
|
2210 |
error_description(errno)); |
|
2211 |
rv = -1; |
|
2212 |
}
|
|
2213 |
||
2214 |
fs_give((void **) &folder); |
|
2215 |
return(rv); |
|
2216 |
}
|
|
2217 |
||
2218 |
||
2219 |
int
|
|
2220 |
commence_fcc(char *fcc, CONTEXT_S **fcc_cntxt, int forced) |
|
2221 |
{
|
|
2222 |
if(fcc && *fcc){ |
|
2223 |
lmc.all_written = lmc.text_written = 0; |
|
2224 |
lmc.text_only = F_ON(F_NO_FCC_ATTACH, ps_global) != 0; |
|
2225 |
return((lmc.so = open_fcc(fcc, fcc_cntxt, 0, NULL, NULL)) != NULL); |
|
2226 |
}
|
|
2227 |
else
|
|
2228 |
lmc.so = NULL; |
|
2229 |
||
2230 |
return(TRUE); |
|
2231 |
}
|
|
2232 |
||
2233 |
||
2234 |
int
|
|
2235 |
wrapup_fcc(char *fcc, CONTEXT_S *fcc_cntxt, METAENV *header, struct mail_bodystruct *body) |
|
2236 |
{
|
|
2237 |
int rv = TRUE; |
|
2238 |
||
2239 |
if(lmc.so){ |
|
2240 |
if(!header || pine_rfc822_output(header, body, NULL, NULL)){ |
|
2241 |
char label[50]; |
|
2242 |
||
2243 |
strncpy(label, "Fcc", sizeof(label)); |
|
2244 |
label[sizeof(label)-1] = '\0'; |
|
2245 |
if(strcmp(fcc, ps_global->VAR_DEFAULT_FCC)){ |
|
2246 |
snprintf(label + 3, sizeof(label)-3, " to %.40s", fcc); |
|
2247 |
label[sizeof(label)-1] = '\0'; |
|
2248 |
}
|
|
2249 |
||
2250 |
rv = write_fcc(fcc,fcc_cntxt,lmc.so,NULL,NULL,NULL); |
|
2251 |
}
|
|
2252 |
else{ |
|
2253 |
rv = FALSE; |
|
2254 |
}
|
|
2255 |
||
2256 |
so_give(&lmc.so); |
|
2257 |
}
|
|
2258 |
||
2259 |
return(rv); |
|
2260 |
}
|
|
2261 |
||
2262 |
||
2263 |
/*----------------------------------------------------------------------
|
|
2264 |
Checks to make sure the fcc is available and can be opened
|
|
2265 |
||
2266 |
Args: fcc -- the name of the fcc to create. It can't be NULL.
|
|
2267 |
fcc_cntxt -- Returns the context the fcc is in.
|
|
2268 |
force -- supress user option prompt
|
|
2269 |
||
2270 |
Returns allocated storage object on success, NULL on failure
|
|
2271 |
----*/
|
|
2272 |
STORE_S * |
|
2273 |
open_fcc(char *fcc, CONTEXT_S **fcc_cntxt, int force, char *err_prefix, char *err_suffix) |
|
2274 |
{
|
|
2275 |
int exists, ok = 0; |
|
2276 |
||
2277 |
ps_global->mm_log_error = 0; |
|
2278 |
||
2279 |
/*
|
|
2280 |
* check for fcc's existance...
|
|
2281 |
*/
|
|
2282 |
TIME_STAMP("open_fcc start", 1); |
|
2283 |
if(!is_absolute_path(fcc) && context_isambig(fcc) |
|
2284 |
&& (strucmp(ps_global->inbox_name, fcc) != 0)){ |
|
2285 |
int flip_dot = 0; |
|
2286 |
||
2287 |
/*
|
|
2288 |
* Don't want to preclude a user from Fcc'ing a .name'd folder
|
|
2289 |
*/
|
|
2290 |
if(F_OFF(F_ENABLE_DOT_FOLDERS, ps_global)){ |
|
2291 |
flip_dot = 1; |
|
2292 |
F_TURN_ON(F_ENABLE_DOT_FOLDERS, ps_global); |
|
2293 |
}
|
|
2294 |
||
2295 |
/*
|
|
2296 |
* We only want to set the "context" if fcc is an ambiguous
|
|
2297 |
* name. Otherwise, our "relativeness" rules for contexts
|
|
2298 |
* (implemented in context.c) might cause the name to be
|
|
2299 |
* interpreted in the wrong context...
|
|
2300 |
*/
|
|
2301 |
if(!(*fcc_cntxt || (*fcc_cntxt = default_save_context(ps_global->context_list)))) |
|
2302 |
*fcc_cntxt = ps_global->context_list; |
|
2303 |
||
2304 |
build_folder_list(NULL, *fcc_cntxt, fcc, NULL, BFL_FLDRONLY); |
|
2305 |
if(folder_index(fcc, *fcc_cntxt, FI_FOLDER) < 0){ |
|
2306 |
if(force |
|
2307 |
|| (pith_opt_save_create_prompt |
|
2308 |
&& (*pith_opt_save_create_prompt)(*fcc_cntxt, fcc, 0) > 0)){ |
|
2309 |
||
2310 |
ps_global->noshow_error = 1; |
|
2311 |
||
2312 |
if(context_create(*fcc_cntxt, NULL, fcc)) |
|
2313 |
ok++; |
|
2314 |
||
2315 |
ps_global->noshow_error = 0; |
|
2316 |
}
|
|
2317 |
else
|
|
2318 |
ok--; /* declined! */ |
|
2319 |
}
|
|
2320 |
else
|
|
2321 |
ok++; /* found! */ |
|
2322 |
||
2323 |
if(flip_dot) |
|
2324 |
F_TURN_OFF(F_ENABLE_DOT_FOLDERS, ps_global); |
|
2325 |
||
2326 |
free_folder_list(*fcc_cntxt); |
|
2327 |
}
|
|
2328 |
else if((exists = folder_exists(NULL, fcc)) != FEX_ERROR){ |
|
2329 |
if(exists & (FEX_ISFILE | FEX_ISDIR)){ |
|
2330 |
ok++; |
|
2331 |
}
|
|
2332 |
else{ |
|
2333 |
if(force |
|
2334 |
|| (pith_opt_save_create_prompt |
|
2335 |
&& (*pith_opt_save_create_prompt)(NULL, fcc, 0) > 0)){ |
|
2336 |
||
2337 |
ps_global->mm_log_error = 0; |
|
2338 |
ps_global->noshow_error = 1; |
|
2339 |
||
2340 |
ok = pine_mail_create(NULL, fcc) != 0L; |
|
2341 |
||
2342 |
ps_global->noshow_error = 0; |
|
2343 |
}
|
|
2344 |
else
|
|
2345 |
ok--; /* declined! */ |
|
2346 |
}
|
|
2347 |
}
|
|
2348 |
||
2349 |
TIME_STAMP("open_fcc done.", 1); |
|
2350 |
if(ok > 0){ |
|
2351 |
return(so_get(FCC_SOURCE, NULL, WRITE_ACCESS)); |
|
2352 |
}
|
|
2353 |
else{ |
|
2354 |
int l1, l2, l3, wid, w; |
|
2355 |
char *errstr, tmp[MAILTMPLEN]; |
|
2356 |
char *s1, *s2; |
|
2357 |
||
2358 |
if(ok == 0){ |
|
2359 |
if(ps_global->mm_log_error){ |
|
2360 |
s1 = err_prefix ? err_prefix : "Fcc Error: "; |
|
2361 |
s2 = err_suffix ? err_suffix : " Message NOT sent or copied."; |
|
2362 |
||
2363 |
l1 = strlen(s1); |
|
2364 |
l2 = strlen(s2); |
|
2365 |
l3 = strlen(ps_global->c_client_error); |
|
2366 |
wid = (ps_global->ttyo && ps_global->ttyo->screen_cols > 0) |
|
2367 |
? ps_global->ttyo->screen_cols : 80; |
|
2368 |
w = wid - l1 - l2 - 5; |
|
2369 |
||
2370 |
snprintf(errstr = tmp, sizeof(tmp), |
|
2371 |
"%.99s\"%.*s%.99s\".%.99s", |
|
2372 |
s1, |
|
2373 |
(l3 > w) ? MAX(w-3,0) : MAX(w,0), |
|
2374 |
ps_global->c_client_error, |
|
2375 |
(l3 > w) ? "..." : "", |
|
2376 |
s2); |
|
2377 |
tmp[sizeof(tmp)-1] = '\0'; |
|
2378 |
||
2379 |
}
|
|
2380 |
else
|
|
2381 |
errstr = _("Fcc creation error. Message NOT sent or copied."); |
|
2382 |
}
|
|
2383 |
else
|
|
2384 |
errstr = _("Fcc creation rejected. Message NOT sent or copied."); |
|
2385 |
||
2386 |
q_status_message(SM_ORDER | SM_DING, 3, 3, errstr); |
|
2387 |
}
|
|
2388 |
||
2389 |
return(NULL); |
|
2390 |
}
|
|
2391 |
||
2392 |
||
2393 |
/*----------------------------------------------------------------------
|
|
2394 |
mail_append() the fcc accumulated in temp_storage to proper destination
|
|
2395 |
||
2396 |
Args: fcc -- name of folder
|
|
2397 |
fcc_cntxt -- context for folder
|
|
2398 |
temp_storage -- String of file where Fcc has been accumulated
|
|
2399 |
||
2400 |
This copies the string of file to the actual folder, which might be IMAP
|
|
2401 |
or a disk folder. The temp_storage is freed after it is written.
|
|
2402 |
An error message is produced if this fails.
|
|
2403 |
----*/
|
|
2404 |
int
|
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2405 |
write_fcc(char *fcc, CONTEXT_S *fcc_cntxt, STORE_S *tmp_storage, |
2406 |
MAILSTREAM *stream, char *label, char *flags) |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2407 |
{
|
2408 |
STRING msg; |
|
2409 |
CONTEXT_S *cntxt; |
|
2410 |
int we_cancel = 0; |
|
2411 |
||
2412 |
if(!tmp_storage) |
|
2413 |
return(0); |
|
2414 |
||
2415 |
TIME_STAMP("write_fcc start.", 1); |
|
2416 |
dprint((4, "Writing %s\n", (label && *label) ? label : "")); |
|
2417 |
if(label && *label){ |
|
2418 |
char msg_buf[80]; |
|
2419 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
2420 |
strncpy(msg_buf, "Writing ", sizeof(msg_buf)); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2421 |
msg_buf[sizeof(msg_buf)-1] = '\0'; |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
2422 |
strncat(msg_buf, label, sizeof(msg_buf)-10); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2423 |
we_cancel = busy_cue(msg_buf, NULL, 0); |
2424 |
}
|
|
2425 |
else
|
|
2426 |
we_cancel = busy_cue(NULL, NULL, 1); |
|
2427 |
||
2428 |
so_seek(tmp_storage, 0L, 0); |
|
2429 |
||
2430 |
/*
|
|
2431 |
* Before changing this note that these lines depend on the
|
|
2432 |
* definition of FCC_SOURCE.
|
|
2433 |
*/
|
|
2434 |
INIT(&msg, mail_string, (void *)so_text(tmp_storage), |
|
2435 |
strlen((char *)so_text(tmp_storage))); |
|
2436 |
||
2437 |
cntxt = fcc_cntxt; |
|
2438 |
||
2439 |
if(!context_append_full(cntxt, stream, fcc, flags, NULL, &msg)){ |
|
2440 |
cancel_busy_cue(-1); |
|
2441 |
we_cancel = 0; |
|
2442 |
||
2443 |
q_status_message1(SM_ORDER | SM_DING, 3, 5, |
|
2444 |
"Write to \"%s\" FAILED!!!", fcc); |
|
2445 |
dprint((1, "ERROR appending %s in \"%s\"", |
|
2446 |
fcc ? fcc : "?", |
|
2447 |
(cntxt && cntxt->context) ? cntxt->context : "NULL")); |
|
2448 |
return(0); |
|
2449 |
}
|
|
2450 |
||
2451 |
if(we_cancel) |
|
2452 |
cancel_busy_cue(label ? 0 : -1); |
|
2453 |
||
2454 |
dprint((4, "done.\n")); |
|
2455 |
TIME_STAMP("write_fcc done.", 1); |
|
2456 |
return(1); |
|
2457 |
}
|
|
2458 |
||
2459 |
||
2460 |
/*
|
|
2461 |
* first_text_8bit - return TRUE if somewhere in the body 8BIT data's
|
|
2462 |
* contained.
|
|
2463 |
*/
|
|
2464 |
BODY * |
|
2465 |
first_text_8bit(struct mail_bodystruct *body) |
|
2466 |
{
|
|
2467 |
if(body->type == TYPEMULTIPART) /* advance to first contained part */ |
|
2468 |
body = &body->nested.part->body; |
|
2469 |
||
2470 |
return((body->type == TYPETEXT && body->encoding != ENC7BIT) |
|
2471 |
? body : NULL); |
|
2472 |
}
|
|
2473 |
||
2474 |
||
2475 |
/*
|
|
2476 |
* Build and return the "From:" address for outbound messages from
|
|
2477 |
* global data...
|
|
2478 |
*/
|
|
2479 |
ADDRESS * |
|
2480 |
generate_from(void) |
|
2481 |
{
|
|
2482 |
ADDRESS *addr = mail_newaddr(); |
|
2483 |
if(ps_global->VAR_PERSONAL_NAME){ |
|
2484 |
addr->personal = cpystr(ps_global->VAR_PERSONAL_NAME); |
|
2485 |
removing_leading_and_trailing_white_space(addr->personal); |
|
2486 |
if(addr->personal[0] == '\0') |
|
2487 |
fs_give((void **)&addr->personal); |
|
2488 |
}
|
|
2489 |
||
2490 |
addr->mailbox = cpystr(ps_global->VAR_USER_ID); |
|
2491 |
addr->host = cpystr(ps_global->maildomain); |
|
2492 |
removing_leading_and_trailing_white_space(addr->mailbox); |
|
2493 |
removing_leading_and_trailing_white_space(addr->host); |
|
2494 |
return(addr); |
|
2495 |
}
|
|
2496 |
||
2497 |
||
2498 |
/*
|
|
2499 |
* set_mime_type_by_grope - sniff the given storage object to determine its
|
|
2500 |
* type, subtype, encoding, and charset
|
|
2501 |
*
|
|
2502 |
* "Type" and "encoding" must be set before calling this routine.
|
|
2503 |
* If "type" is set to something other than TYPEOTHER on entry,
|
|
2504 |
* then that is the "type" we wish to use. Same for "encoding"
|
|
2505 |
* using ENCOTHER instead of TYPEOTHER. Otherwise, we
|
|
2506 |
* figure them out here. If "type" is already set, we also
|
|
2507 |
* leave subtype alone. If not, we figure out subtype here.
|
|
2508 |
* There is a chance that we will upgrade encoding to a "higher"
|
|
2509 |
* level. For example, if it comes in as 7BIT we may change
|
|
2510 |
* that to 8BIT if we find a From_ we want to escape.
|
|
2511 |
* We may also set the charset attribute if the type is TEXT.
|
|
2512 |
*
|
|
2513 |
* NOTE: this is rather inefficient if the store object is a CharStar
|
|
2514 |
* but the win is all types are handled the same
|
|
2515 |
*/
|
|
2516 |
void
|
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2517 |
set_mime_type_by_grope(struct mail_bodystruct *body) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2518 |
{
|
2519 |
#define RBUFSZ (8193)
|
|
2520 |
unsigned char *buf, *p, *bol; |
|
2521 |
register size_t n; |
|
2522 |
long max_line = 0L, |
|
2523 |
eight_bit_chars = 0L, |
|
2524 |
line_so_far = 0L, |
|
2525 |
len = 0L; |
|
2526 |
STORE_S *so = (STORE_S *)body->contents.text.data; |
|
2527 |
unsigned short new_encoding = ENCOTHER; |
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2528 |
int we_cancel = 0; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2529 |
#ifdef ENCODE_FROMS
|
2530 |
short froms = 0, dots = 0, |
|
2531 |
bmap = 0x1, dmap = 0x1; |
|
2532 |
#endif
|
|
2533 |
||
2534 |
we_cancel = busy_cue(NULL, NULL, 1); |
|
2535 |
||
2536 |
buf = (unsigned char *)fs_get(RBUFSZ); |
|
2537 |
so_seek(so, 0L, 0); |
|
2538 |
||
2539 |
for(n = 0; n < RBUFSZ-1 && so_readc(&buf[n], so) != 0; n++) |
|
2540 |
;
|
|
2541 |
||
2542 |
buf[n] = '\0'; |
|
2543 |
||
2544 |
if(n){ /* check first few bytes to look for magic numbers */ |
|
2545 |
if(body->type == TYPEOTHER){ |
|
2546 |
if(buf[0] == 'G' && buf[1] == 'I' && buf[2] == 'F'){ |
|
2547 |
body->type = TYPEIMAGE; |
|
2548 |
body->subtype = cpystr("GIF"); |
|
2549 |
}
|
|
2550 |
else if((n > 9) && buf[0] == 0xFF && buf[1] == 0xD8 |
|
2551 |
&& buf[2] == 0xFF && buf[3] == 0xE0 |
|
2552 |
&& !strncmp((char *)&buf[6], "JFIF", 4)){ |
|
2553 |
body->type = TYPEIMAGE; |
|
2554 |
body->subtype = cpystr("JPEG"); |
|
2555 |
}
|
|
2556 |
else if((buf[0] == 'M' && buf[1] == 'M') |
|
2557 |
|| (buf[0] == 'I' && buf[1] == 'I')){ |
|
2558 |
body->type = TYPEIMAGE; |
|
2559 |
body->subtype = cpystr("TIFF"); |
|
2560 |
}
|
|
2561 |
else if((buf[0] == '%' && buf[1] == '!') |
|
2562 |
|| (buf[0] == '\004' && buf[1] == '%' && buf[2] == '!')){ |
|
2563 |
body->type = TYPEAPPLICATION; |
|
2564 |
body->subtype = cpystr("PostScript"); |
|
2565 |
}
|
|
2566 |
else if(buf[0] == '%' && !strncmp((char *)buf+1, "PDF-", 4)){ |
|
2567 |
body->type = TYPEAPPLICATION; |
|
2568 |
body->subtype = cpystr("PDF"); |
|
2569 |
}
|
|
2570 |
else if(buf[0] == '.' && !strncmp((char *)buf+1, "snd", 3)){ |
|
2571 |
body->type = TYPEAUDIO; |
|
2572 |
body->subtype = cpystr("Basic"); |
|
2573 |
}
|
|
2574 |
else if((n > 3) && buf[0] == 0x00 && buf[1] == 0x05 |
|
2575 |
&& buf[2] == 0x16 && buf[3] == 0x00){ |
|
2576 |
body->type = TYPEAPPLICATION; |
|
2577 |
body->subtype = cpystr("APPLEFILE"); |
|
2578 |
}
|
|
2579 |
else if((n > 3) && buf[0] == 0x50 && buf[1] == 0x4b |
|
2580 |
&& buf[2] == 0x03 && buf[3] == 0x04){ |
|
2581 |
body->type = TYPEAPPLICATION; |
|
2582 |
body->subtype = cpystr("ZIP"); |
|
2583 |
}
|
|
2584 |
||
2585 |
/*
|
|
2586 |
* if type was set above, but no encoding specified, go
|
|
2587 |
* ahead and make it BASE64...
|
|
2588 |
*/
|
|
2589 |
if(body->type != TYPEOTHER && body->encoding == ENCOTHER) |
|
2590 |
body->encoding = ENCBINARY; |
|
2591 |
}
|
|
2592 |
}
|
|
2593 |
else{ |
|
2594 |
/* PROBLEM !!! */
|
|
2595 |
if(body->type == TYPEOTHER){ |
|
2596 |
body->type = TYPEAPPLICATION; |
|
2597 |
body->subtype = cpystr("octet-stream"); |
|
2598 |
if(body->encoding == ENCOTHER) |
|
2599 |
body->encoding = ENCBINARY; |
|
2600 |
}
|
|
2601 |
}
|
|
2602 |
||
2603 |
if (body->encoding == ENCOTHER || body->type == TYPEOTHER){ |
|
2604 |
#if defined(DOS) || defined(OS2) /* for binary file detection */ |
|
2605 |
int lastchar = '\0'; |
|
2606 |
#define BREAKOUT 300 /* a value that a character can't be */ |
|
2607 |
#endif
|
|
2608 |
||
2609 |
p = bol = buf; |
|
2610 |
len = n; |
|
2611 |
while (n--){ |
|
2612 |
/* Some people don't like quoted-printable caused by leading Froms */
|
|
2613 |
#ifdef ENCODE_FROMS
|
|
2614 |
Find_Froms(froms, dots, bmap, dmap, *p); |
|
2615 |
#endif
|
|
2616 |
if(*p == '\n'){ |
|
2617 |
max_line = MAX(max_line, line_so_far + p - bol); |
|
2618 |
bol = NULL; /* clear beginning of line */ |
|
2619 |
line_so_far = 0L; /* clear line count */ |
|
2620 |
#if defined(DOS) || defined(OS2)
|
|
2621 |
/* LF with no CR!! */
|
|
2622 |
if(lastchar != '\r') /* must be non-text data! */ |
|
2623 |
lastchar = BREAKOUT; |
|
2624 |
#endif
|
|
2625 |
}
|
|
2626 |
else if(*p & 0x80){ |
|
2627 |
eight_bit_chars++; |
|
2628 |
}
|
|
2629 |
else if(!*p){ |
|
2630 |
/* NULL found. Unless we're told otherwise, must be binary */
|
|
2631 |
if(body->type == TYPEOTHER){ |
|
2632 |
body->type = TYPEAPPLICATION; |
|
2633 |
body->subtype = cpystr("octet-stream"); |
|
2634 |
}
|
|
2635 |
||
2636 |
/*
|
|
2637 |
* The "TYPETEXT" here handles the case that the NULL
|
|
2638 |
* comes from imported text generated by some external
|
|
2639 |
* editor that permits or inserts NULLS. Otherwise,
|
|
2640 |
* assume it's a binary segment...
|
|
2641 |
*/
|
|
2642 |
new_encoding = (body->type==TYPETEXT) ? ENC8BIT : ENCBINARY; |
|
2643 |
||
2644 |
/*
|
|
2645 |
* Since we've already set encoding, count this as a
|
|
2646 |
* hi bit char and continue. The reason is that if this
|
|
2647 |
* is text, there may be a high percentage of encoded
|
|
2648 |
* characters, so base64 may get set below...
|
|
2649 |
*/
|
|
2650 |
if(body->type == TYPETEXT) |
|
2651 |
eight_bit_chars++; |
|
2652 |
else
|
|
2653 |
break; |
|
2654 |
}
|
|
2655 |
||
2656 |
#if defined(DOS) || defined(OS2) /* for binary file detection */ |
|
2657 |
if(lastchar != BREAKOUT) |
|
2658 |
lastchar = *p; |
|
2659 |
#endif
|
|
2660 |
||
2661 |
/* read another buffer in */
|
|
2662 |
if(n == 0){ |
|
2663 |
if(bol) |
|
2664 |
line_so_far += p - bol; |
|
2665 |
||
2666 |
for (n = 0; n < RBUFSZ-1 && so_readc(&buf[n], so) != 0; n++) |
|
2667 |
;
|
|
2668 |
||
2669 |
len += n; |
|
2670 |
p = buf; |
|
2671 |
}
|
|
2672 |
else
|
|
2673 |
p++; |
|
2674 |
||
2675 |
/*
|
|
2676 |
* If there's no beginning-of-line pointer, then we must
|
|
2677 |
* have seen an end-of-line. Set bol to the start of the
|
|
2678 |
* new line...
|
|
2679 |
*/
|
|
2680 |
if(!bol) |
|
2681 |
bol = p; |
|
2682 |
||
2683 |
#if defined(DOS) || defined(OS2) /* for binary file detection */ |
|
2684 |
/* either a lone \r or lone \n indicate binary file */
|
|
2685 |
if(lastchar == '\r' || lastchar == BREAKOUT){ |
|
2686 |
if(lastchar == BREAKOUT || n == 0 || *p != '\n'){ |
|
2687 |
if(body->type == TYPEOTHER){ |
|
2688 |
body->type = TYPEAPPLICATION; |
|
2689 |
body->subtype = cpystr("octet-stream"); |
|
2690 |
}
|
|
2691 |
||
2692 |
new_encoding = ENCBINARY; |
|
2693 |
break; |
|
2694 |
}
|
|
2695 |
}
|
|
2696 |
#endif
|
|
2697 |
}
|
|
2698 |
}
|
|
2699 |
||
2700 |
/* stash away for later */
|
|
2701 |
so_attr(so, "maxline", long2string(max_line)); |
|
2702 |
||
2703 |
if(body->encoding == ENCOTHER || body->type == TYPEOTHER){ |
|
2704 |
/*
|
|
2705 |
* Since the type or encoding aren't set yet, fall thru a
|
|
2706 |
* series of tests to make sure an adequate type and
|
|
2707 |
* encoding are set...
|
|
2708 |
*/
|
|
2709 |
||
2710 |
if(max_line >= 1000L){ /* 1000 comes from rfc821 */ |
|
2711 |
if(body->type == TYPEOTHER){ |
|
2712 |
/*
|
|
2713 |
* Since the types not set, then we didn't find a NULL.
|
|
2714 |
* If there's no NULL, then this is likely text. However,
|
|
2715 |
* since we can't be *completely* sure, we set it to
|
|
2716 |
* the generic type.
|
|
2717 |
*/
|
|
2718 |
body->type = TYPEAPPLICATION; |
|
2719 |
body->subtype = cpystr("octet-stream"); |
|
2720 |
}
|
|
2721 |
||
2722 |
if(new_encoding != ENCBINARY) |
|
2723 |
/*
|
|
2724 |
* As with NULL handling, if we're told it's text,
|
|
2725 |
* qp-encode it, else it gets base 64...
|
|
2726 |
*/
|
|
2727 |
new_encoding = (body->type == TYPETEXT) ? ENC8BIT : ENCBINARY; |
|
2728 |
}
|
|
2729 |
||
2730 |
if(eight_bit_chars == 0L){ |
|
2731 |
if(body->type == TYPEOTHER) |
|
2732 |
body->type = TYPETEXT; |
|
2733 |
||
2734 |
if(new_encoding == ENCOTHER) |
|
2735 |
new_encoding = ENC7BIT; /* short lines, no 8 bit */ |
|
2736 |
}
|
|
2737 |
else if(len <= 3000L || (eight_bit_chars * 100L)/len < 30L){ |
|
2738 |
/*
|
|
2739 |
* The 30% threshold is based on qp encoded readability
|
|
2740 |
* on non-MIME UA's.
|
|
2741 |
*/
|
|
2742 |
if(body->type == TYPEOTHER) |
|
2743 |
body->type = TYPETEXT; |
|
2744 |
||
2745 |
if(new_encoding != ENCBINARY) |
|
2746 |
new_encoding = ENC8BIT; /* short lines, < 30% 8 bit chars */ |
|
2747 |
}
|
|
2748 |
else{ |
|
2749 |
if(body->type == TYPEOTHER){ |
|
2750 |
body->type = TYPEAPPLICATION; |
|
2751 |
body->subtype = cpystr("octet-stream"); |
|
2752 |
}
|
|
2753 |
||
2754 |
/*
|
|
2755 |
* Apply maximal encoding regardless of previous
|
|
2756 |
* setting. This segment's either not text, or is
|
|
2757 |
* unlikely to be readable with > 30% of the
|
|
2758 |
* text encoded anyway, so we might as well save space...
|
|
2759 |
*/
|
|
2760 |
new_encoding = ENCBINARY; /* > 30% 8 bit chars */ |
|
2761 |
}
|
|
2762 |
}
|
|
2763 |
||
2764 |
#ifdef ENCODE_FROMS
|
|
2765 |
/* If there were From_'s at the beginning of a line or standalone dots */
|
|
2766 |
if((froms || dots) && new_encoding != ENCBINARY) |
|
2767 |
new_encoding = ENC8BIT; |
|
2768 |
#endif
|
|
2769 |
||
2770 |
/* Set the subtype */
|
|
2771 |
if(body->subtype == NULL) |
|
2772 |
body->subtype = cpystr(rfc822_default_subtype(body->type)); |
|
2773 |
||
2774 |
if(body->encoding == ENCOTHER) |
|
2775 |
body->encoding = new_encoding; |
|
2776 |
||
2777 |
fs_give((void **)&buf); |
|
2778 |
||
2779 |
if(we_cancel) |
|
2780 |
cancel_busy_cue(-1); |
|
2781 |
}
|
|
2782 |
||
2783 |
||
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2784 |
/*
|
2785 |
* Call this to set the charset of an attachment we have
|
|
2786 |
* created. If the attachment contains any non-ascii characters
|
|
2787 |
* then we'll set the charset to the passed in charset, otherwise
|
|
2788 |
* we'll make it us-ascii.
|
|
2789 |
*/
|
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2790 |
void
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2791 |
set_charset_possibly_to_ascii(struct mail_bodystruct *body, char *charset) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2792 |
{
|
2793 |
unsigned char c; |
|
2794 |
int can_be_ascii = 1; |
|
2795 |
STORE_S *so = (STORE_S *)body->contents.text.data; |
|
2796 |
int we_cancel = 0; |
|
2797 |
||
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2798 |
if(!body || body->type != TYPETEXT) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2799 |
return; |
2800 |
||
2801 |
we_cancel = busy_cue(NULL, NULL, 1); |
|
2802 |
||
2803 |
so_seek(so, 0L, 0); |
|
2804 |
||
2805 |
while(can_be_ascii && so_readc(&c, so)) |
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2806 |
if(!c || c & 0x80) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2807 |
can_be_ascii--; |
2808 |
||
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2809 |
if(can_be_ascii) |
2810 |
set_parameter(&body->parameter, "charset", "US-ASCII"); |
|
2811 |
else if(charset && *charset && strucmp(charset, "US-ASCII")) |
|
2812 |
set_parameter(&body->parameter, "charset", charset); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2813 |
else{ |
2814 |
/*
|
|
2815 |
* Else we don't know. There are non ascii characters but we either
|
|
2816 |
* don't have a charset to set it to or that charset is just us_ascii,
|
|
2817 |
* which is impossible. So we label it unknown. An alternative would
|
|
2818 |
* have been to strip the high bits instead and label it ascii.
|
|
2819 |
*/
|
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2820 |
set_parameter(&body->parameter, "charset", UNKNOWN_CHARSET); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2821 |
}
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2822 |
|
2823 |
if(we_cancel) |
|
2824 |
cancel_busy_cue(-1); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2825 |
}
|
2826 |
||
2827 |
||
2828 |
/*
|
|
2829 |
* since encoding happens on the way out the door, this is basically
|
|
2830 |
* just needed to handle TYPEMULTIPART
|
|
2831 |
*/
|
|
2832 |
void
|
|
2833 |
pine_encode_body (struct mail_bodystruct *body) |
|
2834 |
{
|
|
2835 |
PART *part; |
|
2836 |
||
2837 |
dprint((4, "-- pine_encode_body: %d\n", body ? body->type : 0)); |
|
2838 |
if (body) switch (body->type) { |
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
2839 |
char *freethis; |
2840 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2841 |
case TYPEMULTIPART: /* multi-part */ |
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
2842 |
if(!(freethis=parameter_val(body->parameter, "BOUNDARY"))){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2843 |
char tmp[MAILTMPLEN]; /* make cookie not in BASE64 or QUOTEPRINT*/ |
2844 |
||
2845 |
snprintf (tmp,sizeof(tmp),"%ld-%ld-%ld=:%ld",gethostid (),random (),(long) time (0), |
|
2846 |
(long) getpid ()); |
|
2847 |
tmp[sizeof(tmp)-1] = '\0'; |
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2848 |
set_parameter(&body->parameter, "BOUNDARY", tmp); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2849 |
}
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
2850 |
|
2851 |
if(freethis) |
|
2852 |
fs_give((void **) &freethis); |
|
2853 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2854 |
part = body->nested.part; /* encode body parts */ |
2855 |
do pine_encode_body (&part->body); |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
2856 |
while ((part = part->next) != NULL); /* until done */ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2857 |
break; |
2858 |
||
2859 |
case TYPETEXT : |
|
2860 |
/*
|
|
2861 |
* If the part is text we edited, then it is UTF-8.
|
|
2862 |
* The user may be asking us to send it as something else
|
|
2863 |
* or we may want to downconvert to a more-specific characterset.
|
|
2864 |
* Mark it for conversion here so the right MIME header's written.
|
|
2865 |
* Do conversion pine_rfc822_output_body.
|
|
2866 |
* Attachments are left as is.
|
|
2867 |
*/
|
|
2868 |
if(body->contents.text.data |
|
2869 |
&& so_attr((STORE_S *) body->contents.text.data, "edited", NULL)){ |
|
2870 |
char *charset, *posting_charset, *lp; |
|
2871 |
||
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
2872 |
if(!((charset = parameter_val(body->parameter, "charset")) |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
2873 |
&& !strucmp(charset, UNKNOWN_CHARSET)) |
2874 |
&& (posting_charset = posting_characterset(body, charset, MsgBody))){ |
|
2875 |
||
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2876 |
set_parameter(&body->parameter, "charset", posting_charset); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2877 |
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
2878 |
/*
|
2879 |
* Fix iso-2022-jp encoding to ENC7BIT since it's escape based
|
|
2880 |
* and doesn't use anything but ASCII characters.
|
|
2881 |
* Why is it not ENC7BIT already? Because when we set the encoding
|
|
2882 |
* in set_mime_type_by_grope we were groping through UTF-8 text
|
|
2883 |
* not 2022 text. Not only that, but we didn't know at that point
|
|
2884 |
* that it wouldn't stay UTF-8 when we sent it, which would require
|
|
2885 |
* encoding.
|
|
2886 |
*/
|
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2887 |
if(!strucmp(posting_charset, "iso-2022-jp") |
2888 |
&& (lp = so_attr((STORE_S *) body->contents.text.data, "maxline", NULL)) |
|
2889 |
&& strlen(lp) < 4) |
|
2890 |
body->encoding = ENC7BIT; |
|
2891 |
}
|
|
2892 |
||
2893 |
if(charset) |
|
2894 |
fs_give((void **)&charset); |
|
2895 |
}
|
|
2896 |
||
2897 |
break; |
|
2898 |
||
2899 |
/* case MESSAGE: */ /* here for documentation */ |
|
2900 |
/* Encapsulated messages are always treated as text objects at this point.
|
|
2901 |
This means that you must replace body->contents.msg with
|
|
2902 |
body->contents.text, which probably involves copying
|
|
2903 |
body->contents.msg.text to body->contents.text */
|
|
2904 |
default: /* all else has some encoding */ |
|
2905 |
/*
|
|
2906 |
* but we'll delay encoding it until the message is on the way
|
|
2907 |
* into the mail slot...
|
|
2908 |
*/
|
|
2909 |
break; |
|
2910 |
}
|
|
2911 |
}
|
|
2912 |
||
2913 |
||
2914 |
/*
|
|
2915 |
* pine_header_line - simple wrapper around c-client call to contain
|
|
2916 |
* repeated code, and to write fcc if required.
|
|
2917 |
*/
|
|
2918 |
int
|
|
2919 |
pine_header_line(char *field, METAENV *header, char *text, soutr_t f, void *s, |
|
2920 |
int writehdr, int localcopy) |
|
2921 |
{
|
|
2922 |
int ret = 1; |
|
2923 |
int big = 10000; |
|
2924 |
char *value, *folded = NULL, *cs; |
|
2925 |
char *converted; |
|
2926 |
||
2927 |
if(!text) |
|
2928 |
return 1; |
|
2929 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
2930 |
converted = utf8_to_charset(text, cs = posting_characterset(text, NULL, HdrText), 0); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2931 |
|
2932 |
if(converted){ |
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
2933 |
if(cs && !strucmp(cs, "us-ascii")) |
2934 |
value = converted; |
|
2935 |
else
|
|
2936 |
value = encode_header_value(tmp_20k_buf, SIZEOF_20KBUF, |
|
2937 |
(unsigned char *) converted, cs, |
|
2938 |
encode_whole_header(field, header)); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2939 |
|
2940 |
if(value && value == converted){ /* no encoding was done, have to fold */ |
|
2941 |
int fold_by, len; |
|
2942 |
char *actual_field; |
|
2943 |
||
2944 |
len = ((header && header->env && header->env->remail) |
|
2945 |
? strlen("ReSent-") : 0) + |
|
2946 |
(field ? strlen(field) : 0) + 2; |
|
2947 |
||
2948 |
actual_field = (char *)fs_get((len+1) * sizeof(char)); |
|
2949 |
snprintf(actual_field, len+1, "%s%s: ", |
|
2950 |
(header && header->env && header->env->remail) ? "ReSent-" : "", |
|
2951 |
field ? field : ""); |
|
2952 |
actual_field[len] = '\0'; |
|
2953 |
||
2954 |
/*
|
|
2955 |
* We were folding everything except message-id, but that wasn't
|
|
2956 |
* sufficient. Since 822 only allows folding where linear-white-space
|
|
2957 |
* is allowed we'd need a smarter folder than "fold" to do it. So,
|
|
2958 |
* instead of inventing that smarter folder (which would have to
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
2959 |
* know 822 syntax)
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2960 |
*
|
2961 |
* We could just alloc space and copy the actual_field followed by
|
|
2962 |
* the value into it, but since that's what fold does anyway we'll
|
|
2963 |
* waste some cpu time and use fold with a big fold parameter.
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
2964 |
*
|
2965 |
* We upped the references folding from 75 to 256 because we were
|
|
2966 |
* encountering longer-than-75 message ids, and to break one line
|
|
2967 |
* in references is to break them all.
|
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2968 |
*/
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
2969 |
if(field && !strucmp("Subject", field)) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2970 |
fold_by = 75; |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
2971 |
else if(field && !strucmp("References", field)) |
2972 |
fold_by = 256; |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
2973 |
else
|
2974 |
fold_by = big; |
|
2975 |
||
2976 |
folded = fold(value, fold_by, big, actual_field, " ", FLD_CRLF); |
|
2977 |
||
2978 |
if(actual_field) |
|
2979 |
fs_give((void **)&actual_field); |
|
2980 |
}
|
|
2981 |
else if(value){ /* encoding was done */ |
|
2982 |
RFC822BUFFER rbuf; |
|
2983 |
size_t ll; |
|
2984 |
||
2985 |
/*
|
|
2986 |
* rfc1522_encode already inserted continuation lines and did
|
|
2987 |
* the necessary folding so we don't have to do it. Let
|
|
2988 |
* rfc822_header_line add the trailing crlf and the resent- if
|
|
2989 |
* necessary. The 20 could actually be a 12.
|
|
2990 |
*/
|
|
2991 |
ll = strlen(field) + strlen(value) + 20; |
|
2992 |
folded = (char *) fs_get(ll * sizeof(char)); |
|
2993 |
*folded = '\0'; |
|
2994 |
rbuf.f = dummy_soutr; |
|
2995 |
rbuf.s = NULL; |
|
2996 |
rbuf.beg = folded; |
|
2997 |
rbuf.cur = folded; |
|
2998 |
rbuf.end = folded+ll-1; |
|
2999 |
rfc822_output_header_line(&rbuf, field, |
|
3000 |
(header && header->env && header->env->remail) ? LONGT : 0L, value); |
|
3001 |
*rbuf.cur = '\0'; |
|
3002 |
}
|
|
3003 |
||
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
3004 |
if(value && folded){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3005 |
if(writehdr && f) |
3006 |
ret = (*f)(s, folded); |
|
3007 |
||
3008 |
if(ret && localcopy && lmc.so && !lmc.all_written) |
|
3009 |
ret = so_puts(lmc.so, folded); |
|
3010 |
}
|
|
3011 |
||
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
3012 |
if(folded) |
3013 |
fs_give((void **)&folded); |
|
3014 |
||
3015 |
if(converted && converted != text) |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3016 |
fs_give((void **) &converted); |
3017 |
}
|
|
3018 |
else
|
|
3019 |
ret = 0; |
|
3020 |
||
3021 |
return(ret); |
|
3022 |
}
|
|
3023 |
||
3024 |
||
3025 |
/*
|
|
3026 |
* Do appropriate encoding of text header lines.
|
|
3027 |
* For some field types (those that consist of 822 *text) we just encode
|
|
3028 |
* the whole thing. For structured fields we encode only within comments
|
|
3029 |
* if possible.
|
|
3030 |
*
|
|
3031 |
* Args d -- Destination buffer if needed. (tmp_20k_buf)
|
|
3032 |
* s -- Source string.
|
|
3033 |
* charset -- Charset to encode with.
|
|
3034 |
* encode_all -- If set, encode the whole string. If not, try to encode
|
|
3035 |
* only within comments if possible.
|
|
3036 |
*
|
|
3037 |
* Returns S is returned if no encoding is done. D is returned if encoding
|
|
3038 |
* was needed.
|
|
3039 |
*/
|
|
3040 |
char * |
|
3041 |
encode_header_value(char *d, size_t dlen, unsigned char *s, char *charset, int encode_all) |
|
3042 |
{
|
|
3043 |
char *p, *q, *r, *start_of_comment = NULL, *value = NULL; |
|
3044 |
int in_comment = 0; |
|
3045 |
||
3046 |
if(!s) |
|
3047 |
return((char *)s); |
|
3048 |
||
3049 |
if(dlen < SIZEOF_20KBUF) |
|
3050 |
panic("bad call to encode_header_value"); |
|
3051 |
||
3052 |
if(!encode_all){ |
|
3053 |
/*
|
|
3054 |
* We don't have to worry about keeping track of quoted-strings because
|
|
3055 |
* none of these fields which aren't addresses contain quoted-strings.
|
|
3056 |
* We do keep track of escaped parens inside of comments and comment
|
|
3057 |
* nesting.
|
|
3058 |
*/
|
|
3059 |
p = d+7000; |
|
3060 |
for(q = (char *)s; *q; q++){ |
|
3061 |
switch(*q){ |
|
3062 |
case LPAREN: |
|
3063 |
if(in_comment++ == 0) |
|
3064 |
start_of_comment = q; |
|
3065 |
||
3066 |
break; |
|
3067 |
||
3068 |
case RPAREN: |
|
3069 |
if(--in_comment == 0){ |
|
3070 |
/* encode the comment, excluding the outer parens */
|
|
3071 |
if(p-d < dlen-1) |
|
3072 |
*p++ = LPAREN; |
|
3073 |
||
3074 |
*q = '\0'; |
|
3075 |
r = rfc1522_encode(d+14000, dlen-14000, |
|
3076 |
(unsigned char *)start_of_comment+1, |
|
3077 |
charset); |
|
3078 |
if(r != start_of_comment+1) |
|
3079 |
value = d+7000; /* some encoding was done */ |
|
3080 |
||
3081 |
start_of_comment = NULL; |
|
3082 |
if(r) |
|
3083 |
sstrncpy(&p, r, dlen-1-(p-d)); |
|
3084 |
||
3085 |
*q = RPAREN; |
|
3086 |
if(p-d < dlen-1) |
|
3087 |
*p++ = *q; |
|
3088 |
}
|
|
3089 |
else if(in_comment < 0){ |
|
3090 |
in_comment = 0; |
|
3091 |
if(p-d < dlen-1) |
|
3092 |
*p++ = *q; |
|
3093 |
}
|
|
3094 |
||
3095 |
break; |
|
3096 |
||
3097 |
case BSLASH: |
|
3098 |
if(!in_comment && *(q+1)){ |
|
3099 |
if(p-d < dlen-2){ |
|
3100 |
*p++ = *q++; |
|
3101 |
*p++ = *q; |
|
3102 |
}
|
|
3103 |
}
|
|
3104 |
||
3105 |
break; |
|
3106 |
||
3107 |
default: |
|
3108 |
if(!in_comment && p-d < dlen-1) |
|
3109 |
*p++ = *q; |
|
3110 |
||
3111 |
break; |
|
3112 |
}
|
|
3113 |
}
|
|
3114 |
||
3115 |
if(value){ |
|
3116 |
/* Unterminated comment (wasn't really a comment) */
|
|
3117 |
if(start_of_comment) |
|
3118 |
sstrncpy(&p, start_of_comment, dlen-1-(p-d)); |
|
3119 |
||
3120 |
*p = '\0'; |
|
3121 |
}
|
|
3122 |
}
|
|
3123 |
||
3124 |
/*
|
|
3125 |
* We have to check if there is anything that needs to be encoded that
|
|
3126 |
* wasn't in a comment. If there is, we'd better just start over and
|
|
3127 |
* encode the whole thing. So, if no encoding has been done within
|
|
3128 |
* comments, or if encoding is needed both within and outside of
|
|
3129 |
* comments, then we encode the whole thing. Otherwise, go with
|
|
3130 |
* the version that has only comments encoded.
|
|
3131 |
*/
|
|
3132 |
if(!value || rfc1522_encode(d, dlen, |
|
3133 |
(unsigned char *)value, charset) != value) |
|
3134 |
return(rfc1522_encode(d, dlen, s, charset)); |
|
3135 |
else{ |
|
3136 |
strncpy(d, value, dlen-1); |
|
3137 |
d[dlen-1] = '\0'; |
|
3138 |
return(d); |
|
3139 |
}
|
|
3140 |
}
|
|
3141 |
||
3142 |
||
3143 |
/*
|
|
3144 |
* pine_address_line - write a header field containing addresses,
|
|
3145 |
* one by one (so there's no buffer limit), and
|
|
3146 |
* wrapping where necessary.
|
|
3147 |
* Note: we use c-client functions to properly build the text string,
|
|
3148 |
* but have to screw around with pointers to fool c-client functions
|
|
3149 |
* into not blatting all the text into a single buffer. Yeah, I know.
|
|
3150 |
*/
|
|
3151 |
int
|
|
3152 |
pine_address_line(char *field, METAENV *header, struct mail_address *alist, |
|
3153 |
soutr_t f, void *s, int writehdr, int localcopy) |
|
3154 |
{
|
|
3155 |
char tmp[MAX_SINGLE_ADDR], *tmpptr = NULL; |
|
3156 |
size_t alloced = 0, sz; |
|
3157 |
char *delim, *ptmp, *mtmp, buftmp[MAILTMPLEN]; |
|
3158 |
char *converted, *cs; |
|
3159 |
ADDRESS *atmp; |
|
3160 |
int i, count; |
|
3161 |
int in_group = 0, was_start_of_group = 0, fix_lcc = 0, failed = 0; |
|
3162 |
RFC822BUFFER rbuf; |
|
3163 |
static char comma[] = ", "; |
|
3164 |
static char end_group[] = ";"; |
|
3165 |
#define no_comma (&comma[1])
|
|
3166 |
||
3167 |
if(!alist) /* nothing in field! */ |
|
3168 |
return(1); |
|
3169 |
||
3170 |
if(!alist->host && alist->mailbox){ /* c-client group convention */ |
|
3171 |
in_group++; |
|
3172 |
was_start_of_group++; |
|
3173 |
/* encode mailbox of group */
|
|
3174 |
mtmp = alist->mailbox; |
|
3175 |
if(mtmp){ |
|
3176 |
snprintf(buftmp, sizeof(buftmp), "%s", mtmp); |
|
3177 |
buftmp[sizeof(buftmp)-1] = '\0'; |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3178 |
converted = utf8_to_charset(buftmp, cs = posting_characterset(buftmp, NULL, HdrText), 0); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3179 |
if(converted){ |
3180 |
alist->mailbox = cpystr(rfc1522_encode(tmp_20k_buf, SIZEOF_20KBUF, |
|
3181 |
(unsigned char *) converted, cs)); |
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
3182 |
if(converted && converted != buftmp) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3183 |
fs_give((void **) &converted); |
3184 |
}
|
|
3185 |
else{ |
|
3186 |
failed++; |
|
3187 |
goto bail_out; |
|
3188 |
}
|
|
3189 |
}
|
|
3190 |
}
|
|
3191 |
else
|
|
3192 |
mtmp = NULL; |
|
3193 |
||
3194 |
ptmp = alist->personal; /* remember personal name */ |
|
3195 |
/* make sure personal name is encoded */
|
|
3196 |
if(ptmp){ |
|
3197 |
snprintf(buftmp, sizeof(buftmp), "%s", ptmp); |
|
3198 |
buftmp[sizeof(buftmp)-1] = '\0'; |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3199 |
converted = utf8_to_charset(buftmp, cs = posting_characterset(buftmp, NULL, HdrText), 0); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3200 |
if(converted){ |
3201 |
alist->personal = cpystr(rfc1522_encode(tmp_20k_buf, SIZEOF_20KBUF, |
|
3202 |
(unsigned char *) converted, cs)); |
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
3203 |
if(converted && converted != buftmp) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3204 |
fs_give((void **) &converted); |
3205 |
}
|
|
3206 |
else{ |
|
3207 |
failed++; |
|
3208 |
goto bail_out; |
|
3209 |
}
|
|
3210 |
}
|
|
3211 |
||
3212 |
atmp = alist->next; |
|
3213 |
alist->next = NULL; /* digest only first address! */ |
|
3214 |
||
3215 |
/* use automatic buffer unless it isn't big enough */
|
|
3216 |
if((alloced = est_size(alist)) > sizeof(tmp)){ |
|
3217 |
tmpptr = (char *)fs_get(alloced); |
|
3218 |
sz = alloced; |
|
3219 |
}
|
|
3220 |
else{ |
|
3221 |
tmpptr = tmp; |
|
3222 |
sz = sizeof(tmp); |
|
3223 |
}
|
|
3224 |
||
3225 |
rbuf.f = dummy_soutr; |
|
3226 |
rbuf.s = NULL; |
|
3227 |
rbuf.beg = tmpptr; |
|
3228 |
rbuf.cur = tmpptr; |
|
3229 |
rbuf.end = tmpptr+sz-1; |
|
3230 |
rfc822_output_address_line(&rbuf, field, |
|
3231 |
(header && header->env && header->env->remail) ? LONGT : 0L, alist, NULL); |
|
3232 |
*rbuf.cur = '\0'; |
|
3233 |
||
3234 |
alist->next = atmp; /* restore pointer to next addr */ |
|
3235 |
||
3236 |
if(alist->personal && alist->personal != ptmp) |
|
3237 |
fs_give((void **) &alist->personal); |
|
3238 |
||
3239 |
alist->personal = ptmp; /* in case it changed, restore name */ |
|
3240 |
||
3241 |
if(mtmp){ |
|
3242 |
if(alist->mailbox && alist->mailbox != mtmp) |
|
3243 |
fs_give((void **) &alist->mailbox); |
|
3244 |
||
3245 |
alist->mailbox = mtmp; |
|
3246 |
}
|
|
3247 |
||
3248 |
if((count = strlen(tmpptr)) > 2){ /* back over CRLF */ |
|
3249 |
count -= 2; |
|
3250 |
tmpptr[count] = '\0'; |
|
3251 |
}
|
|
3252 |
||
3253 |
/*
|
|
3254 |
* If there is no sending_stream and we are writing the Lcc header,
|
|
3255 |
* then we are piping it to sendmail -t which expects it to be a bcc,
|
|
3256 |
* not lcc.
|
|
3257 |
*
|
|
3258 |
* When we write it to the fcc or postponed (the lmc.so),
|
|
3259 |
* we want it to be lcc, not bcc, so we put it back.
|
|
3260 |
*/
|
|
3261 |
if(!sending_stream && writehdr && struncmp("lcc:", tmpptr, 4) == 0) |
|
3262 |
fix_lcc = 1; |
|
3263 |
||
3264 |
if(writehdr && f && *tmpptr){ |
|
3265 |
if(fix_lcc) |
|
3266 |
tmpptr[0] = 'b'; |
|
3267 |
||
3268 |
failed = !(*f)(s, tmpptr); |
|
3269 |
if(fix_lcc) |
|
3270 |
tmpptr[0] = 'L'; |
|
3271 |
||
3272 |
if(failed) |
|
3273 |
goto bail_out; |
|
3274 |
}
|
|
3275 |
||
3276 |
if(localcopy && lmc.so && |
|
3277 |
!lmc.all_written && *tmpptr && !so_puts(lmc.so, tmpptr)) |
|
3278 |
goto bail_out; |
|
3279 |
||
3280 |
for(alist = atmp; alist; alist = alist->next){ |
|
3281 |
delim = comma; |
|
3282 |
/* account for c-client's representation of group names */
|
|
3283 |
if(in_group){ |
|
3284 |
if(!alist->host){ /* end of group */ |
|
3285 |
in_group = 0; |
|
3286 |
was_start_of_group = 0; |
|
3287 |
/*
|
|
3288 |
* Rfc822_write_address no longer writes out the end of group
|
|
3289 |
* unless the whole group address is passed to it, so we do
|
|
3290 |
* it ourselves.
|
|
3291 |
*/
|
|
3292 |
delim = end_group; |
|
3293 |
}
|
|
3294 |
else if(!localcopy || !lmc.so || lmc.all_written) |
|
3295 |
continue; |
|
3296 |
}
|
|
3297 |
/* start of new group, print phrase below */
|
|
3298 |
else if(!alist->host && alist->mailbox){ |
|
3299 |
in_group++; |
|
3300 |
was_start_of_group++; |
|
3301 |
}
|
|
3302 |
||
3303 |
/* no comma before first address in group syntax */
|
|
3304 |
if(was_start_of_group && alist->host){ |
|
3305 |
delim = no_comma; |
|
3306 |
was_start_of_group = 0; |
|
3307 |
}
|
|
3308 |
||
3309 |
/* write delimiter */
|
|
3310 |
if(((!in_group||was_start_of_group) && writehdr && f && !(*f)(s, delim)) |
|
3311 |
|| (localcopy && lmc.so && !lmc.all_written |
|
3312 |
&& !so_puts(lmc.so, delim))) |
|
3313 |
goto bail_out; |
|
3314 |
||
3315 |
ptmp = alist->personal; /* remember personal name */ |
|
3316 |
snprintf(buftmp, sizeof(buftmp), "%.200s", ptmp ? ptmp : ""); |
|
3317 |
buftmp[sizeof(buftmp)-1] = '\0'; |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3318 |
converted = utf8_to_charset(buftmp, cs = posting_characterset(buftmp, NULL, HdrText), 0); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3319 |
if(converted){ |
3320 |
alist->personal = cpystr(rfc1522_encode(tmp_20k_buf, SIZEOF_20KBUF, |
|
3321 |
(unsigned char *) converted, cs)); |
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
3322 |
if(converted && converted != buftmp) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3323 |
fs_give((void **) &converted); |
3324 |
}
|
|
3325 |
else{ |
|
3326 |
failed++; |
|
3327 |
goto bail_out; |
|
3328 |
}
|
|
3329 |
||
3330 |
atmp = alist->next; |
|
3331 |
alist->next = NULL; /* tie off linked list */ |
|
3332 |
if((i = est_size(alist)) > MAX(sizeof(tmp), alloced)){ |
|
3333 |
alloced = i; |
|
3334 |
sz = alloced; |
|
3335 |
fs_resize((void **)&tmpptr, alloced); |
|
3336 |
}
|
|
3337 |
||
3338 |
*tmpptr = '\0'; |
|
3339 |
/* make sure we don't write out group end with rfc822_write_address */
|
|
3340 |
if(alist->host || alist->mailbox){ |
|
3341 |
rbuf.f = dummy_soutr; |
|
3342 |
rbuf.s = NULL; |
|
3343 |
rbuf.beg = tmpptr; |
|
3344 |
rbuf.cur = tmpptr; |
|
3345 |
rbuf.end = tmpptr+sz-1; |
|
3346 |
rfc822_output_address_list(&rbuf, alist, 0L, NULL); |
|
3347 |
*rbuf.cur = '\0'; |
|
3348 |
}
|
|
3349 |
||
3350 |
alist->next = atmp; /* restore next pointer */ |
|
3351 |
||
3352 |
if(alist->personal && alist->personal != ptmp) |
|
3353 |
fs_give((void **) &alist->personal); |
|
3354 |
||
3355 |
alist->personal = ptmp; /* in case it changed, restore name */ |
|
3356 |
||
3357 |
/*
|
|
3358 |
* BUG
|
|
3359 |
* With group syntax addresses we no longer have two identical
|
|
3360 |
* streams of output. Instead, for the fcc/postpone copy we include
|
|
3361 |
* all of the addresses inside the :; of the group, and for the
|
|
3362 |
* mail we're sending we don't include them. That means we aren't
|
|
3363 |
* correctly keeping track of the column to wrap in, below. That is,
|
|
3364 |
* we are keeping track of the fcc copy but we aren't keeping track
|
|
3365 |
* of the regular copy. It could result in too long or too short
|
|
3366 |
* lines. Should almost never come up since group addresses are almost
|
|
3367 |
* never followed by other addresses in the same header, and even
|
|
3368 |
* when they are, you have to go out of your way to get the headers
|
|
3369 |
* messed up.
|
|
3370 |
*/
|
|
3371 |
if(count + 2 + (i = strlen(tmpptr)) > 78){ /* wrap long lines... */ |
|
3372 |
count = i + 4; |
|
3373 |
if((!in_group && writehdr && f && !(*f)(s, "\015\012 ")) |
|
3374 |
|| (localcopy && lmc.so && !lmc.all_written && |
|
3375 |
!so_puts(lmc.so, "\015\012 "))) |
|
3376 |
goto bail_out; |
|
3377 |
}
|
|
3378 |
else
|
|
3379 |
count += i + 2; |
|
3380 |
||
3381 |
if(((!in_group || was_start_of_group) |
|
3382 |
&& writehdr && *tmpptr && f && !(*f)(s, tmpptr)) |
|
3383 |
|| (localcopy && lmc.so && !lmc.all_written |
|
3384 |
&& *tmpptr && !so_puts(lmc.so, tmpptr))) |
|
3385 |
goto bail_out; |
|
3386 |
}
|
|
3387 |
||
3388 |
bail_out: |
|
3389 |
if(tmpptr && tmpptr != tmp) |
|
3390 |
fs_give((void **)&tmpptr); |
|
3391 |
||
3392 |
if(failed) |
|
3393 |
return(0); |
|
3394 |
||
3395 |
return((writehdr && f ? (*f)(s, "\015\012") : 1) |
|
3396 |
&& ((localcopy && lmc.so |
|
3397 |
&& !lmc.all_written) ? so_puts(lmc.so, "\015\012") : 1)); |
|
3398 |
}
|
|
3399 |
||
3400 |
||
3401 |
/*
|
|
3402 |
* mutated pine version of c-client's rfc822_header() function.
|
|
3403 |
* changed to call pine-wrapped header and address functions
|
|
3404 |
* so we don't have to limit the header size to a fixed buffer.
|
|
3405 |
* This function also calls pine's body_header write function
|
|
3406 |
* because encoding is delayed until output_body() is called.
|
|
3407 |
*/
|
|
3408 |
long
|
|
3409 |
pine_rfc822_header(METAENV *header, struct mail_bodystruct *body, soutr_t f, void *s) |
|
3410 |
{
|
|
3411 |
PINEFIELD *pf; |
|
3412 |
int j; |
|
3413 |
||
3414 |
if(header->env->remail){ /* if remailing */ |
|
3415 |
long i = strlen (header->env->remail); |
|
3416 |
if(i > 4 && header->env->remail[i-4] == '\015') |
|
3417 |
header->env->remail[i-2] = '\0'; /* flush extra blank line */ |
|
3418 |
||
3419 |
if((f && !(*f)(s, header->env->remail)) |
|
3420 |
|| (lmc.so && !lmc.all_written |
|
3421 |
&& !so_puts(lmc.so, header->env->remail))) |
|
3422 |
return(0L); /* start with remail header */ |
|
3423 |
}
|
|
3424 |
||
3425 |
j = 0; |
|
3426 |
for(pf = header->sending_order[j]; pf; pf = header->sending_order[++j]){ |
|
3427 |
switch(pf->type){ |
|
3428 |
/*
|
|
3429 |
* Warning: This is confusing. The 2nd to last argument used to
|
|
3430 |
* be just pf->writehdr. We want Bcc lines to be written out
|
|
3431 |
* if we are handing off to a sendmail temp file but not if we
|
|
3432 |
* are talking smtp, so bcc's writehdr is set to 0 and
|
|
3433 |
* pine_address_line was sending if writehdr OR !sending_stream.
|
|
3434 |
* That works as long as we want to write everything when
|
|
3435 |
* !sending_stream (an mta handoff to sendmail). But then we
|
|
3436 |
* added the undisclosed recipients line which should only get
|
|
3437 |
* written if writehdr is set, and not when we pass to a
|
|
3438 |
* sendmail temp file. So pine_address_line has been changed
|
|
3439 |
* so it bases its decision solely on the writehdr passed to it,
|
|
3440 |
* and the logic that worries about Bcc and sending_stream
|
|
3441 |
* was moved up to the caller (here) to decide when to set it.
|
|
3442 |
*
|
|
3443 |
* So we have:
|
|
3444 |
* undisclosed recipients:; This will just be written
|
|
3445 |
* if writehdr was set and not
|
|
3446 |
* otherwise, nothing magical.
|
|
3447 |
*** We may want to change this, because sendmail -t doesn't handle
|
|
3448 |
*** the empty group syntax well unless it has been configured to
|
|
3449 |
*** do so. It isn't configured by default, or in any of the
|
|
3450 |
*** sendmail v8 configs. So we may want to not write this line
|
|
3451 |
*** if we're doing an mta_handoff (!sending_stream).
|
|
3452 |
*
|
|
3453 |
* !sending_stream (which means a handoff to a sendmail -t)
|
|
3454 |
* bcc or lcc both set the arg so they'll get written
|
|
3455 |
* (There is also Lcc hocus pocus in pine_address_line
|
|
3456 |
* which converts the Lcc: to Bcc: for sendmail
|
|
3457 |
* processing.)
|
|
3458 |
* sending_stream (which means an smtp handoff)
|
|
3459 |
* bcc and lcc will never have writehdr set, so
|
|
3460 |
* will never be written (They both do have rcptto set,
|
|
3461 |
* so they both do cause RCPT TO commands.)
|
|
3462 |
*
|
|
3463 |
* The localcopy is independent of sending_stream and is just
|
|
3464 |
* written if it is set for all of these.
|
|
3465 |
*/
|
|
3466 |
case Address: |
|
3467 |
if(!pine_address_line(pf->name, |
|
3468 |
header, |
|
3469 |
pf->addr ? *pf->addr : NULL, |
|
3470 |
f, |
|
3471 |
s, |
|
3472 |
(!strucmp("bcc",pf->name ? pf->name : "") |
|
3473 |
|| !strucmp("Lcc",pf->name ? pf->name : "")) |
|
3474 |
? !sending_stream |
|
3475 |
: pf->writehdr, |
|
3476 |
pf->localcopy)) |
|
3477 |
return(0L); |
|
3478 |
||
3479 |
break; |
|
3480 |
||
3481 |
case Fcc: |
|
3482 |
case FreeText: |
|
3483 |
case Subject: |
|
3484 |
if(!pine_header_line(pf->name, header, |
|
3485 |
pf->text ? *pf->text : NULL, |
|
3486 |
f, s, pf->writehdr, pf->localcopy)) |
|
3487 |
return(0L); |
|
3488 |
||
3489 |
break; |
|
3490 |
||
3491 |
default: |
|
3492 |
q_status_message1(SM_ORDER,3,7,"Unknown header type: %.200s", |
|
3493 |
pf->name); |
|
3494 |
break; |
|
3495 |
}
|
|
3496 |
}
|
|
3497 |
||
3498 |
||
3499 |
#if (defined(DOS) || defined(OS2)) && !defined(NOAUTH)
|
|
3500 |
/*
|
|
3501 |
* Add comforting "X-" header line indicating what sort of
|
|
3502 |
* authenticity the receiver can expect...
|
|
3503 |
*/
|
|
3504 |
if(F_OFF(F_DISABLE_SENDER, ps_global)){ |
|
3505 |
NETMBX netmbox; |
|
3506 |
char sstring[MAILTMPLEN], *label; /* place to write */ |
|
3507 |
MAILSTREAM *m; |
|
3508 |
int i, anonymous = 1; |
|
3509 |
||
3510 |
for(i = 0; anonymous && i < ps_global->s_pool.nstream; i++){ |
|
3511 |
m = ps_global->s_pool.streams[i]; |
|
3512 |
if(m && sp_flagged(m, SP_LOCKED) |
|
3513 |
&& mail_valid_net_parse(m->mailbox, &netmbox) |
|
3514 |
&& !netmbox.anoflag) |
|
3515 |
anonymous = 0; |
|
3516 |
}
|
|
3517 |
||
3518 |
if(!anonymous){ |
|
3519 |
char last_char = netmbox.host[strlen(netmbox.host) - 1], |
|
3520 |
*user = (*netmbox.user) |
|
3521 |
? netmbox.user |
|
3522 |
: cached_user_name(netmbox.mailbox); |
|
3523 |
snprintf(sstring, sizeof(sstring), "%.300s@%s%.300s%s", user ? user : "NULL", |
|
3524 |
isdigit((unsigned char)last_char) ? "[" : "", |
|
3525 |
netmbox.host, |
|
3526 |
isdigit((unsigned char) last_char) ? "]" : ""); |
|
3527 |
sstring[sizeof(sstring)-1] = '\0'; |
|
3528 |
label = "X-X-Sender"; /* Jeez. */ |
|
3529 |
if(F_ON(F_USE_SENDER_NOT_X,ps_global)) |
|
3530 |
label += 4; |
|
3531 |
}
|
|
3532 |
else{ |
|
3533 |
strncpy(sstring,"UNAuthenticated Sender", sizeof(sstring)); |
|
3534 |
sstring[sizeof(sstring)-1] = '\0'; |
|
3535 |
label = "X-Warning"; |
|
3536 |
}
|
|
3537 |
||
3538 |
if(!pine_header_line(label, header, sstring, f, s, 1, 1)) |
|
3539 |
return(0L); |
|
3540 |
}
|
|
3541 |
#endif
|
|
3542 |
||
3543 |
if(body && !header->env->remail){ /* not if remail or no body */ |
|
3544 |
if((f && !(*f)(s, MIME_VER)) |
|
3545 |
|| (lmc.so && !lmc.all_written && !so_puts(lmc.so, MIME_VER)) |
|
3546 |
|| !pine_write_body_header(body, f, s)) |
|
3547 |
return(0L); |
|
3548 |
}
|
|
3549 |
else{ /* write terminating newline */ |
|
3550 |
if((f && !(*f)(s, "\015\012")) |
|
3551 |
|| (lmc.so && !lmc.all_written && !so_puts(lmc.so, "\015\012"))) |
|
3552 |
return(0L); |
|
3553 |
}
|
|
3554 |
||
3555 |
return(1L); |
|
3556 |
}
|
|
3557 |
||
3558 |
||
3559 |
/*
|
|
3560 |
* pine_rfc822_output - pine's version of c-client call. Necessary here
|
|
3561 |
* since we're not using its structures as intended!
|
|
3562 |
*/
|
|
3563 |
long
|
|
3564 |
pine_rfc822_output(METAENV *header, struct mail_bodystruct *body, soutr_t f, void *s) |
|
3565 |
{
|
|
3566 |
int we_cancel = 0; |
|
3567 |
long retval; |
|
3568 |
||
3569 |
dprint((4, "-- pine_rfc822_output\n")); |
|
3570 |
||
3571 |
we_cancel = busy_cue(NULL, NULL, 1); |
|
3572 |
pine_encode_body(body); /* encode body as necessary */ |
|
3573 |
/* build and output RFC822 header, output body */
|
|
3574 |
retval = pine_rfc822_header(header, body, f, s) |
|
3575 |
&& (body ? pine_rfc822_output_body(body, f, s) : 1L); |
|
3576 |
||
3577 |
if(we_cancel) |
|
3578 |
cancel_busy_cue(-1); |
|
3579 |
||
3580 |
return(retval); |
|
3581 |
}
|
|
3582 |
||
3583 |
||
3584 |
/*
|
|
3585 |
* post_rfc822_output - cloak for pine's 822 output routine. Since
|
|
3586 |
* we can't pass opaque envelope thru c-client posting
|
|
3587 |
* logic, we need to wrap the real output inside
|
|
3588 |
* something that c-client knows how to call.
|
|
3589 |
*/
|
|
3590 |
long
|
|
3591 |
post_rfc822_output(char *tmp, |
|
3592 |
ENVELOPE *env, |
|
3593 |
struct mail_bodystruct *body, |
|
3594 |
soutr_t f, |
|
3595 |
void *s, |
|
3596 |
long int ok8bit) |
|
3597 |
{
|
|
3598 |
return(pine_rfc822_output(send_header, body, f, s)); |
|
3599 |
}
|
|
3600 |
||
3601 |
||
3602 |
/*
|
|
3603 |
* posting_characterset- determine what transliteration is reasonable
|
|
3604 |
* for posting the given non-ascii messsage data.
|
|
3605 |
*
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3606 |
* preferred_charset is the charset the original data was labeled in.
|
3607 |
* If we can keep that we do.
|
|
3608 |
*
|
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3609 |
* Returns: always returns the preferred character set.
|
3610 |
*/
|
|
3611 |
char * |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3612 |
posting_characterset(void *data, char *preferred_charset, MsgPart mp) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3613 |
{
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3614 |
unsigned long *charsetmap = NULL; |
3615 |
unsigned long validbitmap; |
|
3616 |
static char *ascii = "US-ASCII"; |
|
3617 |
static char *utf8 = "UTF-8"; |
|
3618 |
int notcjk = 0; |
|
3619 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3620 |
if(!ps_global->post_utf8){ |
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3621 |
validbitmap = 0; |
3622 |
||
3623 |
if(mp == HdrText){ |
|
3624 |
char *text = NULL; |
|
3625 |
UCS *ucs = NULL, *ucsp; |
|
3626 |
||
3627 |
text = (char *) data; |
|
3628 |
||
3629 |
/* convert text in header to UCS characters */
|
|
3630 |
if(text) |
|
3631 |
ucsp = ucs = utf8_to_ucs4_cpystr(text); |
|
3632 |
||
3633 |
if(!(ucs && *ucs)) |
|
3634 |
return(ascii); |
|
3635 |
||
3636 |
/*
|
|
3637 |
* After the while loop is done the validbitmap has
|
|
3638 |
* a 1 bit for all the character sets that can
|
|
3639 |
* represent all of the characters of this header.
|
|
3640 |
*/
|
|
3641 |
charsetmap = init_charsetchecker(preferred_charset); |
|
3642 |
||
3643 |
if(!charsetmap) |
|
3644 |
return(utf8); |
|
3645 |
||
3646 |
validbitmap = ~0; |
|
3647 |
while((validbitmap & ~0x1) && (*ucsp)){ |
|
3648 |
if(*ucsp > 0xffff){ |
|
3649 |
fs_give((void **) &ucs); |
|
3650 |
return(utf8); |
|
3651 |
}
|
|
3652 |
||
3653 |
validbitmap &= charsetmap[(unsigned long) (*ucsp++)]; |
|
3654 |
}
|
|
3655 |
||
3656 |
fs_give((void **) &ucs); |
|
3657 |
||
3658 |
notcjk = validbitmap & 0x1; |
|
3659 |
validbitmap &= ~0x1; |
|
3660 |
||
3661 |
if(!validbitmap) |
|
3662 |
return(utf8); |
|
3663 |
}
|
|
3664 |
else{ |
|
3665 |
struct mail_bodystruct *body = NULL; |
|
3666 |
STORE_S *the_text = NULL; |
|
3667 |
int outchars; |
|
3668 |
unsigned char c; |
|
3669 |
UCS ucs; |
|
3670 |
CBUF_S cbuf; |
|
3671 |
||
3672 |
cbuf.cbuf[0] = '\0'; |
|
3673 |
cbuf.cbufp = cbuf.cbuf; |
|
3674 |
cbuf.cbufend = cbuf.cbuf; |
|
3675 |
||
3676 |
body = (struct mail_bodystruct *) data; |
|
3677 |
||
3678 |
if(body && body->type == TYPEMULTIPART) |
|
3679 |
body = &body->nested.part->body; |
|
3680 |
||
3681 |
if(body && body->type == TYPETEXT) |
|
3682 |
the_text = (STORE_S *) body->contents.text.data; |
|
3683 |
||
3684 |
if(!the_text) |
|
3685 |
return(ascii); |
|
3686 |
||
3687 |
so_seek(the_text, 0L, 0); /* rewind */ |
|
3688 |
||
3689 |
charsetmap = init_charsetchecker(preferred_charset); |
|
3690 |
||
3691 |
if(!charsetmap) |
|
3692 |
return(utf8); |
|
3693 |
||
3694 |
validbitmap = ~0; |
|
3695 |
||
3696 |
/*
|
|
3697 |
* Read a stream of UTF-8 characters from the_text
|
|
3698 |
* and convert them to UCS-4 characters for the translatable
|
|
3699 |
* test.
|
|
3700 |
*/
|
|
3701 |
while((validbitmap & ~0x1) && so_readc(&c, the_text)){ |
|
3702 |
if((outchars = utf8_to_ucs4_oneatatime(c, &cbuf, &ucs, NULL)) > 0){ |
|
3703 |
/* got a ucs character */
|
|
3704 |
if(ucs > 0xffff) |
|
3705 |
return(utf8); |
|
3706 |
||
3707 |
validbitmap &= charsetmap[(unsigned long) ucs]; |
|
3708 |
}
|
|
3709 |
}
|
|
3710 |
||
3711 |
notcjk = validbitmap & 0x1; |
|
3712 |
validbitmap &= ~0x1; |
|
3713 |
||
3714 |
if(!validbitmap) |
|
3715 |
return(utf8); |
|
3716 |
}
|
|
3717 |
||
3718 |
/* user chooses something other than UTF-8 */
|
|
3719 |
if(strucmp(ps_global->posting_charmap, utf8)){ |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3720 |
/*
|
3721 |
* If we're to post in other than UTF-8, and it can be
|
|
3722 |
* transliterated without losing fidelity, do it.
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3723 |
* Else, use UTF-8.
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3724 |
*/
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3725 |
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3726 |
/* if ascii works, always use that */
|
3727 |
if(representable_in_charset(validbitmap, ascii)) |
|
3728 |
return(ascii); |
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
3729 |
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3730 |
/* does the user's posting character set work? */
|
3731 |
if(representable_in_charset(validbitmap, ps_global->posting_charmap)) |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3732 |
return(ps_global->posting_charmap); |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3733 |
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3734 |
/* this is the charset the message we are replying to was in */
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3735 |
if(preferred_charset |
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3736 |
&& strucmp(preferred_charset, ascii) |
3737 |
&& representable_in_charset(validbitmap, preferred_charset)) |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3738 |
return(preferred_charset); |
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3739 |
|
3740 |
/* else, use UTF-8 */
|
|
3741 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3742 |
}
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3743 |
/* user chooses nothing, going with the default */
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
3744 |
else if(ps_global->vars[V_POST_CHAR_SET].main_user_val.p == NULL |
3745 |
&& ps_global->vars[V_POST_CHAR_SET].post_user_val.p == NULL |
|
3746 |
&& ps_global->vars[V_POST_CHAR_SET].fixed_val.p == NULL){ |
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3747 |
char *most_preferred; |
3748 |
||
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
3749 |
/*
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3750 |
* In this case the user didn't specify a posting character set
|
3751 |
* and we will choose the most-specific one from our list.
|
|
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
3752 |
*/
|
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3753 |
|
3754 |
/* ascii is best */
|
|
3755 |
if(representable_in_charset(validbitmap, ascii)) |
|
3756 |
return(ascii); |
|
3757 |
||
3758 |
/* Can we keep the original from the message we're replying to? */
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3759 |
if(preferred_charset |
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3760 |
&& strucmp(preferred_charset, ascii) |
3761 |
&& representable_in_charset(validbitmap, preferred_charset)) |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
3762 |
return(preferred_charset); |
3763 |
||
1.1.5
by Asheesh Laroia
Import upstream version 1.0+dfsg |
3764 |
/* choose the best of the rest */
|
3765 |
most_preferred = most_preferred_charset(validbitmap); |
|
3766 |
if(!most_preferred) |
|
3767 |
return(utf8); |
|
3768 |
||
3769 |
/*
|
|
3770 |
* If the text we're labeling contains something like
|
|
3771 |
* smart quotes but no CJK characters, then instead of
|
|
3772 |
* labeling it as ISO-2022-JP we want to use UTF-8.
|
|
3773 |
*/
|
|
3774 |
if(notcjk){ |
|
3775 |
const CHARSET *cs; |
|
3776 |
||
3777 |
cs = utf8_charset(most_preferred); |
|
3778 |
if(!cs |
|
3779 |
|| cs->script == SC_CHINESE_SIMPLIFIED |
|
3780 |
|| cs->script == SC_CHINESE_TRADITIONAL |
|
3781 |
|| cs->script == SC_JAPANESE |
|
3782 |
|| cs->script == SC_KOREAN) |
|
3783 |
return(utf8); |
|
3784 |
}
|
|
3785 |
||
3786 |
return(most_preferred); |
|
3787 |
}
|
|
3788 |
/* user explicitly chooses UTF-8 */
|
|
3789 |
else{ |
|
3790 |
/* if ascii works, always use that */
|
|
3791 |
if(representable_in_charset(validbitmap, ascii)) |
|
3792 |
return(ascii); |
|
3793 |
||
3794 |
/* else, use UTF-8 */
|
|
3795 |
||
3796 |
}
|
|
3797 |
}
|
|
3798 |
||
3799 |
return(utf8); |
|
3800 |
}
|
|
3801 |
||
3802 |
||
3803 |
static char **charsetlist = NULL; |
|
3804 |
static int items_in_charsetlist = 0; |
|
3805 |
static unsigned long *charsetmap = NULL; |
|
3806 |
||
3807 |
static char *downgrades[] = { |
|
3808 |
"US-ASCII", |
|
3809 |
"ISO-8859-15", |
|
3810 |
"ISO-8859-1", |
|
3811 |
"ISO-8859-2", |
|
3812 |
"VISCII", |
|
3813 |
"KOI8-R", |
|
3814 |
"KOI8-U", |
|
3815 |
"ISO-8859-7", |
|
3816 |
"ISO-8859-6", |
|
3817 |
"ISO-8859-8", |
|
3818 |
"TIS-620", |
|
3819 |
"ISO-2022-JP", |
|
3820 |
"GB2312", |
|
3821 |
"BIG5", |
|
3822 |
"EUC-KR"
|
|
3823 |
};
|
|
3824 |
||
3825 |
||
3826 |
unsigned long * |
|
3827 |
init_charsetchecker(char *preferred_charset) |
|
3828 |
{
|
|
3829 |
int i, count = 0, reset = 0; |
|
3830 |
char *ascii = "US-ASCII"; |
|
3831 |
char *utf8 = "UTF-8"; |
|
3832 |
||
3833 |
/*
|
|
3834 |
* When user doesn't set a posting character set posting_charmap ends up
|
|
3835 |
* set to UTF-8. That also happens if user sets UTF-8 explicitly.
|
|
3836 |
* That's where the strange set of if-else's come from.
|
|
3837 |
*/
|
|
3838 |
||
3839 |
/* user chooses something other than UTF-8 */
|
|
3840 |
if(strucmp(ps_global->posting_charmap, utf8)){ |
|
3841 |
count++; /* US-ASCII */ |
|
3842 |
if(items_in_charsetlist < 1 || strucmp(charsetlist[0], ascii)) |
|
3843 |
reset++; |
|
3844 |
||
3845 |
/* if posting_charmap is valid, include it in list */
|
|
3846 |
if(ps_global->posting_charmap && ps_global->posting_charmap[0] |
|
3847 |
&& strucmp(ps_global->posting_charmap, ascii) |
|
3848 |
&& strucmp(ps_global->posting_charmap, utf8) |
|
3849 |
&& utf8_charset(ps_global->posting_charmap)){ |
|
3850 |
count++; |
|
3851 |
if(!reset |
|
3852 |
&& (items_in_charsetlist < count |
|
3853 |
|| strucmp(charsetlist[count-1], ps_global->posting_charmap))) |
|
3854 |
reset++; |
|
3855 |
}
|
|
3856 |
||
3857 |
if(preferred_charset && preferred_charset[0] |
|
3858 |
&& strucmp(preferred_charset, ascii) |
|
3859 |
&& strucmp(preferred_charset, utf8) |
|
3860 |
&& (count < 2 || strucmp(preferred_charset, ps_global->posting_charmap))){ |
|
3861 |
count++; |
|
3862 |
if(!reset |
|
3863 |
&& (items_in_charsetlist < count |
|
3864 |
|| strucmp(charsetlist[count-1], preferred_charset))) |
|
3865 |
reset++; |
|
3866 |
}
|
|
3867 |
||
3868 |
if(items_in_charsetlist != count) |
|
3869 |
reset++; |
|
3870 |
||
3871 |
if(reset){ |
|
3872 |
if(charsetlist) |
|
3873 |
free_list_array(&charsetlist); |
|
3874 |
||
3875 |
items_in_charsetlist = count; |
|
3876 |
charsetlist = (char **) fs_get((count + 1) * sizeof(char *)); |
|
3877 |
||
3878 |
i = 0; |
|
3879 |
charsetlist[i++] = cpystr(ascii); |
|
3880 |
||
3881 |
if(ps_global->posting_charmap && ps_global->posting_charmap[0] |
|
3882 |
&& strucmp(ps_global->posting_charmap, ascii) |
|
3883 |
&& strucmp(ps_global->posting_charmap, utf8) |
|
3884 |
&& utf8_charset(ps_global->posting_charmap)) |
|
3885 |
charsetlist[i++] = cpystr(ps_global->posting_charmap); |
|
3886 |
||
3887 |
if(preferred_charset && preferred_charset[0] |
|
3888 |
&& strucmp(preferred_charset, ascii) |
|
3889 |
&& strucmp(preferred_charset, utf8) |
|
3890 |
&& (i < 2 || strucmp(preferred_charset, ps_global->posting_charmap))) |
|
3891 |
charsetlist[i++] = cpystr(preferred_charset); |
|
3892 |
||
3893 |
charsetlist[i] = NULL; |
|
3894 |
}
|
|
3895 |
}
|
|
3896 |
/* user chooses nothing, going with the default */
|
|
3897 |
else if(ps_global->vars[V_POST_CHAR_SET].main_user_val.p == NULL |
|
3898 |
&& ps_global->vars[V_POST_CHAR_SET].post_user_val.p == NULL |
|
3899 |
&& ps_global->vars[V_POST_CHAR_SET].fixed_val.p == NULL){ |
|
3900 |
int add_preferred = 0; |
|
3901 |
||
3902 |
/* does preferred_charset have to be added to the list? */
|
|
3903 |
if(preferred_charset && preferred_charset[0] && strucmp(preferred_charset, utf8)){ |
|
3904 |
add_preferred = 1; |
|
3905 |
for(i = 0; add_preferred && i < sizeof(downgrades)/sizeof(downgrades[0]); i++) |
|
3906 |
if(!strucmp(downgrades[i], preferred_charset)) |
|
3907 |
add_preferred = 0; |
|
3908 |
}
|
|
3909 |
||
3910 |
if(add_preferred){ |
|
3911 |
/* existing list is right size already */
|
|
3912 |
if(items_in_charsetlist == sizeof(downgrades)/sizeof(downgrades[0]) + 1){ |
|
3913 |
/* just check to see if last list item is the preferred_charset */
|
|
3914 |
if(strucmp(preferred_charset, charsetlist[items_in_charsetlist-1])){ |
|
3915 |
/* no, fix it */
|
|
3916 |
reset++; |
|
3917 |
fs_give((void **) &charsetlist[items_in_charsetlist-1]); |
|
3918 |
charsetlist[items_in_charsetlist-1] = cpystr(preferred_charset); |
|
3919 |
}
|
|
3920 |
}
|
|
3921 |
else{ |
|
3922 |
reset++; |
|
3923 |
if(charsetlist) |
|
3924 |
free_list_array(&charsetlist); |
|
3925 |
||
3926 |
count = sizeof(downgrades)/sizeof(downgrades[0]) + 1; |
|
3927 |
items_in_charsetlist = count; |
|
3928 |
charsetlist = (char **) fs_get((count + 1) * sizeof(char *)); |
|
3929 |
for(i = 0; i < sizeof(downgrades)/sizeof(downgrades[0]); i++) |
|
3930 |
charsetlist[i] = cpystr(downgrades[i]); |
|
3931 |
||
3932 |
charsetlist[i++] = cpystr(preferred_charset); |
|
3933 |
charsetlist[i] = NULL; |
|
3934 |
}
|
|
3935 |
}
|
|
3936 |
else{ |
|
3937 |
/* if list is same size as downgrades, consider it good */
|
|
3938 |
if(items_in_charsetlist != sizeof(downgrades)/sizeof(downgrades[0])) |
|
3939 |
reset++; |
|
3940 |
||
3941 |
if(reset){ |
|
3942 |
if(charsetlist) |
|
3943 |
free_list_array(&charsetlist); |
|
3944 |
||
3945 |
count = sizeof(downgrades)/sizeof(downgrades[0]); |
|
3946 |
items_in_charsetlist = count; |
|
3947 |
charsetlist = (char **) fs_get((count + 1) * sizeof(char *)); |
|
3948 |
for(i = 0; i < sizeof(downgrades)/sizeof(downgrades[0]); i++) |
|
3949 |
charsetlist[i] = cpystr(downgrades[i]); |
|
3950 |
||
3951 |
charsetlist[i] = NULL; |
|
3952 |
}
|
|
3953 |
}
|
|
3954 |
}
|
|
3955 |
/* user explicitly chooses UTF-8 */
|
|
3956 |
else{ |
|
3957 |
/* include possibility of ascii even if they explicitly ask for UTF-8 */
|
|
3958 |
count++; /* US-ASCII */ |
|
3959 |
if(items_in_charsetlist < 1 || strucmp(charsetlist[0], ascii)) |
|
3960 |
reset++; |
|
3961 |
||
3962 |
if(items_in_charsetlist != count) |
|
3963 |
reset++; |
|
3964 |
||
3965 |
if(reset){ |
|
3966 |
if(charsetlist) |
|
3967 |
free_list_array(&charsetlist); |
|
3968 |
||
3969 |
/* the list is just ascii and nothing else */
|
|
3970 |
items_in_charsetlist = count; |
|
3971 |
charsetlist = (char **) fs_get((count + 1) * sizeof(char *)); |
|
3972 |
||
3973 |
i = 0; |
|
3974 |
charsetlist[i++] = cpystr(ascii); |
|
3975 |
charsetlist[i] = NULL; |
|
3976 |
}
|
|
3977 |
}
|
|
3978 |
||
3979 |
||
3980 |
if(reset){ |
|
3981 |
if(charsetmap) |
|
3982 |
fs_give((void **) &charsetmap); |
|
3983 |
||
3984 |
if(charsetlist) |
|
3985 |
charsetmap = utf8_csvalidmap(charsetlist); |
|
3986 |
}
|
|
3987 |
||
3988 |
return(charsetmap); |
|
3989 |
}
|
|
3990 |
||
3991 |
||
3992 |
/* total reset */
|
|
3993 |
void
|
|
3994 |
free_charsetchecker(void) |
|
3995 |
{
|
|
3996 |
if(charsetlist) |
|
3997 |
free_list_array(&charsetlist); |
|
3998 |
||
3999 |
items_in_charsetlist = 0; |
|
4000 |
||
4001 |
if(charsetmap) |
|
4002 |
fs_give((void **) &charsetmap); |
|
4003 |
}
|
|
4004 |
||
4005 |
||
4006 |
int
|
|
4007 |
representable_in_charset(unsigned long validbitmap, char *charset) |
|
4008 |
{
|
|
4009 |
int i, done = 0, ret = 0; |
|
4010 |
unsigned long j; |
|
4011 |
||
4012 |
if(!(charset && charset[0])) |
|
4013 |
return ret; |
|
4014 |
||
4015 |
if(!strucmp(charset, "UTF-8")) |
|
4016 |
return 1; |
|
4017 |
||
4018 |
for(i = 0; !done && i < items_in_charsetlist; i++){ |
|
4019 |
if(!strucmp(charset, charsetlist[i])){ |
|
4020 |
j = 1; |
|
4021 |
j <<= (i+1); |
|
4022 |
done++; |
|
4023 |
if(validbitmap & j) |
|
4024 |
ret = 1; |
|
4025 |
}
|
|
4026 |
}
|
|
4027 |
||
4028 |
return ret; |
|
4029 |
}
|
|
4030 |
||
4031 |
||
4032 |
char * |
|
4033 |
most_preferred_charset(unsigned long validbitmap) |
|
4034 |
{
|
|
4035 |
unsigned long bm; |
|
4036 |
unsigned long rm; |
|
4037 |
int index; |
|
4038 |
||
4039 |
if(!(validbitmap && items_in_charsetlist > 0)) |
|
4040 |
return("UTF-8"); |
|
4041 |
||
4042 |
/* careful, find_rightmost_bit modifies the bitmap */
|
|
4043 |
bm = validbitmap; |
|
4044 |
rm = find_rightmost_bit(&bm); |
|
4045 |
index = MIN(MAX(rm-1,0), items_in_charsetlist-1); |
|
4046 |
||
4047 |
return(charsetlist[index]); |
|
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
4048 |
}
|
4049 |
||
4050 |
||
4051 |
/*
|
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
4052 |
* Set parameter to new value.
|
4053 |
*/
|
|
4054 |
void
|
|
4055 |
set_parameter(PARAMETER **param, char *paramname, char *new_value) |
|
4056 |
{
|
|
4057 |
PARAMETER *pm; |
|
4058 |
||
4059 |
if(!param || !(paramname && *paramname)) |
|
4060 |
return; |
|
4061 |
||
4062 |
if(*param == NULL){ |
|
4063 |
pm = (*param) = mail_newbody_parameter(); |
|
4064 |
pm->attribute = cpystr(paramname); |
|
4065 |
}
|
|
4066 |
else{ |
|
4067 |
int nomatch; |
|
4068 |
||
4069 |
for(pm = *param; |
|
4070 |
(nomatch=strucmp(pm->attribute, paramname)) && pm->next != NULL; |
|
4071 |
pm = pm->next) |
|
4072 |
;/* searching for paramname parameter */ |
|
4073 |
||
4074 |
if(nomatch){ /* add charset parameter */ |
|
4075 |
pm->next = mail_newbody_parameter(); |
|
4076 |
pm = pm->next; |
|
4077 |
pm->attribute = cpystr(paramname); |
|
4078 |
}
|
|
4079 |
/* else pm is existing paramname parameter */
|
|
4080 |
}
|
|
4081 |
||
4082 |
if(pm){ |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4083 |
if(!(pm->value && new_value && !strcmp(pm->value, new_value))){ |
4084 |
if(pm->value) |
|
4085 |
fs_give((void **) &pm->value); |
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
4086 |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4087 |
if(new_value) |
4088 |
pm->value = cpystr(new_value); |
|
4089 |
}
|
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
4090 |
}
|
4091 |
}
|
|
4092 |
||
4093 |
||
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4094 |
/*----------------------------------------------------------------------
|
4095 |
Remove the leading digits from SMTP error messages
|
|
4096 |
-----*/
|
|
4097 |
char * |
|
4098 |
tidy_smtp_mess(char *error, char *printstring, char *outbuf, size_t outbuflen) |
|
4099 |
{
|
|
4100 |
while(isdigit((unsigned char)*error) || isspace((unsigned char)*error) || |
|
4101 |
(*error == '.' && isdigit((unsigned char)*(error+1)))) |
|
4102 |
error++; |
|
4103 |
||
4104 |
snprintf(outbuf, outbuflen, printstring, error); |
|
4105 |
outbuf[outbuflen-1] = '\0'; |
|
4106 |
return(outbuf); |
|
4107 |
}
|
|
4108 |
||
4109 |
||
4110 |
/*
|
|
4111 |
* Local globals pine's body output routine needs
|
|
4112 |
*/
|
|
4113 |
static soutr_t l_f; |
|
4114 |
static TCPSTREAM *l_stream; |
|
4115 |
static unsigned c_in_buf = 0; |
|
4116 |
||
4117 |
/*
|
|
4118 |
* def to make our pipe write's more friendly
|
|
4119 |
*/
|
|
4120 |
#ifdef PIPE_MAX
|
|
4121 |
#if PIPE_MAX > 20000
|
|
4122 |
#undef PIPE_MAX
|
|
4123 |
#endif
|
|
4124 |
#endif
|
|
4125 |
||
4126 |
#ifndef PIPE_MAX
|
|
4127 |
#define PIPE_MAX 1024
|
|
4128 |
#endif
|
|
4129 |
||
4130 |
||
4131 |
/*
|
|
4132 |
* l_flust_net - empties gf_io terminal function's buffer
|
|
4133 |
*/
|
|
4134 |
int
|
|
4135 |
l_flush_net(int force) |
|
4136 |
{
|
|
4137 |
if(c_in_buf && c_in_buf < SIZEOF_20KBUF){ |
|
4138 |
char *p = &tmp_20k_buf[0], *lp = NULL, c = '\0'; |
|
4139 |
||
4140 |
tmp_20k_buf[c_in_buf] = '\0'; |
|
4141 |
if(!force){ |
|
4142 |
/*
|
|
4143 |
* The start of each write is expected to be the start of a
|
|
4144 |
* "record" (i.e., a CRLF terminated line). Make sure that is true
|
|
4145 |
* else we might screw up SMTP dot quoting...
|
|
4146 |
*/
|
|
4147 |
for(p = tmp_20k_buf, lp = NULL; |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4148 |
(p = strstr(p, "\015\012")) != NULL; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4149 |
lp = (p += 2)) |
4150 |
;
|
|
4151 |
||
4152 |
||
4153 |
if(!lp && c_in_buf > 2) /* no CRLF! */ |
|
4154 |
for(p = &tmp_20k_buf[c_in_buf] - 2; |
|
4155 |
p > &tmp_20k_buf[0] && *p == '.'; |
|
4156 |
p--) /* find last non-dot */ |
|
4157 |
;
|
|
4158 |
||
4159 |
if(lp && *lp && lp >= tmp_20k_buf && lp < tmp_20k_buf + SIZEOF_20KBUF){ |
|
4160 |
/* snippet remains */
|
|
4161 |
c = *lp; |
|
4162 |
*lp = '\0'; |
|
4163 |
}
|
|
4164 |
}
|
|
4165 |
||
4166 |
if((l_f && !(*l_f)(l_stream, tmp_20k_buf)) |
|
4167 |
|| (lmc.so && !lmc.all_written |
|
4168 |
&& !(lmc.text_only && lmc.text_written) |
|
4169 |
&& !so_puts(lmc.so, tmp_20k_buf))) |
|
4170 |
return(0); |
|
4171 |
||
4172 |
c_in_buf = 0; |
|
4173 |
if(lp && lp >= tmp_20k_buf && lp < tmp_20k_buf + SIZEOF_20KBUF && (*lp = c)) /* Shift text left? */ |
|
4174 |
while(c_in_buf < SIZEOF_20KBUF && (tmp_20k_buf[c_in_buf] = *lp)) |
|
4175 |
c_in_buf++, lp++; |
|
4176 |
}
|
|
4177 |
||
4178 |
return(1); |
|
4179 |
}
|
|
4180 |
||
4181 |
||
4182 |
/*
|
|
4183 |
* l_putc - gf_io terminal function that calls smtp's soutr_t function.
|
|
4184 |
*
|
|
4185 |
*/
|
|
4186 |
int
|
|
4187 |
l_putc(int c) |
|
4188 |
{
|
|
4189 |
if(c_in_buf >= 0 && c_in_buf < SIZEOF_20KBUF) |
|
4190 |
tmp_20k_buf[c_in_buf++] = (char) c; |
|
4191 |
||
4192 |
return((c_in_buf >= PIPE_MAX) ? l_flush_net(FALSE) : TRUE); |
|
4193 |
}
|
|
4194 |
||
4195 |
||
4196 |
||
4197 |
/*
|
|
4198 |
* pine_rfc822_output_body - pine's version of c-client call. Again,
|
|
4199 |
* necessary since c-client doesn't know about how
|
|
4200 |
* we're treating attachments
|
|
4201 |
*/
|
|
4202 |
long
|
|
4203 |
pine_rfc822_output_body(struct mail_bodystruct *body, soutr_t f, void *s) |
|
4204 |
{
|
|
4205 |
PART *part; |
|
4206 |
PARAMETER *param; |
|
4207 |
char *t, *cookie = NIL, *encode_error; |
|
4208 |
char tmp[MAILTMPLEN]; |
|
4209 |
int add_trailing_crlf; |
|
4210 |
LOC_2022_JP ljp; |
|
4211 |
gf_io_t gc; |
|
4212 |
||
4213 |
dprint((4, "-- pine_rfc822_output_body: %d\n", |
|
4214 |
body ? body->type : 0)); |
|
4215 |
if(body->type == TYPEMULTIPART) { /* multipart gets special handling */ |
|
4216 |
part = body->nested.part; /* first body part */ |
|
4217 |
/* find cookie */
|
|
4218 |
for (param = body->parameter; param && !cookie; param = param->next) |
|
4219 |
if (!strucmp (param->attribute,"BOUNDARY")) cookie = param->value; |
|
4220 |
if (!cookie) cookie = "-"; /* yucky default */ |
|
4221 |
||
4222 |
/*
|
|
4223 |
* Output a bit of text before the first multipart delimiter
|
|
4224 |
* to warn unsuspecting users of non-mime-aware ua's that
|
|
4225 |
* they should expect weirdness...
|
|
4226 |
*/
|
|
4227 |
if(f && !(*f)(s, " This message is in MIME format. The first part should be readable text,\015\012 while the remaining parts are likely unreadable without MIME-aware tools.\015\012\015\012")) |
|
4228 |
return(0); |
|
4229 |
||
4230 |
do { /* for each part */ |
|
4231 |
/* build cookie */
|
|
4232 |
snprintf (tmp, sizeof(tmp), "--%s\015\012", cookie); |
|
4233 |
tmp[sizeof(tmp)-1] = '\0'; |
|
4234 |
/* append cookie,mini-hdr,contents */
|
|
4235 |
if((f && !(*f)(s, tmp)) |
|
4236 |
|| (lmc.so && !lmc.all_written && !so_puts(lmc.so, tmp)) |
|
4237 |
|| !pine_write_body_header(&part->body,f,s) |
|
4238 |
|| !pine_rfc822_output_body (&part->body,f,s)) |
|
4239 |
return(0); |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4240 |
} while ((part = part->next) != NULL); /* until done */ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4241 |
/* output trailing cookie */
|
4242 |
snprintf (t = tmp, sizeof(tmp), "--%s--",cookie); |
|
4243 |
tmp[sizeof(tmp)-1] = '\0'; |
|
4244 |
if(lmc.so && !lmc.all_written){ |
|
4245 |
so_puts(lmc.so, t); |
|
4246 |
so_puts(lmc.so, "\015\012"); |
|
4247 |
}
|
|
4248 |
||
4249 |
return(f ? ((*f) (s,t) && (*f) (s,"\015\012")) : 1); |
|
4250 |
}
|
|
4251 |
||
4252 |
l_f = f; /* set up for writing chars... */ |
|
4253 |
l_stream = s; /* out other end of pipe... */ |
|
4254 |
gf_filter_init(); |
|
4255 |
dprint((4, "-- pine_rfc822_output_body: segment %ld bytes\n", |
|
4256 |
body->size.bytes)); |
|
4257 |
||
4258 |
if(body->contents.text.data) |
|
4259 |
gf_set_so_readc(&gc, (STORE_S *) body->contents.text.data); |
|
4260 |
else
|
|
4261 |
return(1); |
|
4262 |
||
4263 |
/*
|
|
4264 |
* Don't add trailing line if it is ExternalText, which already guarantees
|
|
4265 |
* a trailing newline.
|
|
4266 |
*/
|
|
4267 |
add_trailing_crlf = !(((STORE_S *) body->contents.text.data)->src == ExternalText); |
|
4268 |
||
4269 |
so_seek((STORE_S *) body->contents.text.data, 0L, 0); |
|
4270 |
||
4271 |
if(body->type != TYPEMESSAGE){ /* NOT encapsulated message */ |
|
4272 |
char *charset; |
|
4273 |
||
4274 |
if(body->type == TYPETEXT |
|
4275 |
&& so_attr((STORE_S *) body->contents.text.data, "edited", NULL) |
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
4276 |
&& (charset = parameter_val(body->parameter, "charset"))){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4277 |
if(strucmp(charset, "utf-8") && strucmp(charset, "us-ascii")){ |
4278 |
if(!strucmp(charset, "iso-2022-jp")){ |
|
4279 |
ljp.report_err = 0; |
|
4280 |
gf_link_filter(gf_line_test, |
|
4281 |
gf_line_test_opt(translate_utf8_to_2022_jp,&ljp)); |
|
4282 |
}
|
|
4283 |
else{ |
|
4284 |
void *table = utf8_rmap(charset); |
|
4285 |
||
4286 |
if(table){ |
|
4287 |
gf_link_filter(gf_convert_utf8_charset, |
|
4288 |
gf_convert_utf8_charset_opt(table,0)); |
|
4289 |
}
|
|
4290 |
else{ |
|
4291 |
/* else, just send it? */
|
|
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
4292 |
set_parameter(&body->parameter, "charset", "UTF-8"); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4293 |
}
|
4294 |
}
|
|
4295 |
}
|
|
4296 |
||
4297 |
fs_give((void **)&charset); |
|
4298 |
}
|
|
4299 |
||
4300 |
/*
|
|
4301 |
* Convert text pieces to canonical form
|
|
4302 |
* BEFORE applying any encoding (rfc1341: appendix G)...
|
|
4303 |
* NOTE: almost all filters expect CRLF newlines
|
|
4304 |
*/
|
|
4305 |
if(body->type == TYPETEXT |
|
4306 |
&& body->encoding != ENCBASE64 |
|
4307 |
&& !so_attr((STORE_S *) body->contents.text.data, "rawbody", NULL)){ |
|
4308 |
gf_link_filter(gf_local_nvtnl, NULL); |
|
4309 |
}
|
|
4310 |
||
4311 |
switch (body->encoding) { /* all else needs filtering */ |
|
4312 |
case ENC8BIT: /* encode 8BIT into QUOTED-PRINTABLE */ |
|
4313 |
gf_link_filter(gf_8bit_qp, NULL); |
|
4314 |
break; |
|
4315 |
||
4316 |
case ENCBINARY: /* encode binary into BASE64 */ |
|
4317 |
gf_link_filter(gf_binary_b64, NULL); |
|
4318 |
break; |
|
4319 |
||
4320 |
default: /* otherwise text */ |
|
4321 |
break; |
|
4322 |
}
|
|
4323 |
}
|
|
4324 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4325 |
if((encode_error = gf_pipe(gc, l_putc)) != NULL){ /* shove body part down pipe */ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4326 |
q_status_message1(SM_ORDER | SM_DING, 3, 4, |
4327 |
_("Encoding Error \"%s\""), encode_error); |
|
4328 |
display_message('x'); |
|
4329 |
}
|
|
4330 |
||
4331 |
gf_clear_so_readc((STORE_S *) body->contents.text.data); |
|
4332 |
||
4333 |
if(encode_error || !l_flush_net(TRUE)) |
|
4334 |
return(0); |
|
4335 |
||
4336 |
send_bytes_sent += gf_bytes_piped(); |
|
4337 |
so_release((STORE_S *)body->contents.text.data); |
|
4338 |
||
4339 |
if(lmc.so && !lmc.all_written && lmc.text_only){ |
|
4340 |
if(lmc.text_written){ /* we have some splainin' to do */ |
|
4341 |
char tmp[MAILTMPLEN]; |
|
4342 |
char *name = NULL; |
|
4343 |
||
4344 |
if(!(so_puts(lmc.so,_("The following attachment was sent,\015\012")) |
|
4345 |
&& so_puts(lmc.so,_("but NOT saved in the Fcc copy:\015\012")))) |
|
4346 |
return(0); |
|
4347 |
||
4348 |
/*
|
|
4349 |
* BUG: If this name is not ascii it's going to cause trouble.
|
|
4350 |
*/
|
|
1.1.7
by Asheesh Laroia
Import upstream version 2.00+dfsg |
4351 |
name = parameter_val(body->parameter, "name"); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4352 |
snprintf(tmp, sizeof(tmp), |
4353 |
" A %s/%s%s%s%s segment of about %s bytes.\015\012", |
|
4354 |
body_type_names(body->type), |
|
4355 |
body->subtype ? body->subtype : "Unknown", |
|
4356 |
name ? " (Name=\"" : "", |
|
4357 |
name ? name : "", |
|
4358 |
name ? "\")" : "", |
|
4359 |
comatose(body->size.bytes)); |
|
4360 |
tmp[sizeof(tmp)-1] = '\0'; |
|
4361 |
if(name) |
|
4362 |
fs_give((void **)&name); |
|
4363 |
||
4364 |
if(!so_puts(lmc.so, tmp)) |
|
4365 |
return(0); |
|
4366 |
}
|
|
4367 |
else /* suppress everything after first text part */ |
|
4368 |
lmc.text_written = (body->type == TYPETEXT |
|
4369 |
&& (!body->subtype |
|
4370 |
|| !strucmp(body->subtype, "plain"))); |
|
4371 |
}
|
|
4372 |
||
4373 |
if(add_trailing_crlf) |
|
4374 |
return((f ? (*f)(s, "\015\012") : 1) /* output final stuff */ |
|
4375 |
&& ((lmc.so && !lmc.all_written) ? so_puts(lmc.so,"\015\012") : 1)); |
|
4376 |
else
|
|
4377 |
return(1); |
|
4378 |
}
|
|
4379 |
||
4380 |
||
4381 |
/*
|
|
4382 |
* pine_write_body_header - another c-client clone. This time
|
|
4383 |
* so the final encoding labels get set
|
|
4384 |
* correctly since it hasn't happened yet,
|
|
4385 |
* and to be paranoid about line lengths.
|
|
4386 |
*
|
|
4387 |
* Returns: TRUE/nonzero on success, zero on error
|
|
4388 |
*/
|
|
4389 |
int
|
|
4390 |
pine_write_body_header(struct mail_bodystruct *body, soutr_t f, void *s) |
|
4391 |
{
|
|
4392 |
char tmp[MAILTMPLEN]; |
|
4393 |
RFC822BUFFER rbuf; |
|
4394 |
int i; |
|
4395 |
unsigned char c; |
|
4396 |
STRINGLIST *stl; |
|
4397 |
STORE_S *so; |
|
4398 |
extern const char *tspecials; |
|
4399 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4400 |
if((so = so_get(CharStar, NULL, WRITE_ACCESS)) != NULL){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4401 |
if(!(so_puts(so, "Content-Type: ") |
4402 |
&& so_puts(so, body_types[body->type]) |
|
4403 |
&& so_puts(so, "/") |
|
4404 |
&& so_puts(so, body->subtype |
|
4405 |
? body->subtype |
|
4406 |
: rfc822_default_subtype (body->type)))) |
|
4407 |
return(pwbh_finish(0, so)); |
|
4408 |
||
4409 |
if(body->parameter){ |
|
4410 |
if(!pine_write_params(body->parameter, so)) |
|
4411 |
return(pwbh_finish(0, so)); |
|
4412 |
}
|
|
4413 |
else if(!so_puts(so, "; CHARSET=US-ASCII")) |
|
4414 |
return(pwbh_finish(0, so)); |
|
4415 |
||
4416 |
if(!so_puts(so, "\015\012")) |
|
4417 |
return(pwbh_finish(0, so)); |
|
4418 |
||
4419 |
if ((body->encoding /* note: encoding 7BIT never output! */ |
|
4420 |
&& !(so_puts(so, "Content-Transfer-Encoding: ") |
|
4421 |
&& so_puts(so, body_encodings[(body->encoding==ENCBINARY) |
|
4422 |
? ENCBASE64 |
|
4423 |
: (body->encoding == ENC8BIT) |
|
4424 |
? ENCQUOTEDPRINTABLE |
|
4425 |
: (body->encoding <= ENCMAX) |
|
4426 |
? body->encoding |
|
4427 |
: ENCOTHER]) |
|
4428 |
&& so_puts(so, "\015\012"))) |
|
4429 |
/*
|
|
4430 |
* If requested, strip Content-ID headers that don't look like they
|
|
4431 |
* are needed. Microsoft's Outlook XP has a bug that causes it to
|
|
4432 |
* not show that there is an attachment when there is a Content-ID
|
|
4433 |
* header present on that attachment.
|
|
4434 |
*
|
|
4435 |
* If user has quell-content-id turned on, don't output content-id
|
|
4436 |
* unless it is of type message/external-body.
|
|
4437 |
* Since this code doesn't look inside messages being forwarded
|
|
4438 |
* type message content-ids will remain as is and type multipart
|
|
4439 |
* alternative will remain as is. We don't create those on our
|
|
4440 |
* own. If we did, we'd have to worry about getting this right.
|
|
4441 |
*/
|
|
4442 |
|| (body->id && (F_OFF(F_QUELL_CONTENT_ID, ps_global) |
|
4443 |
|| (body->type == TYPEMESSAGE |
|
4444 |
&& body->subtype |
|
4445 |
&& !strucmp(body->subtype, "external-body"))) |
|
4446 |
&& !(so_puts(so, "Content-ID: ") && so_puts(so, body->id) |
|
4447 |
&& so_puts(so, "\015\012"))) |
|
4448 |
|| (body->description |
|
4449 |
&& strlen(body->description) < 5000 /* arbitrary! */ |
|
4450 |
&& !pine_write_header_line("Content-Description: ", body->description, so)) |
|
4451 |
|| (body->md5 |
|
4452 |
&& !(so_puts(so, "Content-MD5: ") |
|
4453 |
&& so_puts(so, body->md5) |
|
4454 |
&& so_puts(so, "\015\012")))) |
|
4455 |
return(pwbh_finish(0, so)); |
|
4456 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4457 |
if ((stl = body->language) != NULL) { |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4458 |
if(!so_puts(so, "Content-Language: ")) |
4459 |
return(pwbh_finish(0, so)); |
|
4460 |
||
4461 |
do { |
|
4462 |
if(strlen((char *)stl->text.data) > 500) /* arbitrary! */ |
|
4463 |
return(pwbh_finish(0, so)); |
|
4464 |
||
4465 |
tmp[0] = '\0'; |
|
4466 |
rbuf.f = dummy_soutr; |
|
4467 |
rbuf.s = NULL; |
|
4468 |
rbuf.beg = tmp; |
|
4469 |
rbuf.cur = tmp; |
|
4470 |
rbuf.end = tmp+sizeof(tmp)-1; |
|
4471 |
rfc822_output_cat(&rbuf, (char *)stl->text.data, tspecials); |
|
4472 |
*rbuf.cur = '\0'; |
|
4473 |
||
4474 |
if(!so_puts(so, tmp) |
|
4475 |
|| ((stl = stl->next) && !so_puts(so, ", "))) |
|
4476 |
return(pwbh_finish(0, so)); |
|
4477 |
}
|
|
4478 |
while (stl); |
|
4479 |
||
4480 |
if(!so_puts(so, "\015\012")) |
|
4481 |
return(pwbh_finish(0, so)); |
|
4482 |
}
|
|
4483 |
||
4484 |
if (body->disposition.type) { |
|
4485 |
if(!(so_puts(so, "Content-Disposition: ") |
|
4486 |
&& so_puts(so, body->disposition.type))) |
|
4487 |
return(pwbh_finish(0, so)); |
|
4488 |
||
4489 |
if(!pine_write_params(body->disposition.parameter, so)) |
|
4490 |
return(pwbh_finish(0, so)); |
|
4491 |
||
4492 |
if(!so_puts(so, "\015\012")) |
|
4493 |
return(pwbh_finish(0, so)); |
|
4494 |
}
|
|
4495 |
||
4496 |
/* copy out of so, a line at a time (or less than a K)
|
|
4497 |
* and send it down the pike
|
|
4498 |
*/
|
|
4499 |
so_seek(so, 0L, 0); |
|
4500 |
i = 0; |
|
4501 |
while(so_readc(&c, so)) |
|
4502 |
if((tmp[i++] = c) == '\012' || i > sizeof(tmp) - 3){ |
|
4503 |
tmp[i] = '\0'; |
|
4504 |
if((f && !(*f)(s, tmp)) |
|
4505 |
|| !lmc_body_header_line(tmp, i <= sizeof(tmp) - 3)) |
|
4506 |
return(pwbh_finish(0, so)); |
|
4507 |
||
4508 |
i = 0; |
|
4509 |
}
|
|
4510 |
||
4511 |
/* Finally, write blank line */
|
|
4512 |
if((f && !(*f)(s, "\015\012")) || !lmc_body_header_finish()) |
|
4513 |
return(pwbh_finish(0, so)); |
|
4514 |
||
4515 |
return(pwbh_finish(i == 0, so)); /* better of ended on LF */ |
|
4516 |
}
|
|
4517 |
||
4518 |
return(0); |
|
4519 |
}
|
|
4520 |
||
4521 |
||
4522 |
/*
|
|
4523 |
* pine_write_header - convert, encode (if needed) and
|
|
4524 |
* write "header-name: field-body"
|
|
4525 |
*/
|
|
4526 |
int
|
|
4527 |
pine_write_header_line(char *hdr, char *val, STORE_S *so) |
|
4528 |
{
|
|
4529 |
char *cv, *cs, *vp; |
|
4530 |
int rv; |
|
4531 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4532 |
cs = posting_characterset(val, NULL, HdrText); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4533 |
cv = utf8_to_charset(val, cs, 0); |
4534 |
vp = rfc1522_encode(tmp_20k_buf, SIZEOF_20KBUF, |
|
4535 |
(unsigned char *) cv, cs); |
|
4536 |
||
4537 |
rv = (so_puts(so, hdr) && so_puts(so, vp) && so_puts(so, "\015\012")); |
|
4538 |
||
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
4539 |
if(cv && cv != val) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4540 |
fs_give((void **) &cv); |
4541 |
||
4542 |
||
4543 |
return(rv); |
|
4544 |
}
|
|
4545 |
||
4546 |
||
4547 |
/*
|
|
4548 |
* pine_write_param - convert, encode and write MIME header-field parameters
|
|
4549 |
*/
|
|
4550 |
int
|
|
4551 |
pine_write_params(PARAMETER *param, STORE_S *so) |
|
4552 |
{
|
|
4553 |
for(; param; param = param->next){ |
|
4554 |
int rv; |
|
4555 |
char *cv, *cs; |
|
4556 |
extern const char *tspecials; |
|
4557 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4558 |
cs = posting_characterset(param->value, NULL, HdrText); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4559 |
cv = utf8_to_charset(param->value, cs, 0); |
4560 |
rv = (so_puts(so, "; ") |
|
4561 |
&& rfc2231_output(so, param->attribute, cv, (char *) tspecials, cs)); |
|
4562 |
||
1.1.1
by Asheesh Laroia
Import upstream version 0.98+dfsg |
4563 |
if(cv && cv != param->value) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4564 |
fs_give((void **) &cv); |
4565 |
||
4566 |
if(!rv) |
|
4567 |
return(0); |
|
4568 |
}
|
|
4569 |
||
4570 |
return(1); |
|
4571 |
}
|
|
4572 |
||
4573 |
||
4574 |
||
4575 |
int
|
|
4576 |
lmc_body_header_line(char *line, int beginning) |
|
4577 |
{
|
|
4578 |
if(lmc.so && !lmc.all_written){ |
|
4579 |
if(beginning && lmc.text_only && lmc.text_written |
|
4580 |
&& (!struncmp(line, "content-type:", 13) |
|
4581 |
|| !struncmp(line, "content-transfer-encoding:", 26) |
|
4582 |
|| !struncmp(line, "content-disposition:", 20))){ |
|
4583 |
/*
|
|
4584 |
* "comment out" the real values since our comment isn't
|
|
4585 |
* likely the same type, disposition nor encoding...
|
|
4586 |
*/
|
|
4587 |
if(!so_puts(lmc.so, "X-")) |
|
4588 |
return(FALSE); |
|
4589 |
}
|
|
4590 |
||
4591 |
return(so_puts(lmc.so, line)); |
|
4592 |
}
|
|
4593 |
||
4594 |
return(TRUE); |
|
4595 |
}
|
|
4596 |
||
4597 |
||
4598 |
int
|
|
4599 |
lmc_body_header_finish(void) |
|
4600 |
{
|
|
4601 |
if(lmc.so && !lmc.all_written){ |
|
4602 |
if(lmc.text_only && lmc.text_written |
|
4603 |
&& !so_puts(lmc.so, "Content-Type: TEXT/PLAIN\015\012")) |
|
4604 |
return(FALSE); |
|
4605 |
||
4606 |
return(so_puts(lmc.so, "\015\012")); |
|
4607 |
}
|
|
4608 |
||
4609 |
return(TRUE); |
|
4610 |
}
|
|
4611 |
||
4612 |
||
4613 |
||
4614 |
int
|
|
4615 |
pwbh_finish(int rv, STORE_S *so) |
|
4616 |
{
|
|
4617 |
if(so) |
|
4618 |
so_give(&so); |
|
4619 |
||
4620 |
return(rv); |
|
4621 |
}
|
|
4622 |
||
4623 |
||
4624 |
/*
|
|
4625 |
* pine_free_body - c-client call wrapper so the body data pointer we
|
|
4626 |
* we're using in a way c-client doesn't know about
|
|
4627 |
* gets free'd appropriately.
|
|
4628 |
*/
|
|
4629 |
void
|
|
4630 |
pine_free_body(struct mail_bodystruct **body) |
|
4631 |
{
|
|
4632 |
/*
|
|
4633 |
* Preempt c-client's contents.text.data clean up since we've
|
|
4634 |
* usurped it's meaning for our own purposes...
|
|
4635 |
*/
|
|
4636 |
pine_free_body_data (*body); |
|
4637 |
||
4638 |
/* Then let c-client handle the rest... */
|
|
4639 |
mail_free_body(body); |
|
4640 |
}
|
|
4641 |
||
4642 |
||
4643 |
/*
|
|
4644 |
* pine_free_body_data - free pine's interpretations of the body part's
|
|
4645 |
* data pointer.
|
|
4646 |
*/
|
|
4647 |
void
|
|
4648 |
pine_free_body_data(struct mail_bodystruct *body) |
|
4649 |
{
|
|
4650 |
if(body){ |
|
4651 |
if(body->type == TYPEMULTIPART){ |
|
4652 |
PART *part = body->nested.part; |
|
4653 |
do /* for each part */ |
|
4654 |
pine_free_body_data(&part->body); |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4655 |
while ((part = part->next) != NULL); /* until done */ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4656 |
}
|
4657 |
else if(body->contents.text.data) |
|
4658 |
so_give((STORE_S **) &body->contents.text.data); |
|
4659 |
}
|
|
4660 |
}
|
|
4661 |
||
4662 |
||
4663 |
long
|
|
4664 |
send_body_size(struct mail_bodystruct *body) |
|
4665 |
{
|
|
4666 |
long l = 0L; |
|
4667 |
PART *part; |
|
4668 |
||
4669 |
if(body->type == TYPEMULTIPART) { /* multipart gets special handling */ |
|
4670 |
part = body->nested.part; /* first body part */ |
|
4671 |
do /* for each part */ |
|
4672 |
l += send_body_size(&part->body); |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
4673 |
while ((part = part->next) != NULL); /* until done */ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4674 |
return(l); |
4675 |
}
|
|
4676 |
||
4677 |
return(l + body->size.bytes); |
|
4678 |
}
|
|
4679 |
||
4680 |
||
4681 |
int
|
|
4682 |
sent_percent(void) |
|
4683 |
{
|
|
4684 |
int i = (int) (((send_bytes_sent + gf_bytes_piped()) * 100) |
|
4685 |
/ send_bytes_to_send); |
|
4686 |
return(MIN(i, 100)); |
|
4687 |
}
|
|
4688 |
||
4689 |
||
4690 |
/*
|
|
4691 |
* pine_smtp_verbose_out - write
|
|
4692 |
*/
|
|
4693 |
void
|
|
4694 |
pine_smtp_verbose_out(char *s) |
|
4695 |
{
|
|
4696 |
#ifdef _WINDOWS
|
|
4697 |
LPTSTR slpt; |
|
4698 |
#endif
|
|
4699 |
if(verbose_send_output && s){ |
|
4700 |
char *p, last = '\0'; |
|
4701 |
||
4702 |
for(p = s; *p; p++) |
|
4703 |
if(*p == '\015') |
|
4704 |
*p = ' '; |
|
4705 |
else
|
|
4706 |
last = *p; |
|
4707 |
||
4708 |
#ifdef _WINDOWS
|
|
4709 |
/*
|
|
4710 |
* The stream is opened in Unicode mode, so we need to fix the
|
|
4711 |
* argument to fputs.
|
|
4712 |
*/
|
|
4713 |
slpt = utf8_to_lptstr((LPSTR) s); |
|
4714 |
if(slpt){ |
|
4715 |
_fputts(slpt, verbose_send_output); |
|
4716 |
fs_give((void **) &slpt); |
|
4717 |
}
|
|
4718 |
||
4719 |
if(last != '\012') |
|
4720 |
_fputtc(L'\n', verbose_send_output); |
|
4721 |
#else
|
|
4722 |
fputs(s, verbose_send_output); |
|
4723 |
if(last != '\012') |
|
4724 |
fputc('\n', verbose_send_output); |
|
4725 |
#endif
|
|
4726 |
}
|
|
4727 |
||
4728 |
}
|
|
4729 |
||
4730 |
||
4731 |
/*
|
|
4732 |
* pine_header_forbidden - is this name a "forbidden" header?
|
|
4733 |
*
|
|
4734 |
* name - the header name to check
|
|
4735 |
* We don't allow user to change these.
|
|
4736 |
*/
|
|
4737 |
int
|
|
4738 |
pine_header_forbidden(char *name) |
|
4739 |
{
|
|
4740 |
char **p; |
|
4741 |
static char *forbidden_headers[] = { |
|
4742 |
"sender", |
|
4743 |
"x-sender", |
|
4744 |
"x-x-sender", |
|
4745 |
"date", |
|
4746 |
"received", |
|
4747 |
"message-id", |
|
4748 |
"in-reply-to", |
|
4749 |
"path", |
|
4750 |
"resent-message-id", |
|
4751 |
"resent-date", |
|
4752 |
"resent-from", |
|
4753 |
"resent-sender", |
|
4754 |
"resent-to", |
|
4755 |
"resent-cc", |
|
4756 |
"resent-reply-to", |
|
4757 |
"mime-version", |
|
4758 |
"content-type", |
|
1.2.1
by Asheesh Laroia
Import upstream version 1.10+dfsg |
4759 |
"x-priority", |
4760 |
"user-agent", |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
4761 |
NULL
|
4762 |
};
|
|
4763 |
||
4764 |
for(p = forbidden_headers; *p; p++) |
|
4765 |
if(!strucmp(name, *p)) |
|
4766 |
break; |
|
4767 |
||
4768 |
return((*p) ? 1 : 0); |
|
4769 |
}
|
|
4770 |
||
4771 |
||
4772 |
/*
|
|
4773 |
* hdr_is_in_list - is there a custom value for this header?
|
|
4774 |
*
|
|
4775 |
* hdr - the header name to check
|
|
4776 |
* custom - the list to check in
|
|
4777 |
* Returns 1 if there is a custom value, 0 otherwise.
|
|
4778 |
*/
|
|
4779 |
int
|
|
4780 |
hdr_is_in_list(char *hdr, PINEFIELD *custom) |
|
4781 |
{
|
|
4782 |
PINEFIELD *pf; |
|
4783 |
||
4784 |
for(pf = custom; pf && pf->name; pf = pf->next) |
|
4785 |
if(strucmp(pf->name, hdr) == 0) |
|
4786 |
return 1; |
|
4787 |
||
4788 |
return 0; |
|
4789 |
}
|
|
4790 |
||
4791 |
||
4792 |
/*
|
|
4793 |
* count_custom_hdrs_pf - returns number of custom headers in arg
|
|
4794 |
* custom -- the list to be counted
|
|
4795 |
* only_nonstandard -- only count headers which aren't standard pine headers
|
|
4796 |
*/
|
|
4797 |
int
|
|
4798 |
count_custom_hdrs_pf(PINEFIELD *custom, int only_nonstandard) |
|
4799 |
{
|
|
4800 |
int ret = 0; |
|
4801 |
||
4802 |
for(; custom && custom->name; custom = custom->next) |
|
4803 |
if(!only_nonstandard || !custom->standard) |
|
4804 |
ret++; |
|
4805 |
||
4806 |
return(ret); |
|
4807 |
}
|
|
4808 |
||
4809 |
||
4810 |
/*
|
|
4811 |
* count_custom_hdrs_list - returns number of custom headers in arg
|
|
4812 |
*/
|
|
4813 |
int
|
|
4814 |
count_custom_hdrs_list(char **list) |
|
4815 |
{
|
|
4816 |
char **p; |
|
4817 |
char *q = NULL; |
|
4818 |
char *name; |
|
4819 |
char *t; |
|
4820 |
char save; |
|
4821 |
int ret = 0; |
|
4822 |
||
4823 |
if(list){ |
|
4824 |
for(p = list; (q = *p) != NULL; p++){ |
|
4825 |
if(q[0]){ |
|
4826 |
/* remove leading whitespace */
|
|
4827 |
name = skip_white_space(q); |
|
4828 |
||
4829 |
/* look for colon or space or end */
|
|
4830 |
for(t = name; |
|
4831 |
*t && !isspace((unsigned char)*t) && *t != ':'; t++) |
|
4832 |
;/* do nothing */ |
|
4833 |
||
4834 |
save = *t; |
|
4835 |
*t = '\0'; |
|
4836 |
if(!pine_header_forbidden(name)) |
|
4837 |
ret++; |
|
4838 |
||
4839 |
*t = save; |
|
4840 |
}
|
|
4841 |
}
|
|
4842 |
}
|
|
4843 |
||
4844 |
return(ret); |
|
4845 |
}
|
|
4846 |
||
4847 |
||
4848 |
/*
|
|
4849 |
* set_default_hdrval - put the user's default value for this header
|
|
4850 |
* into pf->textbuf.
|
|
4851 |
* setthis - the pinefield to be set
|
|
4852 |
* custom - where to look for the default
|
|
4853 |
*/
|
|
4854 |
CustomType
|
|
4855 |
set_default_hdrval(PINEFIELD *setthis, PINEFIELD *custom) |
|
4856 |
{
|
|
4857 |
PINEFIELD *pf; |
|
4858 |
CustomType ret = NoMatch; |
|
4859 |
||
4860 |
if(!setthis || !setthis->name){ |
|
4861 |
q_status_message(SM_ORDER,3,7,"Internal error setting default header"); |
|
4862 |
return(ret); |
|
4863 |
}
|
|
4864 |
||
4865 |
setthis->textbuf = NULL; |
|
4866 |
||
4867 |
for(pf = custom; pf && pf->name; pf = pf->next){ |
|
4868 |
if(strucmp(pf->name, setthis->name) != 0) |
|
4869 |
continue; |
|
4870 |
||
4871 |
ret = pf->cstmtype; |
|
4872 |
||
4873 |
/* turn on editing */
|
|
4874 |
if(strucmp(pf->name, "From") == 0 || strucmp(pf->name, "Reply-To") == 0) |
|
4875 |
setthis->canedit = 1; |
|
4876 |
||
4877 |
if(pf->val) |
|
4878 |
setthis->textbuf = cpystr(pf->val); |
|
4879 |
}
|
|
4880 |
||
4881 |
if(!setthis->textbuf) |
|
4882 |
setthis->textbuf = cpystr(""); |
|
4883 |
||
4884 |
return(ret); |
|
4885 |
}
|
|
4886 |
||
4887 |
||
4888 |
/*
|
|
4889 |
* pine_header_standard - is this name a "standard" header?
|
|
4890 |
*
|
|
4891 |
* name - the header name to check
|
|
4892 |
*/
|
|
4893 |
FieldType
|
|
4894 |
pine_header_standard(char *name) |
|
4895 |
{
|
|
4896 |
int i; |
|
4897 |
||
4898 |
/* check to see if this is a standard header */
|
|
4899 |
for(i = 0; pf_template[i].name; i++) |
|
4900 |
if(!strucmp(name, pf_template[i].name)) |
|
4901 |
return(pf_template[i].type); |
|
4902 |
||
4903 |
return(TypeUnknown); |
|
4904 |
}
|
|
4905 |
||
4906 |
||
4907 |
/*
|
|
4908 |
* customized_hdr_setup - setup the PINEFIELDS for all the customized headers
|
|
4909 |
* Allocates space for each name and addr ptr.
|
|
4910 |
* Allocates space for default in textbuf, even if empty.
|
|
4911 |
*
|
|
4912 |
* head - the first PINEFIELD to fill in
|
|
4913 |
* list - the list to parse
|
|
4914 |
*/
|
|
4915 |
void
|
|
4916 |
customized_hdr_setup(PINEFIELD *head, char **list, CustomType cstmtype) |
|
4917 |
{
|
|
4918 |
char **p, *q, *t, *name, *value, save; |
|
4919 |
PINEFIELD *pf; |
|
4920 |
||
4921 |
pf = head; |
|
4922 |
||
4923 |
if(list){ |
|
4924 |
for(p = list; (q = *p) != NULL; p++){ |
|
4925 |
||
4926 |
if(q[0]){ |
|
4927 |
||
4928 |
/* anything after leading whitespace? */
|
|
4929 |
if(!*(name = skip_white_space(q))) |
|
4930 |
continue; |
|
4931 |
||
4932 |
/* look for colon or space or end */
|
|
4933 |
for(t = name; |
|
4934 |
*t && !isspace((unsigned char)*t) && *t != ':'; t++) |
|
4935 |
;/* do nothing */ |
|
4936 |
||
4937 |
/* if there is a space in the field-name, skip it */
|
|
4938 |
if(isspace((unsigned char)*t)){ |
|
4939 |
q_status_message1(SM_ORDER, 3, 3, |
|
4940 |
_("Space not allowed in header name (%s)"), |
|
4941 |
name); |
|
4942 |
continue; |
|
4943 |
}
|
|
4944 |
||
4945 |
save = *t; |
|
4946 |
*t = '\0'; |
|
4947 |
||
4948 |
/* Don't allow any of the forbidden headers. */
|
|
4949 |
if(pine_header_forbidden(name)){ |
|
4950 |
q_status_message1(SM_ORDER | SM_DING, 3, 3, |
|
4951 |
_("Not allowed to change header \"%s\""), |
|
4952 |
name); |
|
4953 |
||
4954 |
*t = save; |
|
4955 |
continue; |
|
4956 |
}
|
|
4957 |
||
4958 |
if(pf){ |
|
4959 |
if(pine_header_standard(name) != TypeUnknown) |
|
4960 |
pf->standard = 1; |
|
4961 |
||
4962 |
pf->name = cpystr(name); |
|
4963 |
pf->type = FreeText; |
|
4964 |
pf->cstmtype = cstmtype; |
|
4965 |
pf->next = pf+1; |
|
4966 |
||
4967 |
#ifdef OLDWAY
|
|
4968 |
/*
|
|
4969 |
* Some mailers apparently break if we change
|
|
4970 |
* user@domain into Fred <user@domain> for
|
|
4971 |
* return-receipt-to,
|
|
4972 |
* so we'll just call this a FreeText field, too.
|
|
4973 |
*/
|
|
4974 |
/*
|
|
4975 |
* For now, all custom headers are FreeText except for
|
|
4976 |
* this one that we happen to know about. We might
|
|
4977 |
* have to add some syntax to the config option so that
|
|
4978 |
* people can tell us their custom header takes addresses.
|
|
4979 |
*/
|
|
4980 |
if(!strucmp(pf->name, "Return-Receipt-to")){ |
|
4981 |
pf->type = Address; |
|
4982 |
pf->addr = (ADDRESS **)fs_get(sizeof(ADDRESS *)); |
|
4983 |
*pf->addr = (ADDRESS *)NULL; |
|
4984 |
}
|
|
4985 |
#endif /* OLDWAY */ |
|
4986 |
||
4987 |
*t = save; |
|
4988 |
||
4989 |
/* remove space between name and colon */
|
|
4990 |
value = skip_white_space(t); |
|
4991 |
||
4992 |
/* give them an alloc'd default, even if empty */
|
|
4993 |
pf->textbuf = cpystr((*value == ':') |
|
4994 |
? skip_white_space(++value) : ""); |
|
4995 |
if(pf->textbuf && pf->textbuf[0]) |
|
4996 |
pf->val = cpystr(pf->textbuf); |
|
4997 |
||
4998 |
pf++; |
|
4999 |
}
|
|
5000 |
else
|
|
5001 |
*t = save; |
|
5002 |
}
|
|
5003 |
}
|
|
5004 |
}
|
|
5005 |
||
5006 |
/* fix last next pointer */
|
|
5007 |
if(head && pf != head) |
|
5008 |
(pf-1)->next = NULL; |
|
5009 |
}
|
|
5010 |
||
5011 |
||
5012 |
/*
|
|
5013 |
* add_defaults_from_list - the PINEFIELDS list given by "head" is already
|
|
5014 |
* setup except that it doesn't have default values.
|
|
5015 |
* Add those defaults if they exist in "list".
|
|
5016 |
*
|
|
5017 |
* head - the first PINEFIELD to add a default to
|
|
5018 |
* list - the list to get the defaults from
|
|
5019 |
*/
|
|
5020 |
void
|
|
5021 |
add_defaults_from_list(PINEFIELD *head, char **list) |
|
5022 |
{
|
|
5023 |
char **p, *q, *t, *name, *value, save; |
|
5024 |
PINEFIELD *pf; |
|
5025 |
||
5026 |
for(pf = head; pf && list; pf = pf->next){ |
|
5027 |
if(!pf->name) |
|
5028 |
continue; |
|
5029 |
||
5030 |
for(p = list; (q = *p) != NULL; p++){ |
|
5031 |
||
5032 |
if(q[0]){ |
|
5033 |
||
5034 |
/* anything after leading whitespace? */
|
|
5035 |
if(!*(name = skip_white_space(q))) |
|
5036 |
continue; |
|
5037 |
||
5038 |
/* look for colon or space or end */
|
|
5039 |
for(t = name; |
|
5040 |
*t && !isspace((unsigned char)*t) && *t != ':'; t++) |
|
5041 |
;/* do nothing */ |
|
5042 |
||
5043 |
/* if there is a space in the field-name, skip it */
|
|
5044 |
if(isspace((unsigned char)*t)) |
|
5045 |
continue; |
|
5046 |
||
5047 |
save = *t; |
|
5048 |
*t = '\0'; |
|
5049 |
||
5050 |
if(strucmp(name, pf->name) != 0){ |
|
5051 |
*t = save; |
|
5052 |
continue; |
|
5053 |
}
|
|
5054 |
||
5055 |
*t = save; |
|
5056 |
||
5057 |
/*
|
|
5058 |
* Found the right header. See if it has a default
|
|
5059 |
* value set.
|
|
5060 |
*/
|
|
5061 |
||
5062 |
/* remove space between name and colon */
|
|
5063 |
value = skip_white_space(t); |
|
5064 |
||
5065 |
if(*value == ':'){ |
|
5066 |
char *defval; |
|
5067 |
||
5068 |
defval = skip_white_space(++value); |
|
5069 |
if(defval && *defval){ |
|
5070 |
if(pf->val) |
|
5071 |
fs_give((void **)&pf->val); |
|
5072 |
||
5073 |
pf->val = cpystr(defval); |
|
5074 |
}
|
|
5075 |
}
|
|
5076 |
||
5077 |
break; /* on to next pf */ |
|
5078 |
}
|
|
5079 |
}
|
|
5080 |
}
|
|
5081 |
}
|
|
5082 |
||
5083 |
||
5084 |
/*
|
|
5085 |
* parse_custom_hdrs - allocate PINEFIELDS for custom headers
|
|
5086 |
* fill in the defaults
|
|
5087 |
* Args - list -- The list to parse.
|
|
5088 |
* cstmtype -- Fill the in cstmtype field with this value
|
|
5089 |
*/
|
|
5090 |
PINEFIELD * |
|
5091 |
parse_custom_hdrs(char **list, CustomType cstmtype) |
|
5092 |
{
|
|
5093 |
PINEFIELD *pfields; |
|
5094 |
int i; |
|
5095 |
||
5096 |
/*
|
|
5097 |
* add one for possible use by fcc
|
|
5098 |
* What is this "possible use"? I don't see it. I don't
|
|
5099 |
* think it exists anymore. I think +1 would be ok. hubert 2000-08-02
|
|
5100 |
*/
|
|
5101 |
i = (count_custom_hdrs_list(list) + 2) * sizeof(PINEFIELD); |
|
5102 |
pfields = (PINEFIELD *)fs_get((size_t) i); |
|
5103 |
memset(pfields, 0, (size_t) i); |
|
5104 |
||
5105 |
/* set up the custom header pfields */
|
|
5106 |
customized_hdr_setup(pfields, list, cstmtype); |
|
5107 |
||
5108 |
return(pfields); |
|
5109 |
}
|
|
5110 |
||
5111 |
||
5112 |
/*
|
|
5113 |
* Combine the two lists of headers into one list which is allocated here
|
|
5114 |
* and freed by the caller. Eliminate duplicates with values from the role
|
|
5115 |
* taking precedence over values from the default.
|
|
5116 |
*/
|
|
5117 |
PINEFIELD * |
|
5118 |
combine_custom_headers(PINEFIELD *dflthdrs, PINEFIELD *rolehdrs) |
|
5119 |
{
|
|
5120 |
PINEFIELD *pfields, *pf, *pf2; |
|
5121 |
int max_hdrs, i; |
|
5122 |
||
5123 |
max_hdrs = count_custom_hdrs_pf(rolehdrs,0) + |
|
5124 |
count_custom_hdrs_pf(dflthdrs,0); |
|
5125 |
||
5126 |
pfields = (PINEFIELD *)fs_get((size_t)(max_hdrs+1)*sizeof(PINEFIELD)); |
|
5127 |
memset(pfields, 0, (size_t)(max_hdrs+1)*sizeof(PINEFIELD)); |
|
5128 |
||
5129 |
pf = pfields; |
|
5130 |
for(pf2 = rolehdrs; pf2 && pf2->name; pf2 = pf2->next){ |
|
5131 |
pf->name = pf2->name ? cpystr(pf2->name) : NULL; |
|
5132 |
pf->type = pf2->type; |
|
5133 |
pf->cstmtype = pf2->cstmtype; |
|
5134 |
pf->textbuf = pf2->textbuf ? cpystr(pf2->textbuf) : NULL; |
|
5135 |
pf->val = pf2->val ? cpystr(pf2->val) : NULL; |
|
5136 |
pf->standard = pf2->standard; |
|
5137 |
pf->next = pf+1; |
|
5138 |
pf++; |
|
5139 |
}
|
|
5140 |
||
5141 |
/* if these aren't already there, add them */
|
|
5142 |
for(pf2 = dflthdrs; pf2 && pf2->name; pf2 = pf2->next){ |
|
5143 |
/* check for already there */
|
|
5144 |
for(i = 0; |
|
5145 |
pfields[i].name && strucmp(pfields[i].name, pf2->name); |
|
5146 |
i++) |
|
5147 |
;
|
|
5148 |
||
5149 |
if(!pfields[i].name){ /* this is a new one */ |
|
5150 |
pf->name = pf2->name ? cpystr(pf2->name) : NULL; |
|
5151 |
pf->type = pf2->type; |
|
5152 |
pf->cstmtype = pf2->cstmtype; |
|
5153 |
pf->textbuf = pf2->textbuf ? cpystr(pf2->textbuf) : NULL; |
|
5154 |
pf->val = pf2->val ? cpystr(pf2->val) : NULL; |
|
5155 |
pf->standard = pf2->standard; |
|
5156 |
pf->next = pf+1; |
|
5157 |
pf++; |
|
5158 |
}
|
|
5159 |
}
|
|
5160 |
||
5161 |
/* fix last next pointer */
|
|
5162 |
if(pf != pfields) |
|
5163 |
(pf-1)->next = NULL; |
|
5164 |
||
5165 |
return(pfields); |
|
5166 |
}
|
|
5167 |
||
5168 |
||
5169 |
/*
|
|
5170 |
* free_customs - free misc. resources associated with custom header fields
|
|
5171 |
*
|
|
5172 |
* pf - pointer to first custom field
|
|
5173 |
*/
|
|
5174 |
void
|
|
5175 |
free_customs(PINEFIELD *head) |
|
5176 |
{
|
|
5177 |
PINEFIELD *pf; |
|
5178 |
||
5179 |
for(pf = head; pf && pf->name; pf = pf->next){ |
|
5180 |
||
5181 |
fs_give((void **)&pf->name); |
|
5182 |
||
5183 |
if(pf->val) |
|
5184 |
fs_give((void **)&pf->val); |
|
5185 |
||
5186 |
/* only true for FreeText */
|
|
5187 |
if(pf->textbuf) |
|
5188 |
fs_give((void **)&pf->textbuf); |
|
5189 |
||
5190 |
/* only true for Address */
|
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
5191 |
if(pf->addr && *pf->addr) |
5192 |
mail_free_address(pf->addr); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5193 |
}
|
5194 |
||
5195 |
fs_give((void **)&head); |
|
5196 |
}
|
|
5197 |
||
5198 |
||
5199 |
/*
|
|
5200 |
* encode_whole_header
|
|
5201 |
*
|
|
5202 |
* Returns 1 if whole value should be encoded
|
|
5203 |
* 0 to encode only within comments
|
|
5204 |
*/
|
|
5205 |
int
|
|
5206 |
encode_whole_header(char *field, METAENV *header) |
|
5207 |
{
|
|
5208 |
int retval = 0; |
|
5209 |
PINEFIELD *pf; |
|
5210 |
||
5211 |
if(field && (!strucmp(field, "Subject") || |
|
5212 |
!strucmp(field, "Comment") || |
|
5213 |
!struncmp(field, "X-", 2))) |
|
5214 |
retval++; |
|
5215 |
else if(field && *field && header && header->custom){ |
|
5216 |
for(pf = header->custom; pf && pf->name; pf = pf->next){ |
|
5217 |
||
5218 |
if(!pf->standard && !strucmp(pf->name, field)){ |
|
5219 |
retval++; |
|
5220 |
break; |
|
5221 |
}
|
|
5222 |
}
|
|
5223 |
}
|
|
5224 |
||
5225 |
return(retval); |
|
5226 |
}
|
|
5227 |
||
5228 |
||
5229 |
/*----------------------------------------------------------------------
|
|
5230 |
Post news via NNTP or inews
|
|
5231 |
||
5232 |
Args: env -- envelope of message to post
|
|
5233 |
body -- body of message to post
|
|
5234 |
||
5235 |
Returns: -1 if failed or cancelled, 1 if succeeded
|
|
5236 |
||
5237 |
WARNING: This call function has the side effect of writing the message
|
|
5238 |
to the lmc.so object.
|
|
5239 |
----*/
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5240 |
int
|
5241 |
news_poster(METAENV *header, struct mail_bodystruct *body, char **alt_nntp_servers, |
|
5242 |
void (*pipecb_f)(PIPE_S *, int, void *)) |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5243 |
{
|
5244 |
char *error_mess, error_buf[200], **news_servers; |
|
5245 |
char **servers_to_use; |
|
5246 |
int we_cancel = 0, server_no = 0, done_posting = 0; |
|
5247 |
void *orig_822_output; |
|
5248 |
BODY *bp = NULL; |
|
5249 |
||
5250 |
error_buf[0] = '\0'; |
|
5251 |
we_cancel = busy_cue("Posting news", NULL, 0); |
|
5252 |
||
5253 |
dprint((4, "Posting: [%s]\n", |
|
5254 |
(header && header->env && header->env->newsgroups) |
|
5255 |
? header->env->newsgroups : "?")); |
|
5256 |
||
5257 |
if((alt_nntp_servers && alt_nntp_servers[0] && alt_nntp_servers[0][0]) |
|
5258 |
|| (ps_global->VAR_NNTP_SERVER && ps_global->VAR_NNTP_SERVER[0] |
|
5259 |
&& ps_global->VAR_NNTP_SERVER[0][0])){ |
|
5260 |
/*---------- NNTP server defined ----------*/
|
|
5261 |
error_mess = NULL; |
|
5262 |
servers_to_use = (alt_nntp_servers && alt_nntp_servers[0] |
|
5263 |
&& alt_nntp_servers[0][0]) |
|
5264 |
? alt_nntp_servers : ps_global->VAR_NNTP_SERVER; |
|
5265 |
||
5266 |
/*
|
|
5267 |
* Install our rfc822 output routine
|
|
5268 |
*/
|
|
5269 |
orig_822_output = mail_parameters(NULL, GET_RFC822OUTPUT, NULL); |
|
5270 |
(void) mail_parameters(NULL, SET_RFC822OUTPUT, |
|
5271 |
(void *)post_rfc822_output); |
|
5272 |
||
5273 |
server_no = 0; |
|
5274 |
news_servers = (char **)fs_get(2 * sizeof(char *)); |
|
5275 |
news_servers[1] = NULL; |
|
5276 |
while(!done_posting && servers_to_use[server_no] && |
|
5277 |
servers_to_use[server_no][0]){ |
|
5278 |
news_servers[0] = servers_to_use[server_no]; |
|
5279 |
ps_global->noshow_error = 1; |
|
5280 |
#ifdef DEBUG
|
|
5281 |
sending_stream = nntp_open(news_servers, debug ? NOP_DEBUG : 0L); |
|
5282 |
#else
|
|
5283 |
sending_stream = nntp_open(news_servers, 0L); |
|
5284 |
#endif
|
|
5285 |
ps_global->noshow_error = 0; |
|
5286 |
||
5287 |
if(sending_stream != NULL) { |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
5288 |
unsigned short save_encoding, added_encoding; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5289 |
|
5290 |
/*
|
|
5291 |
* Fake that we've got clearance from the transport agent
|
|
5292 |
* for 8bit transport for the benefit of our output routines...
|
|
5293 |
*/
|
|
5294 |
if(F_ON(F_ENABLE_8BIT_NNTP, ps_global) |
|
5295 |
&& (bp = first_text_8bit(body))){ |
|
5296 |
int i; |
|
5297 |
||
5298 |
for(i = 0; (i <= ENCMAX) && body_encodings[i]; i++) |
|
5299 |
;
|
|
5300 |
||
5301 |
if(i > ENCMAX){ /* no empty encoding slots! */ |
|
5302 |
bp = NULL; |
|
5303 |
}
|
|
5304 |
else { |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
5305 |
added_encoding = i; |
5306 |
body_encodings[added_encoding] = body_encodings[ENC8BIT]; |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5307 |
save_encoding = bp->encoding; |
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
5308 |
bp->encoding = added_encoding; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5309 |
}
|
5310 |
}
|
|
5311 |
||
5312 |
/*
|
|
5313 |
* Set global header pointer so we can get at it later...
|
|
5314 |
*/
|
|
5315 |
send_header = header; |
|
5316 |
ps_global->noshow_error = 1; |
|
5317 |
if(nntp_mail(sending_stream, header->env, body) == 0) |
|
5318 |
snprintf(error_mess = error_buf, sizeof(error_buf), |
|
5319 |
_("Error posting message: %s"), |
|
5320 |
sending_stream->reply); |
|
5321 |
else{ |
|
5322 |
done_posting = 1; |
|
5323 |
error_buf[0] = '\0'; |
|
5324 |
error_mess = NULL; |
|
5325 |
}
|
|
5326 |
||
5327 |
error_buf[sizeof(error_buf)-1] = '\0'; |
|
5328 |
smtp_close(sending_stream); |
|
5329 |
ps_global->noshow_error = 0; |
|
5330 |
sending_stream = NULL; |
|
5331 |
if(F_ON(F_ENABLE_8BIT_NNTP, ps_global) && bp){ |
|
1.1.4
by Asheesh Laroia
Import upstream version 0.99999+dfsg |
5332 |
body_encodings[added_encoding] = NULL; |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5333 |
bp->encoding = save_encoding; |
5334 |
}
|
|
5335 |
||
5336 |
} else { |
|
5337 |
/*---- Open of NNTP connection failed ------ */
|
|
5338 |
snprintf(error_mess = error_buf, sizeof(error_buf), |
|
5339 |
_("Error connecting to news server: %s"), |
|
5340 |
ps_global->c_client_error); |
|
5341 |
error_buf[sizeof(error_buf)-1] = '\0'; |
|
5342 |
dprint((1, error_buf)); |
|
5343 |
}
|
|
5344 |
server_no++; |
|
5345 |
}
|
|
5346 |
fs_give((void **)&news_servers); |
|
5347 |
(void) mail_parameters (NULL, SET_RFC822OUTPUT, orig_822_output); |
|
5348 |
} else { |
|
5349 |
/*----- Post via local mechanism -------*/
|
|
5350 |
#ifdef _WINDOWS
|
|
5351 |
snprintf(error_mess = error_buf, sizeof(error_buf), |
|
5352 |
_("Can't post, NNTP-server must be defined!")); |
|
5353 |
#else /* UNIX */ |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5354 |
error_mess = post_handoff(header, body, error_buf, sizeof(error_buf), NULL, |
5355 |
pipecb_f); |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5356 |
#endif
|
5357 |
}
|
|
5358 |
||
5359 |
if(we_cancel) |
|
5360 |
cancel_busy_cue(0); |
|
5361 |
||
5362 |
if(error_mess){ |
|
5363 |
if(lmc.so && !lmc.all_written) |
|
5364 |
so_give(&lmc.so); /* clean up any fcc data */ |
|
5365 |
||
5366 |
q_status_message(SM_ORDER | SM_DING, 4, 5, error_mess); |
|
5367 |
return(-1); |
|
5368 |
}
|
|
5369 |
||
5370 |
lmc.all_written = 1; |
|
5371 |
return(1); |
|
5372 |
}
|
|
5373 |
||
5374 |
||
5375 |
/* ----------------------------------------------------------------------
|
|
5376 |
Figure out command to start local SMTP agent
|
|
5377 |
||
5378 |
Args: errbuf -- buffer for reporting errors (assumed non-NULL)
|
|
5379 |
||
5380 |
Returns an alloc'd copy of the local SMTP agent invocation or NULL
|
|
5381 |
||
5382 |
----*/
|
|
5383 |
char * |
|
5384 |
smtp_command(char *errbuf, size_t errbuflen) |
|
5385 |
{
|
|
5386 |
#ifdef _WINDOWS
|
|
5387 |
if(!(ps_global->VAR_SMTP_SERVER && ps_global->VAR_SMTP_SERVER[0] |
|
5388 |
&& ps_global->VAR_SMTP_SERVER[0][0])) |
|
5389 |
strncpy(errbuf,_("SMTP-server must be defined!"),errbuflen); |
|
5390 |
||
5391 |
errbuf[errbuflen-1] = '\0'; |
|
5392 |
#else /* UNIX */ |
|
5393 |
# if defined(SENDMAIL) && defined(SENDMAILFLAGS)
|
|
5394 |
char tmp[256]; |
|
5395 |
||
5396 |
snprintf(tmp, sizeof(tmp), "%.*s %.*s", (sizeof(tmp)-3)/2, SENDMAIL, |
|
5397 |
(sizeof(tmp)-3)/2, SENDMAILFLAGS); |
|
5398 |
return(cpystr(tmp)); |
|
5399 |
# else
|
|
5400 |
strncpy(errbuf, _("No default posting command."), errbuflen); |
|
5401 |
errbuf[errbuflen-1] = '\0'; |
|
5402 |
# endif
|
|
5403 |
#endif
|
|
5404 |
||
5405 |
return(NULL); |
|
5406 |
}
|
|
5407 |
||
5408 |
||
5409 |
||
5410 |
#ifndef _WINDOWS
|
|
5411 |
/*----------------------------------------------------------------------
|
|
5412 |
Hand off given message to local posting agent
|
|
5413 |
||
5414 |
Args: envelope -- The envelope for the BCC and debugging
|
|
5415 |
header -- The text of the message header
|
|
5416 |
errbuf -- buffer for reporting errors (assumed non-NULL)
|
|
5417 |
len -- Length of errbuf
|
|
5418 |
|
|
5419 |
----*/
|
|
5420 |
int
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5421 |
mta_handoff(METAENV *header, struct mail_bodystruct *body, |
5422 |
char *errbuf, size_t len, |
|
5423 |
void (*bigresult_f) (char *, int), |
|
5424 |
void (*pipecb_f)(PIPE_S *, int, void *)) |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5425 |
{
|
5426 |
#ifdef DF_SENDMAIL_PATH
|
|
5427 |
char cmd_buf[256]; |
|
5428 |
#endif
|
|
5429 |
char *cmd = NULL; |
|
5430 |
||
5431 |
/*
|
|
5432 |
* A bit of complicated policy implemented here.
|
|
5433 |
* There are two posting variables sendmail-path and smtp-server.
|
|
5434 |
* Precedence is in that order.
|
|
5435 |
* They can be set one of 4 ways: fixed, command-line, user, or globally.
|
|
5436 |
* Precedence is in that order.
|
|
5437 |
* Said differently, the order goes something like what's below.
|
|
5438 |
*
|
|
5439 |
* NOTE: the fixed/command-line/user precendence handling is also
|
|
5440 |
* indicated by what's pointed to by ps_global->VAR_*, but since
|
|
5441 |
* that also includes the global defaults, it's not sufficient.
|
|
5442 |
*/
|
|
5443 |
||
5444 |
if(ps_global->FIX_SENDMAIL_PATH |
|
5445 |
&& ps_global->FIX_SENDMAIL_PATH[0]){ |
|
5446 |
cmd = ps_global->FIX_SENDMAIL_PATH; |
|
5447 |
}
|
|
5448 |
else if(!(ps_global->FIX_SMTP_SERVER |
|
5449 |
&& ps_global->FIX_SMTP_SERVER[0])){ |
|
5450 |
if(ps_global->COM_SENDMAIL_PATH |
|
5451 |
&& ps_global->COM_SENDMAIL_PATH[0]){ |
|
5452 |
cmd = ps_global->COM_SENDMAIL_PATH; |
|
5453 |
}
|
|
5454 |
else if(!(ps_global->COM_SMTP_SERVER |
|
5455 |
&& ps_global->COM_SMTP_SERVER[0])){ |
|
5456 |
if((ps_global->vars[V_SENDMAIL_PATH].post_user_val.p |
|
5457 |
&& ps_global->vars[V_SENDMAIL_PATH].post_user_val.p[0]) || |
|
5458 |
(ps_global->vars[V_SENDMAIL_PATH].main_user_val.p |
|
5459 |
&& ps_global->vars[V_SENDMAIL_PATH].main_user_val.p[0])){ |
|
5460 |
if(ps_global->vars[V_SENDMAIL_PATH].post_user_val.p |
|
5461 |
&& ps_global->vars[V_SENDMAIL_PATH].post_user_val.p[0]) |
|
5462 |
cmd = ps_global->vars[V_SENDMAIL_PATH].post_user_val.p; |
|
5463 |
else
|
|
5464 |
cmd = ps_global->vars[V_SENDMAIL_PATH].main_user_val.p; |
|
5465 |
}
|
|
5466 |
else if(!((ps_global->vars[V_SMTP_SERVER].post_user_val.l |
|
5467 |
&& ps_global->vars[V_SMTP_SERVER].post_user_val.l[0]) || |
|
5468 |
(ps_global->vars[V_SMTP_SERVER].main_user_val.l |
|
5469 |
&& ps_global->vars[V_SMTP_SERVER].main_user_val.l[0]))){ |
|
5470 |
if(ps_global->GLO_SENDMAIL_PATH |
|
5471 |
&& ps_global->GLO_SENDMAIL_PATH[0]){ |
|
5472 |
cmd = ps_global->GLO_SENDMAIL_PATH; |
|
5473 |
}
|
|
5474 |
#ifdef DF_SENDMAIL_PATH
|
|
5475 |
/*
|
|
5476 |
* This defines the default method of posting. So,
|
|
5477 |
* unless we're told otherwise use it...
|
|
5478 |
*/
|
|
5479 |
else if(!(ps_global->GLO_SMTP_SERVER |
|
5480 |
&& ps_global->GLO_SMTP_SERVER[0])){ |
|
5481 |
strncpy(cmd = cmd_buf, DF_SENDMAIL_PATH, sizeof(cmd_buf)-1); |
|
5482 |
cmd_buf[sizeof(cmd_buf)-1] = '\0'; |
|
5483 |
}
|
|
5484 |
#endif
|
|
5485 |
}
|
|
5486 |
}
|
|
5487 |
}
|
|
5488 |
||
5489 |
*errbuf = '\0'; |
|
5490 |
if(cmd){ |
|
5491 |
dprint((4, "call_mailer via cmd: %s\n", cmd ? cmd : "?")); |
|
5492 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5493 |
(void) mta_parse_post(header, body, cmd, errbuf, len, bigresult_f, pipecb_f); |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5494 |
return(1); |
5495 |
}
|
|
5496 |
else
|
|
5497 |
return(0); |
|
5498 |
}
|
|
5499 |
||
5500 |
||
5501 |
||
5502 |
/*----------------------------------------------------------------------
|
|
5503 |
Hand off given message to local posting agent
|
|
5504 |
||
5505 |
Args: envelope -- The envelope for the BCC and debugging
|
|
5506 |
header -- The text of the message header
|
|
5507 |
errbuf -- buffer for reporting errors (assumed non-NULL)
|
|
5508 |
errbuflen -- Length of errbuf
|
|
5509 |
|
|
5510 |
Fork off mailer process and pipe the message into it
|
|
5511 |
Called to post news via Inews when NNTP is unavailable
|
|
5512 |
|
|
5513 |
----*/
|
|
5514 |
char * |
|
5515 |
post_handoff(METAENV *header, struct mail_bodystruct *body, char *errbuf, |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5516 |
size_t errbuflen, |
5517 |
void (*bigresult_f) (char *, int), |
|
5518 |
void (*pipecb_f)(PIPE_S *, int, void *)) |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5519 |
{
|
5520 |
char *err = NULL; |
|
5521 |
#ifdef SENDNEWS
|
|
5522 |
char *s; |
|
5523 |
char tmp[200]; |
|
5524 |
||
5525 |
if(s = strstr(header->env->date," (")) /* fix the date format for news */ |
|
5526 |
*s = '\0'; |
|
5527 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5528 |
if(err = mta_parse_post(header, body, SENDNEWS, errbuf, errbuflen, bigresult_f, pipecb_f)){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5529 |
strncpy(tmp, err, sizeof(tmp)-1); |
5530 |
tmp[sizeof(tmp)-1] = '\0'; |
|
5531 |
snprintf(err = errbuf, errbuflen, _("News not posted: \"%s\": %s"), |
|
5532 |
SENDNEWS, tmp); |
|
5533 |
}
|
|
5534 |
||
5535 |
if(s) |
|
5536 |
*s = ' '; /* restore the date */ |
|
5537 |
||
5538 |
#else /* !SENDNEWS */ /* this is the default case */ |
|
5539 |
strncpy(err = errbuf, _("Can't post, NNTP-server must be defined!"), errbuflen-1); |
|
5540 |
err[errbuflen-1] = '\0'; |
|
5541 |
#endif /* !SENDNEWS */ |
|
5542 |
return(err); |
|
5543 |
}
|
|
5544 |
||
5545 |
||
5546 |
||
5547 |
/*----------------------------------------------------------------------
|
|
5548 |
Hand off message to local MTA; it parses recipients from 822 header
|
|
5549 |
||
5550 |
Args: header -- struct containing header data
|
|
5551 |
body -- struct containing message body data
|
|
5552 |
cmd -- command to use for handoff (%s says where file should go)
|
|
5553 |
errs -- pointer to buf to hold errors
|
|
5554 |
||
5555 |
----*/
|
|
5556 |
char * |
|
5557 |
mta_parse_post(METAENV *header, struct mail_bodystruct *body, char *cmd, |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5558 |
char *errs, size_t errslen, void (*bigresult_f)(char *, int), |
5559 |
void (*pipecb_f)(PIPE_S *, int, void *)) |
|
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5560 |
{
|
5561 |
char *result = NULL; |
|
5562 |
PIPE_S *pipe; |
|
5563 |
||
5564 |
dprint((1, "=== mta_parse_post(%s) ===\n", cmd ? cmd : "?")); |
|
5565 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5566 |
if((pipe = open_system_pipe(cmd, &result, NULL, |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5567 |
PIPE_STDERR|PIPE_WRITE|PIPE_PROT|PIPE_NOSHELL|PIPE_DESC, |
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5568 |
0, pipecb_f, pipe_report_error)) != NULL){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5569 |
if(!pine_rfc822_output(header, body, pine_pipe_soutr_nl, |
5570 |
(TCPSTREAM *) pipe)){ |
|
5571 |
strncpy(errs, _("Error posting."), errslen-1); |
|
5572 |
errs[errslen-1] = '\0'; |
|
5573 |
}
|
|
5574 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5575 |
if(close_system_pipe(&pipe, NULL, pipecb_f) && !*errs){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5576 |
snprintf(errs, errslen, _("Posting program %s returned error"), cmd); |
5577 |
if(result && bigresult_f) |
|
5578 |
(*bigresult_f)(result, CM_BR_ERROR); |
|
5579 |
}
|
|
5580 |
}
|
|
5581 |
else
|
|
5582 |
snprintf(errs, errslen, _("Error running \"%s\""), cmd); |
|
5583 |
||
5584 |
if(result){ |
|
5585 |
our_unlink(result); |
|
5586 |
fs_give((void **)&result); |
|
5587 |
}
|
|
5588 |
||
5589 |
return(*errs ? errs : NULL); |
|
5590 |
}
|
|
5591 |
||
5592 |
||
5593 |
/*
|
|
5594 |
* pine_pipe_soutr - Replacement for tcp_soutr that writes one of our
|
|
5595 |
* pipes rather than a tcp stream
|
|
5596 |
*/
|
|
5597 |
long
|
|
5598 |
pine_pipe_soutr_nl (void *stream, char *s) |
|
5599 |
{
|
|
5600 |
long rv = T; |
|
5601 |
char *p; |
|
5602 |
size_t n; |
|
5603 |
||
5604 |
while(*s && rv){ |
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5605 |
if((n = (p = strstr(s, "\015\012")) ? p - s : strlen(s)) != 0) |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5606 |
while((rv = write(((PIPE_S *)stream)->out.d, s, n)) != n) |
5607 |
if(rv < 0){ |
|
5608 |
if(errno != EINTR){ |
|
5609 |
rv = 0; |
|
5610 |
break; |
|
5611 |
}
|
|
5612 |
}
|
|
5613 |
else{ |
|
5614 |
s += rv; |
|
5615 |
n -= rv; |
|
5616 |
}
|
|
5617 |
||
5618 |
if(p && rv){ |
|
5619 |
s = p + 2; /* write UNIX EOL */ |
|
5620 |
while((rv = write(((PIPE_S *)stream)->out.d,"\n",1)) != 1) |
|
5621 |
if(rv < 0 && errno != EINTR){ |
|
5622 |
rv = 0; |
|
5623 |
break; |
|
5624 |
}
|
|
5625 |
}
|
|
5626 |
else
|
|
5627 |
break; |
|
5628 |
}
|
|
5629 |
||
5630 |
return(rv); |
|
5631 |
}
|
|
5632 |
#endif
|
|
5633 |
||
5634 |
||
5635 |
/**************** "PIPE" READING POSTING I/O ROUTINES ****************/
|
|
5636 |
||
5637 |
||
5638 |
/*
|
|
5639 |
* helpful def's
|
|
5640 |
*/
|
|
5641 |
#define S(X) ((PIPE_S *)(X))
|
|
5642 |
#define GETBUFLEN (4 * MAILTMPLEN)
|
|
5643 |
||
5644 |
||
5645 |
void * |
|
5646 |
piped_smtp_open (char *host, char *service, long unsigned int port) |
|
5647 |
{
|
|
5648 |
char *postcmd; |
|
5649 |
void *rv = NULL; |
|
5650 |
||
5651 |
if(strucmp(host, "localhost")){ |
|
5652 |
char tmp[MAILTMPLEN]; |
|
5653 |
||
5654 |
snprintf(tmp, sizeof(tmp), _("Unexpected hostname for piped SMTP: %.*s"), |
|
5655 |
sizeof(tmp)-50, host); |
|
5656 |
tmp[sizeof(tmp)-1] = '\0'; |
|
5657 |
mm_log(tmp, ERROR); |
|
5658 |
}
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5659 |
else if((postcmd = smtp_command(ps_global->c_client_error, sizeof(ps_global->c_client_error))) != NULL){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5660 |
rv = open_system_pipe(postcmd, NULL, NULL, |
5661 |
PIPE_READ|PIPE_STDERR|PIPE_WRITE|PIPE_PROT|PIPE_NOSHELL|PIPE_DESC, |
|
5662 |
0, NULL, pipe_report_error); |
|
5663 |
fs_give((void **) &postcmd); |
|
5664 |
}
|
|
5665 |
else
|
|
5666 |
mm_log(ps_global->c_client_error, ERROR); |
|
5667 |
||
5668 |
return(rv); |
|
5669 |
}
|
|
5670 |
||
5671 |
||
5672 |
void * |
|
5673 |
piped_aopen (NETMBX *mb, char *service, char *user) |
|
5674 |
{
|
|
5675 |
return(NULL); |
|
5676 |
}
|
|
5677 |
||
5678 |
||
5679 |
/*
|
|
5680 |
* piped_soutr - Replacement for tcp_soutr that writes one of our
|
|
5681 |
* pipes rather than a tcp stream
|
|
5682 |
*/
|
|
5683 |
long
|
|
5684 |
piped_soutr (void *stream, char *s) |
|
5685 |
{
|
|
5686 |
return(piped_sout(stream, s, strlen(s))); |
|
5687 |
}
|
|
5688 |
||
5689 |
||
5690 |
/*
|
|
5691 |
* piped_sout - Replacement for tcp_soutr that writes one of our
|
|
5692 |
* pipes rather than a tcp stream
|
|
5693 |
*/
|
|
5694 |
long
|
|
5695 |
piped_sout (void *stream, char *s, long unsigned int size) |
|
5696 |
{
|
|
5697 |
int i, o; |
|
5698 |
||
5699 |
if(S(stream)->out.d < 0) |
|
5700 |
return(0L); |
|
5701 |
||
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5702 |
if((i = (int) size) != 0){ |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5703 |
while((o = write(S(stream)->out.d, s, i)) != i) |
5704 |
if(o < 0){ |
|
5705 |
if(errno != EINTR){ |
|
5706 |
piped_abort(stream); |
|
5707 |
return(0L); |
|
5708 |
}
|
|
5709 |
}
|
|
5710 |
else{ |
|
5711 |
s += o; /* try again, fix up counts */ |
|
5712 |
i -= o; |
|
5713 |
}
|
|
5714 |
}
|
|
5715 |
||
5716 |
return(1L); |
|
5717 |
}
|
|
5718 |
||
5719 |
||
5720 |
/*
|
|
5721 |
* piped_getline - Replacement for tcp_getline that reads one
|
|
5722 |
* of our pipes rather than a tcp pipe
|
|
5723 |
*
|
|
5724 |
* C-client expects that the \r\n will be stripped off.
|
|
5725 |
*/
|
|
5726 |
char * |
|
5727 |
piped_getline (void *stream) |
|
5728 |
{
|
|
5729 |
static int cnt; |
|
5730 |
static char *ptr; |
|
5731 |
int n, m; |
|
5732 |
char *ret, *s, *sp, c = '\0', d; |
|
5733 |
||
5734 |
if(S(stream)->in.d < 0) |
|
5735 |
return(NULL); |
|
5736 |
||
5737 |
if(!S(stream)->tmp){ /* initialize! */ |
|
5738 |
/* alloc space to collect input (freed in close_system_pipe) */
|
|
5739 |
S(stream)->tmp = (char *) fs_get(GETBUFLEN); |
|
5740 |
memset(S(stream)->tmp, 0, GETBUFLEN); |
|
5741 |
cnt = -1; |
|
5742 |
}
|
|
5743 |
||
5744 |
while(cnt < 0){ |
|
5745 |
while((cnt = read(S(stream)->in.d, S(stream)->tmp, GETBUFLEN)) < 0) |
|
5746 |
if(errno != EINTR){ |
|
5747 |
piped_abort(stream); |
|
5748 |
return(NULL); |
|
5749 |
}
|
|
5750 |
||
5751 |
if(cnt == 0){ |
|
5752 |
piped_abort(stream); |
|
5753 |
return(NULL); |
|
5754 |
}
|
|
5755 |
||
5756 |
ptr = S(stream)->tmp; |
|
5757 |
}
|
|
5758 |
||
5759 |
s = ptr; |
|
5760 |
n = 0; |
|
5761 |
while(cnt--){ |
|
5762 |
d = *ptr++; |
|
5763 |
if((c == '\015') && (d == '\012')){ |
|
5764 |
ret = (char *)fs_get (n--); |
|
5765 |
memcpy(ret, s, n); |
|
5766 |
ret[n] = '\0'; |
|
5767 |
return(ret); |
|
5768 |
}
|
|
5769 |
||
5770 |
n++; |
|
5771 |
c = d; |
|
5772 |
}
|
|
5773 |
/* copy partial string from buffer */
|
|
5774 |
memcpy((ret = sp = (char *) fs_get (n)), s, n); |
|
5775 |
/* get more data */
|
|
5776 |
while(cnt < 0){ |
|
5777 |
memset(S(stream)->tmp, 0, GETBUFLEN); |
|
5778 |
while((cnt = read(S(stream)->in.d, S(stream)->tmp, GETBUFLEN)) < 0) |
|
5779 |
if(errno != EINTR){ |
|
5780 |
fs_give((void **) &ret); |
|
5781 |
piped_abort(stream); |
|
5782 |
return(NULL); |
|
5783 |
}
|
|
5784 |
||
5785 |
if(cnt == 0){ |
|
5786 |
if(n > 0) |
|
5787 |
ret[n-1] = '\0'; /* to try to get error message logged */ |
|
5788 |
else{ |
|
5789 |
piped_abort(stream); |
|
5790 |
return(NULL); |
|
5791 |
}
|
|
5792 |
}
|
|
5793 |
||
5794 |
ptr = S(stream)->tmp; |
|
5795 |
}
|
|
5796 |
||
5797 |
if(c == '\015' && *ptr == '\012'){ |
|
5798 |
ptr++; |
|
5799 |
cnt--; |
|
5800 |
ret[n - 1] = '\0'; /* tie off string with null */ |
|
5801 |
}
|
|
1.1.3
by Asheesh Laroia
Import upstream version 0.9999+dfsg |
5802 |
else if ((s = piped_getline(stream)) != NULL) { |
1
by Asheesh Laroia
Import upstream version 0.82+dfsg |
5803 |
ret = (char *) fs_get(n + 1 + (m = strlen (s))); |
5804 |
memcpy(ret, sp, n); /* copy first part */ |
|
5805 |
memcpy(ret + n, s, m); /* and second part */ |
|
5806 |
fs_give((void **) &sp); /* flush first part */ |
|
5807 |
fs_give((void **) &s); /* flush second part */ |
|
5808 |
ret[n + m] = '\0'; /* tie off string with null */ |
|
5809 |
}
|
|
5810 |
||
5811 |
return(ret); |
|
5812 |
}
|
|
5813 |
||
5814 |
||
5815 |
/*
|
|
5816 |
* piped_close - Replacement for tcp_close that closes pipes to our
|
|
5817 |
* child rather than a tcp connection
|
|
5818 |
*/
|
|
5819 |
void
|
|
5820 |
piped_close(void *stream) |
|
5821 |
{
|
|
5822 |
/*
|
|
5823 |
* Uninstall our hooks into smtp_send since it's being used by
|
|
5824 |
* the nntp driver as well...
|
|
5825 |
*/
|
|
5826 |
(void) close_system_pipe((PIPE_S **) &stream, NULL, NULL); |
|
5827 |
}
|
|
5828 |
||
5829 |
||
5830 |
/*
|
|
5831 |
* piped_abort - close down the pipe we were using to post
|
|
5832 |
*/
|
|
5833 |
void
|
|
5834 |
piped_abort(void *stream) |
|
5835 |
{
|
|
5836 |
if(S(stream)->in.d >= 0){ |
|
5837 |
close(S(stream)->in.d); |
|
5838 |
S(stream)->in.d = -1; |
|
5839 |
}
|
|
5840 |
||
5841 |
if(S(stream)->out.d){ |
|
5842 |
close(S(stream)->out.d); |
|
5843 |
S(stream)->out.d = -1; |
|
5844 |
}
|
|
5845 |
}
|
|
5846 |
||
5847 |
||
5848 |
char * |
|
5849 |
piped_host(void *stream) |
|
5850 |
{
|
|
5851 |
return(ps_global->hostname ? ps_global->hostname : "localhost"); |
|
5852 |
}
|
|
5853 |
||
5854 |
||
5855 |
unsigned long |
|
5856 |
piped_port(void *stream) |
|
5857 |
{
|
|
5858 |
return(0L); |
|
5859 |
}
|