* Remove the "SetRole" option when opening a URL.
[alpine.git] / pith / addrstring.c
blob29025c74e303d10834751de6b484b38f8933ab51
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: addrstring.c 770 2007-10-24 00:23:09Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2020 Eduardo Chappa
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
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include "../pith/headers.h"
20 #include "../pith/addrstring.h"
21 #include "../pith/state.h"
22 #include "../pith/copyaddr.h"
23 #include "../pith/charset.h"
24 #include "../pith/stream.h"
28 * Internal prototypes
30 void rfc822_write_address_decode(char *, size_t, ADDRESS *, int);
34 * Format an address structure into a string
36 * Args: addr -- Single ADDRESS structure to turn into a string
38 * Result: Fills in buf and returns pointer to it.
39 * Just uses the c-client call to do this.
40 * (the address is not rfc1522 decoded)
42 char *
43 addr_string(struct mail_address *addr, char *buf, size_t buflen)
45 ADDRESS *next_addr;
46 RFC822BUFFER rbuf;
48 *buf = '\0';
49 next_addr = addr->next;
50 addr->next = NULL;
51 rbuf.f = dummy_soutr;
52 rbuf.s = NULL;
53 rbuf.beg = buf;
54 rbuf.cur = buf;
55 rbuf.end = buf+buflen-1;
56 rfc822_output_address_list(&rbuf, addr, 0L, NULL);
57 *rbuf.cur = '\0';
58 addr->next = next_addr;
59 return(buf);
64 * Same as addr_string only it doesn't have to be a
65 * single address.
67 char *
68 addr_string_mult(struct mail_address *addr, char *buf, size_t buflen)
70 RFC822BUFFER rbuf;
72 *buf = '\0';
73 rbuf.f = dummy_soutr;
74 rbuf.s = NULL;
75 rbuf.beg = buf;
76 rbuf.cur = buf;
77 rbuf.end = buf+buflen-1;
78 rfc822_output_address_list(&rbuf, addr, 0L, NULL);
79 *rbuf.cur = '\0';
80 return(buf);
85 * Format an address structure into a simple string: "mailbox@host"
87 * Args: addr -- Single ADDRESS structure to turn into a string
88 * buf -- buffer to write address in;
90 * Result: Returns pointer to buf;
92 char *
93 simple_addr_string(struct mail_address *addr, char *buf, size_t buflen)
95 RFC822BUFFER rbuf;
97 rbuf.f = dummy_soutr;
98 rbuf.s = NULL;
99 rbuf.beg = buf;
100 rbuf.cur = buf;
101 rbuf.end = buf+buflen-1;
102 rfc822_output_address(&rbuf, addr);
103 *rbuf.cur = '\0';
105 return(buf);
110 * Format an address structure into a simple string: "mailbox@host"
111 * Like simple_addr_string but can be multiple addresses.
113 * Args: addr -- ADDRESS structure to turn into a string
114 * buf -- buffer to write address in;
115 * buflen -- length of buffer
116 * sep -- separator string
118 * Result: Returns pointer to internal static formatted string.
119 * Just uses the c-client call to do this.
121 char *
122 simple_mult_addr_string(struct mail_address *addr, char *buf, size_t buflen, char *sep)
124 ADDRESS *a;
125 char *dest = buf;
126 size_t seplen = 0;
128 if(sep)
129 seplen = strlen(sep);
131 *dest = '\0';
132 for(a = addr; a; a = a->next){
133 if(dest > buf && seplen > 0 && buflen-1-(dest-buf) >= seplen){
134 strncpy(dest, sep, seplen);
135 dest += seplen;
136 *dest = '\0';
139 simple_addr_string(a, dest, buflen-(dest-buf));
140 dest += strlen(dest);
143 buf[buflen-1] = '\0';
145 return(buf);
150 * 1522 encode the personal name portion of addr and return an allocated
151 * copy of the resulting address string.
153 char *
154 encode_fullname_of_addrstring(char *addr, char *charset)
156 char *pers_encoded,
157 *tmp_a_string,
158 *ret = NULL;
159 ADDRESS *adr;
160 static char *fakedomain = "@";
161 RFC822BUFFER rbuf;
162 size_t len;
164 tmp_a_string = cpystr(addr ? addr : "");
165 adr = NULL;
166 rfc822_parse_adrlist(&adr, tmp_a_string, fakedomain);
167 fs_give((void **)&tmp_a_string);
169 if(!adr)
170 return(cpystr(""));
172 if(adr->personal && adr->personal[0]){
173 pers_encoded = cpystr(rfc1522_encode(tmp_20k_buf, SIZEOF_20KBUF,
174 (unsigned char *)adr->personal,
175 charset));
176 fs_give((void **)&adr->personal);
177 adr->personal = pers_encoded;
180 len = est_size(adr);
181 ret = (char *) fs_get(len * sizeof(char));
182 ret[0] = '\0';
183 rbuf.f = dummy_soutr;
184 rbuf.s = NULL;
185 rbuf.beg = ret;
186 rbuf.cur = ret;
187 rbuf.end = ret+len-1;
188 rfc822_output_address_list(&rbuf, adr, 0L, NULL);
189 *rbuf.cur = '\0';
190 mail_free_address(&adr);
191 return(ret);
196 * 1522 decode the personal name portion of addr and return an allocated
197 * copy of the resulting address string.
199 char *
200 decode_fullname_of_addrstring(char *addr, int verbose)
202 char *pers_decoded,
203 *tmp_a_string,
204 *ret = NULL;
205 ADDRESS *adr;
206 static char *fakedomain = "@";
207 RFC822BUFFER rbuf;
208 size_t len;
210 tmp_a_string = cpystr(addr ? addr : "");
211 adr = NULL;
212 rfc822_parse_adrlist(&adr, tmp_a_string, fakedomain);
213 fs_give((void **)&tmp_a_string);
215 if(!adr)
216 return(cpystr(""));
218 if(adr->personal && adr->personal[0]){
219 pers_decoded
220 = cpystr((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
221 SIZEOF_20KBUF, adr->personal));
222 fs_give((void **)&adr->personal);
223 adr->personal = pers_decoded;
226 len = est_size(adr);
227 ret = (char *) fs_get(len * sizeof(char));
228 ret[0] = '\0';
229 rbuf.f = dummy_soutr;
230 rbuf.s = NULL;
231 rbuf.beg = ret;
232 rbuf.cur = ret;
233 rbuf.end = ret+len-1;
234 rfc822_output_address_list(&rbuf, adr, 0L, NULL);
235 *rbuf.cur = '\0';
236 mail_free_address(&adr);
237 return(ret);
242 * Turn a list of address structures into a formatted string
244 * Args: adrlist -- An adrlist
245 * f -- Function to use to print one address in list. If NULL,
246 * use rfc822_write_address_decode to print whole list.
247 * do_quote -- Quote quotes and dots (only used if f == NULL).
248 * Result: comma separated list of addresses which is
249 * malloced here and returned
250 * (the list is rfc1522 decoded unless f is *not* NULL)
252 char *
253 addr_list_string(struct mail_address *adrlist,
254 char *(*f)(struct mail_address *, char *, size_t),
255 int do_quote)
257 size_t len;
258 char *list, *s, string[MAX_ADDR_EXPN+1];
259 register ADDRESS *a;
261 if(!adrlist)
262 return(cpystr(""));
264 if(f){
265 len = 0;
266 for(a = adrlist; a; a = a->next)
267 len += (strlen((*f)(a, string, sizeof(string))) + 2);
269 list = (char *) fs_get((len+1) * sizeof(char));
270 s = list;
271 s[0] = '\0';
273 for(a = adrlist; a; a = a->next){
274 sstrncpy(&s, (*f)(a, string, sizeof(string)), len-(s-list));
275 if(a->next && len-(s-list) > 2){
276 *s++ = ',';
277 *s++ = SPACE;
281 else{
282 len = est_size(adrlist);
283 list = (char *) fs_get((len+1) * sizeof(char));
284 list[0] = '\0';
285 rfc822_write_address_decode(list, len+1, adrlist, do_quote);
286 removing_leading_and_trailing_white_space(list);
289 list[len] = '\0';
290 return(list);
294 static long rfc822_dummy_soutr (void *stream, char *string)
296 return LONGT;
300 * Copied from c-client/rfc822.c buf with dot and double quote removed.
302 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";
304 /* Write RFC822 address with 1522 decoding of personal name
305 * and optional quoting.
307 * The idea is that there are some places where we'd just like to display
308 * the personal name as is before applying confusing quoting. However,
309 * we do want to be careful not to break things that should be quoted so
310 * we'll only use this where we are sure. Quoting may look ugly but it
311 * doesn't usually break anything.
313 void
314 rfc822_write_address_decode(char *dest, size_t destlen, struct mail_address *adr, int do_quote)
316 RFC822BUFFER buf;
317 extern const char *rspecials;
318 ADDRESS *copy, *a;
321 * We want to print the adr list after decoding it. C-client knows
322 * how to parse and print, so we want to use that. But c-client
323 * doesn't decode. So we make a copy of the address list, decode
324 * things there, and let c-client print that.
326 copy = copyaddrlist(adr);
327 for(a = copy; a; a = a->next){
328 if(a->host){ /* ordinary address? */
329 if(a->personal && *a->personal){
330 unsigned char *p;
332 p = rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf,
333 SIZEOF_20KBUF, a->personal);
335 if(p && (char *) p != a->personal){
336 fs_give((void **) &a->personal);
337 a->personal = cpystr((char *) p);
341 else if(a->mailbox && *a->mailbox){ /* start of group? */
342 unsigned char *p;
344 p = rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, SIZEOF_20KBUF, a->mailbox);
346 if(p && (char *) p != a->mailbox){
347 fs_give((void **) &a->mailbox);
348 a->mailbox = cpystr((char *) p);
353 buf.end = (buf.beg = buf.cur = dest) + destlen;
354 buf.f = rfc822_dummy_soutr;
355 *buf.cur = '\0';
356 buf.s = NIL;
358 (void) rfc822_output_address_list(&buf, copy, 0,
359 do_quote ? rspecials : rspecials_minus_quote_and_dot);
361 *buf.cur = '\0';
363 if(copy)
364 mail_free_address(&copy);
369 * Compute an upper bound on the size of the array required by
370 * rfc822_write_address for this list of addresses.
372 * Args: adrlist -- The address list.
374 * Returns -- an integer giving the upper bound
377 est_size(struct mail_address *a)
379 int cnt = 0;
381 for(; a; a = a->next){
383 /* two times personal for possible quoting */
384 cnt += 2 * (a->personal ? (strlen(a->personal)+1) : 0);
385 cnt += 2 * (a->mailbox ? (strlen(a->mailbox)+1) : 0);
386 cnt += (a->adl ? strlen(a->adl) : 0);
387 cnt += (a->host ? strlen(a->host) : 0);
390 * add room for:
391 * possible single space between fullname and addr
392 * left and right brackets
393 * @ sign
394 * possible : for route addr
395 * , <space>
397 * So I really think that adding 7 is enough. Instead, I'll add 10.
399 cnt += 10;
402 return(MAX(cnt, 50)); /* just making sure */
407 * Returns the number of addresses in the list.
410 count_addrs(struct mail_address *adrlist)
412 int cnt = 0;
414 while(adrlist){
415 if(adrlist->mailbox && adrlist->mailbox[0])
416 cnt++;
418 adrlist = adrlist->next;
421 return(cnt);
426 * Buf is at least size maxlen+1
428 void
429 a_little_addr_string(struct mail_address *addr, char *buf, size_t maxlen)
431 buf[0] = '\0';
432 if(addr){
433 if(addr->personal && addr->personal[0]){
434 char tmp[MAILTMPLEN];
436 snprintf(tmp, sizeof(tmp), "%s", addr->personal);
437 iutf8ncpy(buf, (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf,
438 SIZEOF_20KBUF, tmp),
439 maxlen);
441 else if(addr->mailbox && addr->mailbox[0]){
442 strncpy(buf, addr->mailbox, maxlen);
443 buf[maxlen] = '\0';
444 if(addr->host && addr->host[0] && addr->host[0] != '.'){
445 strncat(buf, "@", maxlen+1-1-strlen(buf));
446 strncat(buf, addr->host, maxlen+1-1-strlen(buf));
451 buf[maxlen] = '\0';