* clear out some warnings by gcc 9.3.1.
[alpine.git] / pith / ablookup.c
blob7ccbd51941b1406bec06e4132bb7b2858cd9e4c3
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: ablookup.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2013-2020 Eduardo Chappa
8 * Copyright 2006-2009 University of Washington
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" /* for os-dep and pith defs/includes */
20 #include "../pith/debug.h"
21 #include "../pith/util.h"
22 #include "../pith/adrbklib.h"
23 #include "../pith/copyaddr.h"
24 #include "../pith/status.h"
25 #include "../pith/conf.h"
26 #include "../pith/search.h"
27 #include "../pith/abdlc.h"
28 #include "../pith/addrstring.h"
29 #include "../pith/ablookup.h"
30 #include "../pith/options.h"
31 #include "../pith/takeaddr.h"
32 #ifdef ENABLE_LDAP
33 #include "../pith/ldap.h"
34 #endif /* ENABLE_LDAP */
38 * Internal prototypes
40 int addr_is_in_addrbook(PerAddrBook *, ADDRESS *);
41 ABOOK_ENTRY_S *adrbk_list_of_possible_trie_completions(AdrBk_Trie *, AdrBk *, char *, unsigned);
42 void gather_abook_entry_list(AdrBk *, AdrBk_Trie *, char *, ABOOK_ENTRY_S **, unsigned);
43 void add_addr_to_return_list(ADDRESS *, unsigned, char *, int, COMPLETE_S **);
47 * Given an address, try to find the first nickname that goes with it.
48 * Copies that nickname into the passed in buffer, which is assumed to
49 * be at least MAX_NICKNAME+1 in length. Returns NULL if it can't be found,
50 * else it returns a pointer to the buffer.
52 char *
53 get_nickname_from_addr(struct mail_address *adr, char *buffer, size_t buflen)
55 AdrBk_Entry *abe;
56 char *ret = NULL;
57 SAVE_STATE_S state;
58 jmp_buf save_jmp_buf;
59 int *save_nesting_level;
60 ADDRESS *copied_adr;
62 state.savep = NULL;
63 state.stp = NULL;
64 state.dlc_to_warp_to = NULL;
65 copied_adr = copyaddr(adr);
67 if(ps_global->remote_abook_validity > 0)
68 (void)adrbk_check_and_fix_all(ab_nesting_level == 0, 0, 0);
70 save_nesting_level = cpyint(ab_nesting_level);
71 memcpy(save_jmp_buf, addrbook_changed_unexpectedly, sizeof(jmp_buf));
72 if(setjmp(addrbook_changed_unexpectedly)){
73 ret = NULL;
74 if(state.savep)
75 fs_give((void **)&(state.savep));
76 if(state.stp)
77 fs_give((void **)&(state.stp));
78 if(state.dlc_to_warp_to)
79 fs_give((void **)&(state.dlc_to_warp_to));
81 q_status_message(SM_ORDER, 3, 5, _("Resetting address book..."));
82 dprint((1,
83 "RESETTING address book... get_nickname_from_addr()!\n"));
84 addrbook_reset();
85 ab_nesting_level = *save_nesting_level;
88 ab_nesting_level++;
89 init_ab_if_needed();
91 if(pith_opt_save_and_restore)
92 (*pith_opt_save_and_restore)(SAR_SAVE, &state);
94 abe = address_to_abe(copied_adr);
96 if(copied_adr)
97 mail_free_address(&copied_adr);
99 if(abe && abe->nickname && abe->nickname[0]){
100 strncpy(buffer, abe->nickname, buflen-1);
101 buffer[buflen-1] = '\0';
102 ret = buffer;
105 if(pith_opt_save_and_restore)
106 (*pith_opt_save_and_restore)(SAR_RESTORE, &state);
108 memcpy(addrbook_changed_unexpectedly, save_jmp_buf, sizeof(jmp_buf));
109 ab_nesting_level--;
111 if(save_nesting_level)
112 fs_give((void **)&save_nesting_level);
114 return(ret);
119 * Given an address, try to find the first fcc that goes with it.
120 * Copies that fcc into the passed in buffer.
121 * Returns NULL if it can't be found, else it returns a pointer to the buffer.
123 char *
124 get_fcc_from_addr(struct mail_address *adr, char *buffer, size_t buflen)
126 AdrBk_Entry *abe;
127 char *ret = NULL;
128 SAVE_STATE_S state;
129 jmp_buf save_jmp_buf;
130 int *save_nesting_level;
131 ADDRESS *copied_adr;
133 state.savep = NULL;
134 state.stp = NULL;
135 state.dlc_to_warp_to = NULL;
136 copied_adr = copyaddr(adr);
138 if(ps_global->remote_abook_validity > 0)
139 (void)adrbk_check_and_fix_all(ab_nesting_level == 0, 0, 0);
141 save_nesting_level = cpyint(ab_nesting_level);
142 memcpy(save_jmp_buf, addrbook_changed_unexpectedly, sizeof(jmp_buf));
143 if(setjmp(addrbook_changed_unexpectedly)){
144 ret = NULL;
145 if(state.savep)
146 fs_give((void **)&(state.savep));
147 if(state.stp)
148 fs_give((void **)&(state.stp));
149 if(state.dlc_to_warp_to)
150 fs_give((void **)&(state.dlc_to_warp_to));
152 q_status_message(SM_ORDER, 3, 5, _("Resetting address book..."));
153 dprint((1,
154 "RESETTING address book... get_fcc_from_addr()!\n"));
155 addrbook_reset();
156 ab_nesting_level = *save_nesting_level;
159 ab_nesting_level++;
160 init_ab_if_needed();
162 if(pith_opt_save_and_restore)
163 (*pith_opt_save_and_restore)(SAR_SAVE, &state);
165 abe = address_to_abe(copied_adr);
167 if(copied_adr)
168 mail_free_address(&copied_adr);
170 if(abe && abe->fcc && abe->fcc[0]){
171 if(!strcmp(abe->fcc, "\"\""))
172 buffer[0] = '\0';
173 else{
174 strncpy(buffer, abe->fcc, buflen-1);
175 buffer[buflen-1] = '\0';
178 ret = buffer;
181 if(pith_opt_save_and_restore)
182 (*pith_opt_save_and_restore)(SAR_RESTORE, &state);
184 memcpy(addrbook_changed_unexpectedly, save_jmp_buf, sizeof(jmp_buf));
185 ab_nesting_level--;
187 if(save_nesting_level)
188 fs_give((void **)&save_nesting_level);
190 return(ret);
195 * Given an address, try to find the first address book entry that
196 * matches it and return all the other fields in the passed in pointers.
197 * Caller needs to free the four fields.
198 * Returns -1 if it can't be found, 0 if it is found.
201 get_contactinfo_from_addr(struct mail_address *adr, char **nick, char **full, char **fcc, char **comment)
203 AdrBk_Entry *abe;
204 int ret = -1;
205 SAVE_STATE_S state;
206 jmp_buf save_jmp_buf;
207 int *save_nesting_level;
208 ADDRESS *copied_adr;
210 state.savep = NULL;
211 state.stp = NULL;
212 state.dlc_to_warp_to = NULL;
213 copied_adr = copyaddr(adr);
215 if(ps_global->remote_abook_validity > 0)
216 (void)adrbk_check_and_fix_all(ab_nesting_level == 0, 0, 0);
218 save_nesting_level = cpyint(ab_nesting_level);
219 memcpy(save_jmp_buf, addrbook_changed_unexpectedly, sizeof(jmp_buf));
220 if(setjmp(addrbook_changed_unexpectedly)){
221 ret = -1;
222 if(state.savep)
223 fs_give((void **)&(state.savep));
224 if(state.stp)
225 fs_give((void **)&(state.stp));
226 if(state.dlc_to_warp_to)
227 fs_give((void **)&(state.dlc_to_warp_to));
229 q_status_message(SM_ORDER, 3, 5, _("Resetting address book..."));
230 dprint((1,
231 "RESETTING address book... get_contactinfo_from_addr()!\n"));
232 addrbook_reset();
233 ab_nesting_level = *save_nesting_level;
236 ab_nesting_level++;
237 init_ab_if_needed();
239 if(pith_opt_save_and_restore)
240 (*pith_opt_save_and_restore)(SAR_SAVE, &state);
242 abe = address_to_abe(copied_adr);
244 if(copied_adr)
245 mail_free_address(&copied_adr);
247 if(abe){
248 if(nick && abe->nickname && abe->nickname[0])
249 *nick = cpystr(abe->nickname);
251 if(full && abe->fullname && abe->fullname[0])
252 *full = cpystr(abe->fullname);
254 if(fcc && abe->fcc && abe->fcc[0])
255 *fcc = cpystr(abe->fcc);
257 if(comment && abe->extra && abe->extra[0])
258 *comment = cpystr(abe->extra);
260 ret = 0;
263 if(pith_opt_save_and_restore)
264 (*pith_opt_save_and_restore)(SAR_RESTORE, &state);
266 memcpy(addrbook_changed_unexpectedly, save_jmp_buf, sizeof(jmp_buf));
267 ab_nesting_level--;
269 if(save_nesting_level)
270 fs_give((void **)&save_nesting_level);
272 return(ret);
277 * This is a very special-purpose routine.
278 * It implements the From or Reply-To address is in the Address Book
279 * part of Pattern matching.
281 void
282 address_in_abook(MAILSTREAM *stream, SEARCHSET *searchset,
283 int inabook, PATTERN_S *abooks)
285 char *savebits;
286 MESSAGECACHE *mc;
287 long i, count = 0L;
288 SEARCHSET *s, *ss;
289 ADDRESS *from, *reply_to, *sender, *to, *cc;
290 int is_there, adrbknum, *abooklist = NULL, positive_match;
291 PATTERN_S *pat;
292 PerAddrBook *pab;
293 ENVELOPE *e;
294 SAVE_STATE_S state;
295 jmp_buf save_jmp_buf;
296 int *save_nesting_level;
298 if(!stream)
299 return;
301 /* everything that matches remains a match */
302 if(inabook == IAB_EITHER)
303 return;
305 state.savep = NULL;
306 state.stp = NULL;
307 state.dlc_to_warp_to = NULL;
310 * This may call build_header_line recursively because we may be in
311 * build_header_line now. So we have to preserve and restore the
312 * sequence bits since we want to use them here.
314 savebits = (char *) fs_get((stream->nmsgs+1) * sizeof(char));
316 for(i = 1L; i <= stream->nmsgs; i++){
317 if((mc = mail_elt(stream, i)) != NULL){
318 savebits[i] = mc->sequence;
319 mc->sequence = 0;
324 * Build a searchset so we can look at all the envelopes
325 * we need to look at but only those we need to look at.
326 * Everything with the searched bit set is still a
327 * possibility, so restrict to that set.
330 for(s = searchset; s; s = s->next)
331 for(i = s->first; i <= s->last; i++)
332 if(i > 0L && i <= stream->nmsgs
333 && (mc=mail_elt(stream, i)) && mc->searched){
334 mc->sequence = 1;
335 count++;
338 ss = build_searchset(stream);
341 * We save the address book state here so we don't have to do it
342 * each time through the loop below.
344 if(ss){
345 if(ps_global->remote_abook_validity > 0)
346 (void)adrbk_check_and_fix_all(ab_nesting_level == 0, 0, 0);
348 save_nesting_level = cpyint(ab_nesting_level);
349 memcpy(save_jmp_buf, addrbook_changed_unexpectedly, sizeof(jmp_buf));
350 if(setjmp(addrbook_changed_unexpectedly)){
351 if(state.savep)
352 fs_give((void **)&(state.savep));
353 if(state.stp)
354 fs_give((void **)&(state.stp));
355 if(state.dlc_to_warp_to)
356 fs_give((void **)&(state.dlc_to_warp_to));
358 q_status_message(SM_ORDER, 3, 5, _("Resetting address book..."));
359 dprint((1,
360 "RESETTING address book... address_in_abook()!\n"));
361 addrbook_reset();
362 ab_nesting_level = *save_nesting_level;
365 ab_nesting_level++;
366 init_ab_if_needed();
368 if(pith_opt_save_and_restore)
369 (*pith_opt_save_and_restore)(SAR_SAVE, &state);
371 if(as.n_addrbk > 0){
372 abooklist = (int *) fs_get(as.n_addrbk * sizeof(*abooklist));
373 memset((void *) abooklist, 0, as.n_addrbk * sizeof(*abooklist));
376 if(abooklist)
377 switch(inabook & IAB_TYPE_MASK){
378 case IAB_YES:
379 case IAB_NO:
380 for(adrbknum = 0; adrbknum < as.n_addrbk; adrbknum++)
381 abooklist[adrbknum] = 1;
383 break;
385 case IAB_SPEC_YES:
386 case IAB_SPEC_NO:
387 /* figure out which address books we're going to look in */
388 for(adrbknum = 0; adrbknum < as.n_addrbk; adrbknum++){
389 pab = &as.adrbks[adrbknum];
391 * For each address book, check all of the address books
392 * in the pattern's list to see if they are it.
394 for(pat = abooks; pat; pat = pat->next){
395 if(!strcmp(pab->abnick, pat->substring)
396 || !strcmp(pab->filename, pat->substring)){
397 abooklist[adrbknum] = 1;
398 break;
403 break;
406 switch(inabook & IAB_TYPE_MASK){
407 case IAB_YES:
408 case IAB_SPEC_YES:
409 positive_match = 1;
410 break;
412 case IAB_NO:
413 case IAB_SPEC_NO:
414 positive_match = 0;
415 break;
419 if(count){
420 SEARCHSET **sset;
422 mail_parameters(NULL, SET_FETCHLOOKAHEADLIMIT, (void *) count);
425 * This causes the lookahead to fetch precisely
426 * the messages we want (in the searchset) instead
427 * of just fetching the next 20 sequential
428 * messages. If the searching so far has caused
429 * a sparse searchset in a large mailbox, the
430 * difference can be substantial.
431 * This resets automatically after the first fetch.
433 sset = (SEARCHSET **) mail_parameters(stream,
434 GET_FETCHLOOKAHEAD,
435 (void *) stream);
436 if(sset)
437 *sset = ss;
440 for(s = ss; s; s = s->next){
441 for(i = s->first; i <= s->last; i++){
442 if(i <= 0L || i > stream->nmsgs)
443 continue;
445 e = pine_mail_fetchenvelope(stream, i);
447 from = e ? e->from : NULL;
448 reply_to = e ? e->reply_to : NULL;
449 sender = e ? e->sender : NULL;
450 to = e ? e->to : NULL;
451 cc = e ? e->cc : NULL;
453 is_there = 0;
454 for(adrbknum = 0; !is_there && adrbknum < as.n_addrbk; adrbknum++){
455 if(!abooklist[adrbknum])
456 continue;
458 pab = &as.adrbks[adrbknum];
459 is_there = ((inabook & IAB_FROM) && addr_is_in_addrbook(pab, from))
460 || ((inabook & IAB_REPLYTO) && addr_is_in_addrbook(pab, reply_to))
461 || ((inabook & IAB_SENDER) && addr_is_in_addrbook(pab, sender))
462 || ((inabook & IAB_TO) && addr_is_in_addrbook(pab, to))
463 || ((inabook & IAB_CC) && addr_is_in_addrbook(pab, cc));
466 if(positive_match){
468 * We matched up until now. If it isn't there, then it
469 * isn't a match. If it is there, leave the searched bit
470 * set.
472 if(!is_there && i > 0L && i <= stream->nmsgs && (mc = mail_elt(stream, i)))
473 mc->searched = NIL;
475 else{
476 if(is_there && i > 0L && i <= stream->nmsgs && (mc = mail_elt(stream, i)))
477 mc->searched = NIL;
482 if(ss){
483 if(pith_opt_save_and_restore)
484 (*pith_opt_save_and_restore)(SAR_RESTORE, &state);
486 memcpy(addrbook_changed_unexpectedly, save_jmp_buf, sizeof(jmp_buf));
487 ab_nesting_level--;
489 if(save_nesting_level)
490 fs_give((void **)&save_nesting_level);
493 /* restore sequence bits */
494 for(i = 1L; i <= stream->nmsgs; i++)
495 if((mc = mail_elt(stream, i)) != NULL)
496 mc->sequence = savebits[i];
498 fs_give((void **) &savebits);
500 if(ss)
501 mail_free_searchset(&ss);
503 if(abooklist)
504 fs_give((void **) &abooklist);
509 * Given two addresses, check to see if either is in the address book.
510 * Returns 1 if yes, 0 if not found.
513 addr_is_in_addrbook(PerAddrBook *pab, struct mail_address *addr)
515 AdrBk_Entry *abe = NULL;
516 int ret = 0;
517 char abuf[MAX_ADDR_FIELD+1];
519 if(!(pab && addr && addr->mailbox))
520 return(ret);
522 if(addr){
523 strncpy(abuf, addr->mailbox, sizeof(abuf)-1);
524 abuf[sizeof(abuf)-1] = '\0';
525 if(addr->host && addr->host[0]){
526 strncat(abuf, "@", sizeof(abuf)-strlen(abuf)-1);
527 strncat(abuf, addr->host, sizeof(abuf)-strlen(abuf)-1);
530 if(pab->ostatus != Open && pab->ostatus != NoDisplay)
531 init_abook(pab, NoDisplay);
533 abe = adrbk_lookup_by_addr(pab->address_book, abuf,
534 (adrbk_cntr_t *) NULL);
537 ret = abe ? 1 : 0;
539 return(ret);
544 * Look through addrbooks for nickname, opening addrbooks first
545 * if necessary. It is assumed that the caller will restore the
546 * state of the addrbooks if desired.
548 * Args: nickname -- the nickname to lookup
549 * clearrefs -- clear reference bits before lookup
550 * which_addrbook -- If matched, addrbook number it was found in.
551 * not_here -- If non-negative, skip looking in this abook.
553 * Results: A pointer to an AdrBk_Entry is returned, or NULL if not found.
554 * Stop at first match (so order of addrbooks is important).
556 AdrBk_Entry *
557 adrbk_lookup_with_opens_by_nick(char *nickname, int clearrefs, int *which_addrbook, int not_here)
559 AdrBk_Entry *abe = (AdrBk_Entry *)NULL;
560 int i;
561 PerAddrBook *pab;
563 dprint((5, "- adrbk_lookup_with_opens_by_nick(%s) -\n",
564 nickname ? nickname : "?"));
566 for(i = 0; i < as.n_addrbk; i++){
568 if(i == not_here)
569 continue;
571 pab = &as.adrbks[i];
573 if(pab->ostatus != Open && pab->ostatus != NoDisplay)
574 init_abook(pab, NoDisplay);
576 if(clearrefs)
577 adrbk_clearrefs(pab->address_book);
579 abe = adrbk_lookup_by_nick(pab->address_book,
580 nickname,
581 (adrbk_cntr_t *)NULL);
582 if(abe)
583 break;
586 if(abe && which_addrbook)
587 *which_addrbook = i;
589 return(abe);
594 * Find the addressbook entry that matches the argument address.
595 * Searches through all addressbooks looking for the match.
596 * Opens addressbooks if necessary. It is assumed that the caller
597 * will restore the state of the addrbooks if desired.
599 * Args: addr -- the address we're trying to match
601 * Returns: NULL -- no match found
602 * abe -- a pointer to the addrbook entry that matches
604 AdrBk_Entry *
605 address_to_abe(struct mail_address *addr)
607 register PerAddrBook *pab;
608 int adrbk_number;
609 AdrBk_Entry *abe = NULL;
610 char *abuf = NULL;
612 if(!(addr && addr->mailbox))
613 return (AdrBk_Entry *)NULL;
615 abuf = (char *)fs_get((MAX_ADDR_FIELD + 1) * sizeof(char));
617 strncpy(abuf, addr->mailbox, MAX_ADDR_FIELD);
618 abuf[MAX_ADDR_FIELD] = '\0';
619 if(addr->host && addr->host[0]){
620 strncat(abuf, "@", MAX_ADDR_FIELD+1-1-strlen(abuf));
621 strncat(abuf, addr->host, MAX_ADDR_FIELD+1-1-strlen(abuf));
624 /* for each addressbook */
625 for(adrbk_number = 0; adrbk_number < as.n_addrbk; adrbk_number++){
627 pab = &as.adrbks[adrbk_number];
629 if(pab->ostatus != Open && pab->ostatus != NoDisplay)
630 init_abook(pab, NoDisplay);
632 abe = adrbk_lookup_by_addr(pab->address_book,
633 abuf,
634 (adrbk_cntr_t *)NULL);
635 if(abe)
636 break;
639 if(abuf)
640 fs_give((void **)&abuf);
642 return(abe);
647 * Turn an AdrBk_Entry into an address list
649 * Args: abe -- the AdrBk_Entry
650 * dl -- the corresponding dl
651 * abook -- which addrbook the abe is in (only used for type ListEnt)
652 * how_many -- The number of addresses is returned here
654 * Result: allocated address list or NULL
656 ADDRESS *
657 abe_to_address(AdrBk_Entry *abe, AddrScrn_Disp *dl, AdrBk *abook, int *how_many)
659 char *fullname, *tmp_a_string;
660 char *list, *l1, **l2;
661 char *fakedomain = "@";
662 ADDRESS *addr = NULL;
663 size_t length;
664 int count = 0;
666 if(!dl || !abe)
667 return(NULL);
669 fullname = (abe->fullname && abe->fullname[0]) ? abe->fullname : NULL;
671 switch(dl->type){
672 case Simple:
673 /* rfc822_parse_adrlist feels free to destroy input so send copy */
674 tmp_a_string = cpystr(abe->addr.addr);
675 rfc822_parse_adrlist(&addr, tmp_a_string, fakedomain);
677 if(tmp_a_string)
678 fs_give((void **)&tmp_a_string);
680 if(addr && fullname){
681 #ifdef ENABLE_LDAP
682 if(strncmp(addr->mailbox, RUN_LDAP, LEN_RL) != 0)
683 #endif /* ENABLE_LDAP */
685 if(addr->personal)
686 fs_give((void **)&addr->personal);
688 addr->personal = adrbk_formatname(fullname, NULL, NULL);
692 if(addr)
693 count++;
695 break;
697 case ListEnt:
698 /* rfc822_parse_adrlist feels free to destroy input so send copy */
699 tmp_a_string = cpystr(listmem_from_dl(abook, dl));
700 rfc822_parse_adrlist(&addr, tmp_a_string, fakedomain);
701 if(tmp_a_string)
702 fs_give((void **)&tmp_a_string);
704 if(addr)
705 count++;
707 break;
709 case ListHead:
710 length = 0;
711 for(l2 = abe->addr.list; *l2; l2++)
712 length += (strlen(*l2) + 1);
714 list = (char *)fs_get(length + 1);
715 l1 = list;
716 for(l2 = abe->addr.list; *l2; l2++){
717 if(l1 != list && length-(l1-list) > 0)
718 *l1++ = ',';
720 strncpy(l1, *l2, length-(l1-list));
721 list[length] = '\0';
722 l1 += strlen(l1);
723 count++;
726 rfc822_parse_adrlist(&addr, list, fakedomain);
727 if(list)
728 fs_give((void **)&list);
730 break;
732 default:
733 dprint((1, "default case in abe_to_address, shouldn't happen\n"));
734 break;
737 if(how_many)
738 *how_many = count;
740 return(addr);
745 * Turn an AdrBk_Entry into a nickname (if it has a nickname) or a
746 * formatted addr_string which has been rfc1522 decoded.
748 * Args: abe -- the AdrBk_Entry
749 * dl -- the corresponding dl
750 * abook -- which addrbook the abe is in (only used for type ListEnt)
752 * Result: allocated string is returned
754 char *
755 abe_to_nick_or_addr_string(AdrBk_Entry *abe, AddrScrn_Disp *dl, int abook_num)
757 ADDRESS *addr;
758 char *a_string;
760 if(!dl || !abe)
761 return(cpystr(""));
763 if((dl->type == Simple || dl->type == ListHead)
764 && abe->nickname && abe->nickname[0]){
765 char *fname;
766 int which_addrbook;
769 * We prefer to pass back the nickname since that allows the
770 * caller to keep track of which entry the address came from.
771 * This is useful in build_address so that the fcc line can
772 * be kept correct. However, if the nickname is also present in
773 * another addressbook then we have to be careful. If that other
774 * addressbook comes before this one then passing back the nickname
775 * will cause the wrong entry to get used. So check for that
776 * and pass back the addr_string in that case.
778 if((fname = addr_lookup(abe->nickname, &which_addrbook, abook_num)) != NULL){
779 fs_give((void **)&fname);
780 if(which_addrbook >= abook_num)
781 return(cpystr(abe->nickname));
783 else
784 return(cpystr(abe->nickname));
787 addr = abe_to_address(abe, dl, as.adrbks[abook_num].address_book, NULL);
788 a_string = addr_list_string(addr, NULL, 0); /* always returns a string */
789 if(addr)
790 mail_free_address(&addr);
792 return(a_string);
797 * Check to see if address is that of the current user running pine
799 * Args: a -- Address to check
800 * ps -- The pine_state structure
802 * Result: returns 1 if it matches, 0 otherwise.
804 * The mailbox must match the user name and the hostname must match.
805 * In matching the hostname, matches occur if the hostname in the address
806 * is blank, or if it matches the local hostname, or the full hostname
807 * with qualifying domain, or the qualifying domain without a specific host.
808 * Note, there is a very small chance that we will err on the
809 * non-conservative side here. That is, we may decide two addresses are
810 * the same even though they are different (because we do case-insensitive
811 * compares on the mailbox). That might cause a reply not to be sent to
812 * somebody because they look like they are us. This should be very,
813 * very rare.
815 * It is also considered a match if any of the addresses in alt-addresses
816 * matches a. The check there is simpler. It parses each address in
817 * the list, adding maildomain if there wasn't a domain, and compares
818 * mailbox and host in the ADDRESS's for equality.
821 address_is_us(struct mail_address *a, struct pine *ps)
823 char **t;
824 int ret;
825 char addrstr[500];
827 if(!a || a->mailbox == NULL || !ps)
828 ret = 0;
830 /* at least LHS must match, but case-independent */
831 else if(strucmp(a->mailbox, ps->VAR_USER_ID) == 0
833 && /* and hostname matches */
835 /* hostname matches if it's not there, */
836 (a->host == NULL ||
837 /* or if hostname and userdomain (the one user sets) match exactly, */
838 ((ps->userdomain && a->host && strucmp(a->host,ps->userdomain) == 0) ||
841 * or if(userdomain is either not set or it is set to be
842 * the same as the localdomain or hostname) and (the hostname
843 * of the address matches either localdomain or hostname)
845 ((ps->userdomain == NULL ||
846 strucmp(ps->userdomain, ps->localdomain) == 0 ||
847 strucmp(ps->userdomain, ps->hostname) == 0) &&
848 (strucmp(a->host, ps->hostname) == 0 ||
849 strucmp(a->host, ps->localdomain) == 0)))))
850 ret = 1;
853 * If no match yet, check to see if it matches any of the alternate
854 * addresses the user has specified.
856 else if(!ps_global->VAR_ALT_ADDRS ||
857 !ps_global->VAR_ALT_ADDRS[0] ||
858 !ps_global->VAR_ALT_ADDRS[0][0])
859 ret = 0; /* none defined */
861 else{
862 ret = 0;
863 if(a && a->host && a->mailbox)
864 snprintf(addrstr, sizeof(addrstr), "%s@%s", a->mailbox, a->host);
865 else
866 addrstr[0] = '\0';
868 for(t = ps_global->VAR_ALT_ADDRS; !ret && t[0] && t[0][0]; t++){
869 char *alt;
870 regex_t reg;
871 int err;
872 char ebuf[200];
874 alt = (*t);
876 if(F_ON(F_DISABLE_REGEX, ps_global) || !contains_regex_special_chars(alt)){
877 ADDRESS *alt_addr;
878 char *alt2;
880 alt2 = cpystr(alt);
881 alt_addr = NULL;
882 rfc822_parse_adrlist(&alt_addr, alt2, ps_global->maildomain);
883 if(alt2)
884 fs_give((void **) &alt2);
886 if(address_is_same(a, alt_addr))
887 ret = 1;
889 if(alt_addr)
890 mail_free_address(&alt_addr);
892 else{
893 /* treat alt as a regular expression */
894 ebuf[0] = '\0';
895 if(!(err=regcomp(&reg, alt, REG_ICASE | REG_NOSUB | REG_EXTENDED))){
896 err = regexec(&reg, addrstr, 0, NULL, 0);
897 if(err == 0)
898 ret = 1;
899 else if(err != REG_NOMATCH){
900 regerror(err, &reg, ebuf, sizeof(ebuf));
901 if(ebuf[0])
902 dprint((2, "- address_is_us regexec error: %s (%s)", ebuf, alt));
905 regfree(&reg);
907 else{
908 regerror(err, &reg, ebuf, sizeof(ebuf));
909 if(ebuf[0])
910 dprint((2, "- address_is_us regcomp error: %s (%s)", ebuf, alt));
916 return(ret);
921 * In an ad hoc way try to decide if str is meant to be a regular
922 * expression or not. Dot doesn't count * as regex stuff because
923 * we're worried about addresses.
925 * Returns 0 or 1
928 contains_regex_special_chars(char *str)
930 char special_chars[] = {'*', '|', '+', '?', '{', '[', '^', '$', '\\', '\0'};
931 char *c;
933 if(!str)
934 return 0;
937 * If any of special_chars are in str consider it a regex expression.
939 for(c = special_chars; *c; c++)
940 if(strindex(str, *c))
941 return 1;
943 return 0;
948 * Compare the two addresses, and return true if they're the same,
949 * false otherwise
951 * Args: a -- First address for comparison
952 * b -- Second address for comparison
954 * Result: returns 1 if it matches, 0 otherwise.
957 address_is_same(struct mail_address *a, struct mail_address *b)
959 return(a && b && a->mailbox && b->mailbox && a->host && b->host
960 && strucmp(a->mailbox, b->mailbox) == 0
961 && strucmp(a->host, b->host) == 0);
966 * Returns nonzero if the two address book entries are equal.
967 * Returns zero if not equal.
970 abes_are_equal(AdrBk_Entry *a, AdrBk_Entry *b)
972 int result = 0;
973 char **alist, **blist;
974 char *addra, *addrb;
976 if(a && b &&
977 a->tag == b->tag &&
978 ((!a->nickname && !b->nickname) ||
979 (a->nickname && b->nickname && strcmp(a->nickname,b->nickname) == 0)) &&
980 ((!a->fullname && !b->fullname) ||
981 (a->fullname && b->fullname && strcmp(a->fullname,b->fullname) == 0)) &&
982 ((!a->fcc && !b->fcc) ||
983 (a->fcc && b->fcc && strcmp(a->fcc,b->fcc) == 0)) &&
984 ((!a->extra && !b->extra) ||
985 (a->extra && b->extra && strcmp(a->extra,b->extra) == 0))){
987 /* If we made it in here, they still might be equal. */
988 if(a->tag == Single)
989 result = strcmp(a->addr.addr,b->addr.addr) == 0;
990 else{
991 alist = a->addr.list;
992 blist = b->addr.list;
993 if(!alist && !blist)
994 result = 1;
995 else{
996 /* compare the whole lists */
997 addra = *alist;
998 addrb = *blist;
999 while(addra && addrb && strcmp(addra,addrb) == 0){
1000 alist++;
1001 blist++;
1002 addra = *alist;
1003 addrb = *blist;
1006 if(!addra && !addrb)
1007 result = 1;
1012 return(result);
1017 * Interface to address book lookups for callers outside or inside this file.
1019 * Args: nickname -- The nickname to look up
1020 * which_addrbook -- If matched, addrbook number it was found in.
1021 * not_here -- If non-negative, skip looking in this abook.
1023 * Result: returns NULL or the corresponding fullname. The fullname is
1024 * allocated here so the caller must free it.
1026 * This opens the address books if they haven't been opened and restores
1027 * them to the state they were in upon entry.
1029 char *
1030 addr_lookup(char *nickname, int *which_addrbook, int not_here)
1032 AdrBk_Entry *abe;
1033 SAVE_STATE_S state;
1034 char *fullname;
1036 dprint((9, "- addr_lookup(%s) -\n",nickname ? nickname : "nil"));
1038 init_ab_if_needed();
1040 if(pith_opt_save_and_restore)
1041 (*pith_opt_save_and_restore)(SAR_SAVE, &state);
1043 abe = adrbk_lookup_with_opens_by_nick(nickname,0,which_addrbook,not_here);
1045 fullname = (abe && abe->fullname) ? cpystr(abe->fullname) : NULL;
1047 if(pith_opt_save_and_restore)
1048 (*pith_opt_save_and_restore)(SAR_RESTORE, &state);
1050 return(fullname);
1055 * Look in all of the address books for all of the possible entries
1056 * that match the query string. The matches can be for the nickname,
1057 * for the fullname, or for the address@host part of the address.
1058 * All of the matches are at the starts of the strings, not a general
1059 * substring match. This is not true anymore. Fullname matches can be
1060 * at the start of the fullname or starting after a space in the fullname.
1061 * If flags has ALC_INCLUDE_LDAP defined then LDAP
1062 * entries are added to the end of the list. The LDAP queries are done
1063 * only for those servers that have the 'impl' feature turned on, which
1064 * means that lookups should be done implicitly. This feature also
1065 * controls whether or not lookups should be done when typing carriage
1066 * return (instead of this which is TAB).
1068 * Args query -- What the user has typed so far
1070 * Returns a list of possibilities for the given query string.
1072 * Caller needs to free the answer.
1074 COMPLETE_S *
1075 adrbk_list_of_completions(char *query, MAILSTREAM *stream, imapuid_t uid, int flags)
1077 int i;
1078 SAVE_STATE_S state;
1079 PerAddrBook *pab;
1080 ABOOK_ENTRY_S *list, *list2, *biglist = NULL;
1081 COMPLETE_S *return_list = NULL, *last_one_added = NULL, *new, *cp, *dp, *dprev;
1082 BuildTo toaddr;
1083 ADDRESS *addr;
1084 char buf[1000];
1085 char *newaddr = NULL, *simple_addr = NULL, *fcc = NULL;
1086 ENVELOPE *env = NULL;
1087 BODY *body = NULL;
1089 init_ab_if_needed();
1091 if(pith_opt_save_and_restore)
1092 (*pith_opt_save_and_restore)(SAR_SAVE, &state);
1094 for(i = 0; i < as.n_addrbk; i++){
1096 pab = &as.adrbks[i];
1098 if(pab->ostatus != Open && pab->ostatus != NoDisplay)
1099 init_abook(pab, NoDisplay);
1101 list = adrbk_list_of_possible_completions(pab ? pab->address_book : NULL, query);
1102 combine_abook_entry_lists(&biglist, list);
1106 * Eliminate duplicates by NO_NEXTing the entrynums.
1108 for(list = biglist; list; list = list->next)
1109 /* eliminate any dups further along in the list */
1110 if(list->entrynum != NO_NEXT)
1111 for(list2 = list->next; list2; list2 = list2->next)
1112 if(list2->entrynum == list->entrynum){
1113 list2->entrynum = NO_NEXT;
1114 list->matches_bitmap |= list2->matches_bitmap;
1117 /* build the return list */
1118 for(list = biglist; list; list = list->next)
1119 if(list->entrynum != NO_NEXT){
1120 fcc = NULL;
1121 toaddr.type = Abe;
1122 toaddr.arg.abe = adrbk_get_ae(list->ab, list->entrynum);
1123 if(our_build_address(toaddr, &newaddr, NULL, &fcc, NULL) == 0){
1124 char *reverse_fullname = NULL;
1127 * ALC_FULL is a regular FullName match and that will be
1128 * captured in the full_address field. If there was also
1129 * an ALC_REVFULL match that means that the user has the
1130 * FullName entered in their addrbook as Last, First and
1131 * that is where the match was. We want to put that in
1132 * the completions structure in the rev_fullname field.
1134 if(list->matches_bitmap & ALC_REVFULL
1135 && toaddr.arg.abe
1136 && toaddr.arg.abe->fullname && toaddr.arg.abe->fullname[0]
1137 && toaddr.arg.abe->fullname[0] != '"'
1138 && strindex(toaddr.arg.abe->fullname, ',') != NULL){
1140 reverse_fullname = toaddr.arg.abe->fullname;
1143 if(flags & ALC_INCLUDE_ADDRS){
1144 if(toaddr.arg.abe && toaddr.arg.abe->tag == Single
1145 && toaddr.arg.abe->addr.addr && toaddr.arg.abe->addr.addr[0]){
1146 char *tmp_a_string;
1147 char *fakedomain = "@";
1149 tmp_a_string = cpystr(toaddr.arg.abe->addr.addr);
1150 addr = NULL;
1151 rfc822_parse_adrlist(&addr, tmp_a_string, fakedomain);
1152 if(tmp_a_string)
1153 fs_give((void **) &tmp_a_string);
1155 if(addr){
1156 if(addr->mailbox && addr->host
1157 && !(addr->host[0] == '@' && addr->host[1] == '\0'))
1158 simple_addr = simple_addr_string(addr, buf, sizeof(buf));
1160 mail_free_address(&addr);
1165 new = new_complete_s(toaddr.arg.abe ? toaddr.arg.abe->nickname : NULL,
1166 newaddr, simple_addr, reverse_fullname, fcc,
1167 list->matches_bitmap | ALC_ABOOK);
1169 /* add to end of list */
1170 if(return_list == NULL){
1171 return_list = new;
1172 last_one_added = new;
1174 else{
1175 last_one_added->next = new;
1176 last_one_added = new;
1180 if(newaddr)
1181 fs_give((void **) &newaddr);
1184 if(pith_opt_save_and_restore)
1185 (*pith_opt_save_and_restore)(SAR_RESTORE, &state);
1187 free_abook_entry_s(&biglist);
1189 #ifdef ENABLE_LDAP
1190 if(flags & ALC_INCLUDE_LDAP){
1191 LDAP_SERV_RES_S *head_of_result_list = NULL, *res;
1192 LDAP_CHOOSE_S cs;
1193 WP_ERR_S wp_err;
1194 LDAPMessage *e;
1196 memset(&wp_err, 0, sizeof(wp_err));
1199 * This lookup covers all servers with the impl bit set.
1200 * It uses the regular LDAP search parameters that the
1201 * user has set, not necessarily just a prefix match
1202 * like the rest of the address completion above.
1204 head_of_result_list = ldap_lookup_all_work(query, as.n_serv, 0, NULL, &wp_err);
1205 for(res = head_of_result_list; res; res = res->next){
1206 for(e = ldap_first_entry(res->ld, res->res);
1207 e != NULL;
1208 e = ldap_next_entry(res->ld, e)){
1209 simple_addr = newaddr = NULL;
1210 cs.ld = res->ld;
1211 cs.selected_entry = e;
1212 cs.info_used = res->info_used;
1213 cs.serv = res->serv;
1214 addr = address_from_ldap(&cs);
1215 if(addr){
1216 add_addr_to_return_list(addr, ALC_LDAP, query, flags, &return_list);
1217 mail_free_address(&addr);
1222 if(wp_err.error)
1223 fs_give((void **) &wp_err.error);
1225 if(head_of_result_list)
1226 free_ldap_result_list(&head_of_result_list);
1228 #endif /* ENABLE_LDAP */
1230 /* add from current message */
1231 if(uid > 0 && stream)
1232 env = pine_mail_fetch_structure(stream, uid, &body, FT_UID);
1234 /* from the envelope addresses */
1235 if(env){
1236 for(addr = env->from; addr; addr = addr->next)
1237 add_addr_to_return_list(addr, ALC_CURR, query, flags, &return_list);
1239 for(addr = env->reply_to; addr; addr = addr->next)
1240 add_addr_to_return_list(addr, ALC_CURR, query, flags, &return_list);
1242 for(addr = env->sender; addr; addr = addr->next)
1243 add_addr_to_return_list(addr, ALC_CURR, query, flags, &return_list);
1245 for(addr = env->to; addr; addr = addr->next)
1246 add_addr_to_return_list(addr, ALC_CURR, query, flags, &return_list);
1248 for(addr = env->cc; addr; addr = addr->next)
1249 add_addr_to_return_list(addr, ALC_CURR, query, flags, &return_list);
1252 * May as well search the body for addresses.
1253 * Use this function written for TakeAddr.
1255 if(body){
1256 TA_S *talist = NULL, *tp;
1258 if(grab_addrs_from_body(stream, mail_msgno(stream,uid), body, &talist) > 0){
1259 if(talist){
1261 /* rewind to start */
1262 while(talist->prev)
1263 talist = talist->prev;
1265 for(tp = talist; tp; tp = tp->next){
1266 addr = tp->addr;
1267 if(addr)
1268 add_addr_to_return_list(addr, ALC_CURR, query, flags, &return_list);
1271 free_talines(&talist);
1279 * Check for and eliminate some duplicates.
1280 * The criteria for deciding what is a duplicate is
1281 * kind of ad hoc.
1283 for(cp = return_list; cp; cp = cp->next)
1284 for(dprev = cp, dp = cp->next; dp; ){
1285 if(cp->full_address && dp->full_address
1286 && !strucmp(dp->full_address, cp->full_address)
1287 && (((cp->matches_bitmap & ALC_ABOOK)
1288 && (dp->matches_bitmap & ALC_ABOOK)
1289 && (!(dp->matches_bitmap & ALC_NICK && dp->nickname && dp->nickname[0])
1290 || ((!cp->addr && !dp->addr) || (cp->addr && dp->addr && !strucmp(cp->addr, dp->addr)))))
1292 (dp->matches_bitmap & ALC_CURR)
1294 (dp->matches_bitmap & ALC_LDAP
1295 && dp->matches_bitmap & (ALC_FULL | ALC_ADDR))
1297 (cp->matches_bitmap == dp->matches_bitmap
1298 && (!(dp->matches_bitmap & ALC_NICK && dp->nickname && dp->nickname[0])
1299 || (dp->nickname && cp->nickname
1300 && !strucmp(cp->nickname, dp->nickname)))))){
1302 * dp is equivalent to cp so eliminate dp
1304 dprev->next = dp->next;
1305 dp->next = NULL;
1306 free_complete_s(&dp);
1307 dp = dprev;
1310 dprev = dp;
1311 dp = dp->next;
1314 return(return_list);
1318 void
1319 add_addr_to_return_list(ADDRESS *addr, unsigned bitmap, char *query,
1320 int flags, COMPLETE_S **return_list)
1322 char buf[1000];
1323 char *newaddr = NULL;
1324 char *simple_addr = NULL;
1325 COMPLETE_S *new = NULL, *cp;
1326 ADDRESS *savenext;
1328 if(return_list && query && addr && addr->mailbox && addr->host){
1330 savenext = addr->next;
1331 addr->next = NULL;
1332 newaddr = addr_list_string(addr, NULL, 0);
1333 addr->next = savenext;
1336 * If the start of the full_address actually matches the query
1337 * string then mark this as ALC_FULL. This might be helpful
1338 * when deciding on the longest unambiguous match.
1340 if(newaddr && newaddr[0] && !struncmp(newaddr, query, strlen(query)))
1341 bitmap |= ALC_FULL;
1343 if(newaddr && newaddr[0] && flags & ALC_INCLUDE_ADDRS){
1344 if(addr->mailbox && addr->host
1345 && !(addr->host[0] == '@' && addr->host[1] == '\0'))
1346 simple_addr = simple_addr_string(addr, buf, sizeof(buf));
1348 if(simple_addr && !simple_addr[0])
1349 simple_addr = NULL;
1351 if(simple_addr && !struncmp(simple_addr, query, strlen(query)))
1352 bitmap |= ALC_ADDR;
1356 * We used to require && bitmap & (ALC_FULL | ALC_ADDR) before
1357 * we would add a match but we think that we should match
1358 * other stuff that matches (like middle names), too, unless we
1359 * are adding an address from the current message.
1361 if((newaddr && newaddr[0])
1362 && (!(bitmap & ALC_CURR) || bitmap & (ALC_FULL | ALC_ADDR))){
1363 new = new_complete_s(NULL, newaddr, simple_addr, NULL, NULL, bitmap);
1365 /* add to end of list */
1366 if(*return_list == NULL){
1367 *return_list = new;
1369 else{
1370 for(cp = *return_list; cp->next; cp = cp->next)
1373 cp->next = new;
1377 if(newaddr)
1378 fs_give((void **) &newaddr);
1384 * nick = nickname
1385 * full = whole thing, like Some Body <someb@there.org>
1386 * addr = address part, like someb@there.org
1388 COMPLETE_S *
1389 new_complete_s(char *nick, char *full, char *addr,
1390 char *rev_fullname, char *fcc, unsigned matches_bitmap)
1392 COMPLETE_S *new = NULL;
1394 new = (COMPLETE_S *) fs_get(sizeof(*new));
1395 memset((void *) new, 0, sizeof(*new));
1396 new->nickname = nick ? cpystr(nick) : NULL;
1397 new->full_address = full ? cpystr(full) : NULL;
1398 new->addr = addr ? cpystr(addr) : NULL;
1399 new->rev_fullname = rev_fullname ? cpystr(rev_fullname) : NULL;
1400 new->fcc = fcc ? cpystr(fcc) : NULL;
1401 new->matches_bitmap = matches_bitmap;
1403 return(new);
1407 void
1408 free_complete_s(COMPLETE_S **compptr)
1410 if(compptr && *compptr){
1411 if((*compptr)->next)
1412 free_complete_s(&(*compptr)->next);
1414 if((*compptr)->nickname)
1415 fs_give((void **) &(*compptr)->nickname);
1417 if((*compptr)->full_address)
1418 fs_give((void **) &(*compptr)->full_address);
1420 if((*compptr)->addr)
1421 fs_give((void **) &(*compptr)->addr);
1423 if((*compptr)->rev_fullname)
1424 fs_give((void **) &(*compptr)->rev_fullname);
1426 if((*compptr)->fcc)
1427 fs_give((void **) &(*compptr)->fcc);
1429 fs_give((void **) compptr);
1434 ABOOK_ENTRY_S *
1435 new_abook_entry_s(AdrBk *ab, a_c_arg_t numarg, unsigned bit)
1437 ABOOK_ENTRY_S *new = NULL;
1438 adrbk_cntr_t entrynum;
1440 entrynum = (adrbk_cntr_t) numarg;
1442 new = (ABOOK_ENTRY_S *) fs_get(sizeof(*new));
1443 memset((void *) new, 0, sizeof(*new));
1444 new->ab = ab;
1445 new->entrynum = entrynum;
1446 new->matches_bitmap = bit;
1448 return(new);
1452 void
1453 free_abook_entry_s(ABOOK_ENTRY_S **aep)
1455 if(aep && *aep){
1456 if((*aep)->next)
1457 free_abook_entry_s(&(*aep)->next);
1459 fs_give((void **) aep);
1465 * Add the second list to the end of the first.
1467 void
1468 combine_abook_entry_lists(ABOOK_ENTRY_S **first, ABOOK_ENTRY_S *second)
1470 ABOOK_ENTRY_S *sl;
1472 if(!second)
1473 return;
1475 if(first){
1476 if(*first){
1477 for(sl = *first; sl->next; sl = sl->next)
1480 sl->next = second;
1482 else
1483 *first = second;
1488 ABOOK_ENTRY_S *
1489 adrbk_list_of_possible_completions(AdrBk *ab, char *prefix)
1491 ABOOK_ENTRY_S *list = NULL, *biglist = NULL;
1493 if(!ab || !prefix)
1494 return(biglist);
1496 if(ab->nick_trie){
1497 list = adrbk_list_of_possible_trie_completions(ab->nick_trie, ab, prefix, ALC_NICK);
1498 combine_abook_entry_lists(&biglist, list);
1501 if(ab->full_trie){
1502 list = adrbk_list_of_possible_trie_completions(ab->full_trie, ab, prefix, ALC_FULL);
1503 combine_abook_entry_lists(&biglist, list);
1506 if(ab->addr_trie){
1507 list = adrbk_list_of_possible_trie_completions(ab->addr_trie, ab, prefix, ALC_ADDR);
1508 combine_abook_entry_lists(&biglist, list);
1511 if(ab->revfull_trie){
1512 list = adrbk_list_of_possible_trie_completions(ab->revfull_trie, ab, prefix, ALC_REVFULL);
1513 combine_abook_entry_lists(&biglist, list);
1516 return(biglist);
1521 * Look in this address book for all nicknames, addresses, or fullnames
1522 * which begin with the prefix prefix, and return an allocated
1523 * list of them.
1525 ABOOK_ENTRY_S *
1526 adrbk_list_of_possible_trie_completions(AdrBk_Trie *trie, AdrBk *ab, char *prefix,
1527 unsigned bit)
1529 AdrBk_Trie *t;
1530 char *p, *lookthisup;
1531 char buf[1000];
1532 ABOOK_ENTRY_S *list = NULL;
1534 if(!ab || !prefix || !trie)
1535 return(list);
1537 t = trie;
1539 /* make lookup case independent */
1541 for(p = prefix; *p && !(*p & 0x80) && islower((unsigned char) *p); p++)
1544 if(*p){
1545 strncpy(buf, prefix, sizeof(buf));
1546 buf[sizeof(buf)-1] = '\0';
1547 for(p = buf; *p; p++)
1548 if(!(*p & 0x80) && isupper((unsigned char) *p))
1549 *p = tolower(*p);
1551 lookthisup = buf;
1553 else
1554 lookthisup = prefix;
1556 p = lookthisup;
1558 while(*p){
1559 /* search for character at this level */
1560 while(t->value != *p){
1561 if(t->right == NULL)
1562 return(list); /* no match */
1564 t = t->right;
1567 if(*++p == '\0') /* matched through end of prefix */
1568 break;
1570 /* need to go down to match next character */
1571 if(t->down == NULL) /* no match */
1572 return(list);
1574 t = t->down;
1578 * If we get here that means we found at least
1579 * one entry that matches up through prefix.
1580 * Gather_abook_list recursively adds the nicknames starting at
1581 * this node.
1583 if(t->entrynum != NO_NEXT){
1585 * Add it to the list.
1587 list = new_abook_entry_s(ab, t->entrynum, bit);
1590 gather_abook_entry_list(ab, t->down, prefix, &list, bit);
1592 return(list);
1596 void
1597 gather_abook_entry_list(AdrBk *ab, AdrBk_Trie *node, char *prefix, ABOOK_ENTRY_S **list, unsigned bit)
1599 char *next_prefix = NULL;
1600 size_t l;
1601 ABOOK_ENTRY_S *newlist = NULL;
1603 if(node){
1604 if(node->entrynum != NO_NEXT || node->down || node->right){
1605 l = strlen(prefix ? prefix : "");
1606 if(node->entrynum != NO_NEXT){
1608 * Add it to the list.
1610 newlist = new_abook_entry_s(ab, node->entrynum, bit);
1611 combine_abook_entry_lists(list, newlist);
1614 /* same prefix for node->right */
1615 if(node->right)
1616 gather_abook_entry_list(ab, node->right, prefix, list, bit);
1618 /* prefix is one longer for node->down */
1619 if(node->down){
1620 next_prefix = (char *) fs_get((l+2) * sizeof(char));
1621 strncpy(next_prefix, prefix ? prefix : "", l+2);
1622 next_prefix[l] = node->value;
1623 next_prefix[l+1] = '\0';
1624 gather_abook_entry_list(ab, node->down, next_prefix, list, bit);
1626 if(next_prefix)
1627 fs_give((void **) &next_prefix);