Add support for tab-completion when selecting by rule
[alpine.git] / pith / addrstring.c
blob783dcb7cf0edf1acf20d398018e80de81edf4c0a
1 /*
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"
24 * Internal prototypes
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)
38 char *
39 addr_string(struct mail_address *addr, char *buf, size_t buflen)
41 ADDRESS *next_addr;
42 RFC822BUFFER rbuf;
44 *buf = '\0';
45 next_addr = addr->next;
46 addr->next = NULL;
47 rbuf.f = dummy_soutr;
48 rbuf.s = NULL;
49 rbuf.beg = buf;
50 rbuf.cur = buf;
51 rbuf.end = buf+buflen-1;
52 rfc822_output_address_list(&rbuf, addr, 0L, NULL);
53 *rbuf.cur = '\0';
54 addr->next = next_addr;
55 return(buf);
60 * Same as addr_string only it doesn't have to be a
61 * single address.
63 char *
64 addr_string_mult(struct mail_address *addr, char *buf, size_t buflen)
66 RFC822BUFFER rbuf;
68 *buf = '\0';
69 rbuf.f = dummy_soutr;
70 rbuf.s = NULL;
71 rbuf.beg = buf;
72 rbuf.cur = buf;
73 rbuf.end = buf+buflen-1;
74 rfc822_output_address_list(&rbuf, addr, 0L, NULL);
75 *rbuf.cur = '\0';
76 return(buf);
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;
88 char *
89 simple_addr_string(struct mail_address *addr, char *buf, size_t buflen)
91 RFC822BUFFER rbuf;
93 rbuf.f = dummy_soutr;
94 rbuf.s = NULL;
95 rbuf.beg = buf;
96 rbuf.cur = buf;
97 rbuf.end = buf+buflen-1;
98 rfc822_output_address(&rbuf, addr);
99 *rbuf.cur = '\0';
101 return(buf);
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.
117 char *
118 simple_mult_addr_string(struct mail_address *addr, char *buf, size_t buflen, char *sep)
120 ADDRESS *a;
121 char *dest = buf;
122 size_t seplen = 0;
124 if(sep)
125 seplen = strlen(sep);
127 *dest = '\0';
128 for(a = addr; a; a = a->next){
129 if(dest > buf && seplen > 0 && buflen-1-(dest-buf) >= seplen){
130 strncpy(dest, sep, seplen);
131 dest += seplen;
132 *dest = '\0';
135 simple_addr_string(a, dest, buflen-(dest-buf));
136 dest += strlen(dest);
139 buf[buflen-1] = '\0';
141 return(buf);
146 * 1522 encode the personal name portion of addr and return an allocated
147 * copy of the resulting address string.
149 char *
150 encode_fullname_of_addrstring(char *addr, char *charset)
152 char *pers_encoded,
153 *tmp_a_string,
154 *ret = NULL;
155 ADDRESS *adr;
156 static char *fakedomain = "@";
157 RFC822BUFFER rbuf;
158 size_t len;
160 tmp_a_string = cpystr(addr ? addr : "");
161 adr = NULL;
162 rfc822_parse_adrlist(&adr, tmp_a_string, fakedomain);
163 fs_give((void **)&tmp_a_string);
165 if(!adr)
166 return(cpystr(""));
168 if(adr->personal && adr->personal[0]){
169 pers_encoded = cpystr(rfc1522_encode(tmp_20k_buf, SIZEOF_20KBUF,
170 (unsigned char *)adr->personal,
171 charset));
172 fs_give((void **)&adr->personal);
173 adr->personal = pers_encoded;
176 len = est_size(adr);
177 ret = (char *) fs_get(len * sizeof(char));
178 ret[0] = '\0';
179 rbuf.f = dummy_soutr;
180 rbuf.s = NULL;
181 rbuf.beg = ret;
182 rbuf.cur = ret;
183 rbuf.end = ret+len-1;
184 rfc822_output_address_list(&rbuf, adr, 0L, NULL);
185 *rbuf.cur = '\0';
186 mail_free_address(&adr);
187 return(ret);
192 * 1522 decode the personal name portion of addr and return an allocated
193 * copy of the resulting address string.
195 char *
196 decode_fullname_of_addrstring(char *addr, int verbose)
198 char *pers_decoded,
199 *tmp_a_string,
200 *ret = NULL;
201 ADDRESS *adr;
202 static char *fakedomain = "@";
203 RFC822BUFFER rbuf;
204 size_t len;
206 tmp_a_string = cpystr(addr ? addr : "");
207 adr = NULL;
208 rfc822_parse_adrlist(&adr, tmp_a_string, fakedomain);
209 fs_give((void **)&tmp_a_string);
211 if(!adr)
212 return(cpystr(""));
214 if(adr->personal && adr->personal[0]){
215 pers_decoded
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;
222 len = est_size(adr);
223 ret = (char *) fs_get(len * sizeof(char));
224 ret[0] = '\0';
225 rbuf.f = dummy_soutr;
226 rbuf.s = NULL;
227 rbuf.beg = ret;
228 rbuf.cur = ret;
229 rbuf.end = ret+len-1;
230 rfc822_output_address_list(&rbuf, adr, 0L, NULL);
231 *rbuf.cur = '\0';
232 mail_free_address(&adr);
233 return(ret);
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)
248 char *
249 addr_list_string(struct mail_address *adrlist,
250 char *(*f)(struct mail_address *, char *, size_t),
251 int do_quote)
253 size_t len;
254 char *list, *s, string[MAX_ADDR_EXPN+1];
255 register ADDRESS *a;
257 if(!adrlist)
258 return(cpystr(""));
260 if(f){
261 len = 0;
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));
266 s = list;
267 s[0] = '\0';
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){
272 *s++ = ',';
273 *s++ = SPACE;
277 else{
278 len = est_size(adrlist);
279 list = (char *) fs_get((len+1) * sizeof(char));
280 list[0] = '\0';
281 rfc822_write_address_decode(list, len+1, adrlist, do_quote);
282 removing_leading_and_trailing_white_space(list);
285 list[len] = '\0';
286 return(list);
290 static long rfc822_dummy_soutr (void *stream, char *string)
292 return LONGT;
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.
309 void
310 rfc822_write_address_decode(char *dest, size_t destlen, struct mail_address *adr, int do_quote)
312 RFC822BUFFER buf;
313 extern const char *rspecials;
314 ADDRESS *copy, *a;
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){
326 unsigned char *p;
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? */
338 unsigned char *p;
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;
351 *buf.cur = '\0';
352 buf.s = NIL;
354 (void) rfc822_output_address_list(&buf, copy, 0,
355 do_quote ? rspecials : rspecials_minus_quote_and_dot);
357 *buf.cur = '\0';
359 if(copy)
360 mail_free_address(&copy);
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)
375 int cnt = 0;
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);
386 * add room for:
387 * possible single space between fullname and addr
388 * left and right brackets
389 * @ sign
390 * possible : for route addr
391 * , <space>
393 * So I really think that adding 7 is enough. Instead, I'll add 10.
395 cnt += 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)
408 int cnt = 0;
410 while(adrlist){
411 if(adrlist->mailbox && adrlist->mailbox[0])
412 cnt++;
414 adrlist = adrlist->next;
417 return(cnt);
422 * Buf is at least size maxlen+1
424 void
425 a_little_addr_string(struct mail_address *addr, char *buf, size_t maxlen)
427 buf[0] = '\0';
428 if(addr){
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,
434 SIZEOF_20KBUF, tmp),
435 maxlen);
437 else if(addr->mailbox && addr->mailbox[0]){
438 strncpy(buf, addr->mailbox, maxlen);
439 buf[maxlen] = '\0';
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));
447 buf[maxlen] = '\0';