2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2007 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 #include "../pith/headers.h"
16 #include "../pith/addrstring.h"
17 #include "../pith/state.h"
18 #include "../pith/copyaddr.h"
19 #include "../pith/charset.h"
20 #include "../pith/stream.h"
26 void rfc822_write_address_decode(char *, size_t, ADDRESS
*, int);
30 * Format an address structure into a string
32 * Args: addr -- Single ADDRESS structure to turn into a string
34 * Result: Fills in buf and returns pointer to it.
35 * Just uses the c-client call to do this.
36 * (the address is not rfc1522 decoded)
39 addr_string(struct mail_address
*addr
, char *buf
, size_t buflen
)
45 next_addr
= addr
->next
;
51 rbuf
.end
= buf
+buflen
-1;
52 rfc822_output_address_list(&rbuf
, addr
, 0L, NULL
);
54 addr
->next
= next_addr
;
60 * Same as addr_string only it doesn't have to be a
64 addr_string_mult(struct mail_address
*addr
, char *buf
, size_t buflen
)
73 rbuf
.end
= buf
+buflen
-1;
74 rfc822_output_address_list(&rbuf
, addr
, 0L, NULL
);
81 * Format an address structure into a simple string: "mailbox@host"
83 * Args: addr -- Single ADDRESS structure to turn into a string
84 * buf -- buffer to write address in;
86 * Result: Returns pointer to buf;
89 simple_addr_string(struct mail_address
*addr
, char *buf
, size_t buflen
)
97 rbuf
.end
= buf
+buflen
-1;
98 rfc822_output_address(&rbuf
, addr
);
106 * Format an address structure into a simple string: "mailbox@host"
107 * Like simple_addr_string but can be multiple addresses.
109 * Args: addr -- ADDRESS structure to turn into a string
110 * buf -- buffer to write address in;
111 * buflen -- length of buffer
112 * sep -- separator string
114 * Result: Returns pointer to internal static formatted string.
115 * Just uses the c-client call to do this.
118 simple_mult_addr_string(struct mail_address
*addr
, char *buf
, size_t buflen
, char *sep
)
125 seplen
= strlen(sep
);
128 for(a
= addr
; a
; a
= a
->next
){
129 if(dest
> buf
&& seplen
> 0 && buflen
-1-(dest
-buf
) >= seplen
){
130 strncpy(dest
, sep
, seplen
);
135 simple_addr_string(a
, dest
, buflen
-(dest
-buf
));
136 dest
+= strlen(dest
);
139 buf
[buflen
-1] = '\0';
146 * 1522 encode the personal name portion of addr and return an allocated
147 * copy of the resulting address string.
150 encode_fullname_of_addrstring(char *addr
, char *charset
)
156 static char *fakedomain
= "@";
160 tmp_a_string
= cpystr(addr
? addr
: "");
162 rfc822_parse_adrlist(&adr
, tmp_a_string
, fakedomain
);
163 fs_give((void **)&tmp_a_string
);
168 if(adr
->personal
&& adr
->personal
[0]){
169 pers_encoded
= cpystr(rfc1522_encode(tmp_20k_buf
, SIZEOF_20KBUF
,
170 (unsigned char *)adr
->personal
,
172 fs_give((void **)&adr
->personal
);
173 adr
->personal
= pers_encoded
;
177 ret
= (char *) fs_get(len
* sizeof(char));
179 rbuf
.f
= dummy_soutr
;
183 rbuf
.end
= ret
+len
-1;
184 rfc822_output_address_list(&rbuf
, adr
, 0L, NULL
);
186 mail_free_address(&adr
);
192 * 1522 decode the personal name portion of addr and return an allocated
193 * copy of the resulting address string.
196 decode_fullname_of_addrstring(char *addr
, int verbose
)
202 static char *fakedomain
= "@";
206 tmp_a_string
= cpystr(addr
? addr
: "");
208 rfc822_parse_adrlist(&adr
, tmp_a_string
, fakedomain
);
209 fs_give((void **)&tmp_a_string
);
214 if(adr
->personal
&& adr
->personal
[0]){
216 = cpystr((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
217 SIZEOF_20KBUF
, adr
->personal
));
218 fs_give((void **)&adr
->personal
);
219 adr
->personal
= pers_decoded
;
223 ret
= (char *) fs_get(len
* sizeof(char));
225 rbuf
.f
= dummy_soutr
;
229 rbuf
.end
= ret
+len
-1;
230 rfc822_output_address_list(&rbuf
, adr
, 0L, NULL
);
232 mail_free_address(&adr
);
238 * Turn a list of address structures into a formatted string
240 * Args: adrlist -- An adrlist
241 * f -- Function to use to print one address in list. If NULL,
242 * use rfc822_write_address_decode to print whole list.
243 * do_quote -- Quote quotes and dots (only used if f == NULL).
244 * Result: comma separated list of addresses which is
245 * malloced here and returned
246 * (the list is rfc1522 decoded unless f is *not* NULL)
249 addr_list_string(struct mail_address
*adrlist
,
250 char *(*f
)(struct mail_address
*, char *, size_t),
254 char *list
, *s
, string
[MAX_ADDR_EXPN
+1];
262 for(a
= adrlist
; a
; a
= a
->next
)
263 len
+= (strlen((*f
)(a
, string
, sizeof(string
))) + 2);
265 list
= (char *) fs_get((len
+1) * sizeof(char));
269 for(a
= adrlist
; a
; a
= a
->next
){
270 sstrncpy(&s
, (*f
)(a
, string
, sizeof(string
)), len
-(s
-list
));
271 if(a
->next
&& len
-(s
-list
) > 2){
278 len
= est_size(adrlist
);
279 list
= (char *) fs_get((len
+1) * sizeof(char));
281 rfc822_write_address_decode(list
, len
+1, adrlist
, do_quote
);
282 removing_leading_and_trailing_white_space(list
);
290 static long rfc822_dummy_soutr (void *stream
, char *string
)
296 * Copied from c-client/rfc822.c buf with dot and double quote removed.
298 static const char *rspecials_minus_quote_and_dot
= "()<>@,;:\\[]\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177";
300 /* Write RFC822 address with 1522 decoding of personal name
301 * and optional quoting.
303 * The idea is that there are some places where we'd just like to display
304 * the personal name as is before applying confusing quoting. However,
305 * we do want to be careful not to break things that should be quoted so
306 * we'll only use this where we are sure. Quoting may look ugly but it
307 * doesn't usually break anything.
310 rfc822_write_address_decode(char *dest
, size_t destlen
, struct mail_address
*adr
, int do_quote
)
313 extern const char *rspecials
;
317 * We want to print the adr list after decoding it. C-client knows
318 * how to parse and print, so we want to use that. But c-client
319 * doesn't decode. So we make a copy of the address list, decode
320 * things there, and let c-client print that.
322 copy
= copyaddrlist(adr
);
323 for(a
= copy
; a
; a
= a
->next
){
324 if(a
->host
){ /* ordinary address? */
325 if(a
->personal
&& *a
->personal
){
328 p
= rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
,
329 SIZEOF_20KBUF
, a
->personal
);
331 if(p
&& (char *) p
!= a
->personal
){
332 fs_give((void **) &a
->personal
);
333 a
->personal
= cpystr((char *) p
);
337 else if(a
->mailbox
&& *a
->mailbox
){ /* start of group? */
340 p
= rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf
, SIZEOF_20KBUF
, a
->mailbox
);
342 if(p
&& (char *) p
!= a
->mailbox
){
343 fs_give((void **) &a
->mailbox
);
344 a
->mailbox
= cpystr((char *) p
);
349 buf
.end
= (buf
.beg
= buf
.cur
= dest
) + destlen
;
350 buf
.f
= rfc822_dummy_soutr
;
354 (void) rfc822_output_address_list(&buf
, copy
, 0,
355 do_quote
? rspecials
: rspecials_minus_quote_and_dot
);
360 mail_free_address(©
);
365 * Compute an upper bound on the size of the array required by
366 * rfc822_write_address for this list of addresses.
368 * Args: adrlist -- The address list.
370 * Returns -- an integer giving the upper bound
373 est_size(struct mail_address
*a
)
377 for(; a
; a
= a
->next
){
379 /* two times personal for possible quoting */
380 cnt
+= 2 * (a
->personal
? (strlen(a
->personal
)+1) : 0);
381 cnt
+= 2 * (a
->mailbox
? (strlen(a
->mailbox
)+1) : 0);
382 cnt
+= (a
->adl
? strlen(a
->adl
) : 0);
383 cnt
+= (a
->host
? strlen(a
->host
) : 0);
387 * possible single space between fullname and addr
388 * left and right brackets
390 * possible : for route addr
393 * So I really think that adding 7 is enough. Instead, I'll add 10.
398 return(MAX(cnt
, 50)); /* just making sure */
403 * Returns the number of addresses in the list.
406 count_addrs(struct mail_address
*adrlist
)
411 if(adrlist
->mailbox
&& adrlist
->mailbox
[0])
414 adrlist
= adrlist
->next
;
422 * Buf is at least size maxlen+1
425 a_little_addr_string(struct mail_address
*addr
, char *buf
, size_t maxlen
)
429 if(addr
->personal
&& addr
->personal
[0]){
430 char tmp
[MAILTMPLEN
];
432 snprintf(tmp
, sizeof(tmp
), "%s", addr
->personal
);
433 iutf8ncpy(buf
, (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
437 else if(addr
->mailbox
&& addr
->mailbox
[0]){
438 strncpy(buf
, addr
->mailbox
, maxlen
);
440 if(addr
->host
&& addr
->host
[0] && addr
->host
[0] != '.'){
441 strncat(buf
, "@", maxlen
+1-1-strlen(buf
));
442 strncat(buf
, addr
->host
, maxlen
+1-1-strlen(buf
));