1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: ablookup.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $";
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"
33 #include "../pith/ldap.h"
34 #endif /* ENABLE_LDAP */
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.
53 get_nickname_from_addr(struct mail_address
*adr
, char *buffer
, size_t buflen
)
59 int *save_nesting_level
;
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
)){
75 fs_give((void **)&(state
.savep
));
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..."));
83 "RESETTING address book... get_nickname_from_addr()!\n"));
85 ab_nesting_level
= *save_nesting_level
;
91 if(pith_opt_save_and_restore
)
92 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
94 abe
= address_to_abe(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';
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));
111 if(save_nesting_level
)
112 fs_give((void **)&save_nesting_level
);
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.
124 get_fcc_from_addr(struct mail_address
*adr
, char *buffer
, size_t buflen
)
129 jmp_buf save_jmp_buf
;
130 int *save_nesting_level
;
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
)){
146 fs_give((void **)&(state
.savep
));
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..."));
154 "RESETTING address book... get_fcc_from_addr()!\n"));
156 ab_nesting_level
= *save_nesting_level
;
162 if(pith_opt_save_and_restore
)
163 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
165 abe
= address_to_abe(copied_adr
);
168 mail_free_address(&copied_adr
);
170 if(abe
&& abe
->fcc
&& abe
->fcc
[0]){
171 if(!strcmp(abe
->fcc
, "\"\""))
174 strncpy(buffer
, abe
->fcc
, buflen
-1);
175 buffer
[buflen
-1] = '\0';
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));
187 if(save_nesting_level
)
188 fs_give((void **)&save_nesting_level
);
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
)
206 jmp_buf save_jmp_buf
;
207 int *save_nesting_level
;
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
)){
223 fs_give((void **)&(state
.savep
));
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..."));
231 "RESETTING address book... get_contactinfo_from_addr()!\n"));
233 ab_nesting_level
= *save_nesting_level
;
239 if(pith_opt_save_and_restore
)
240 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
242 abe
= address_to_abe(copied_adr
);
245 mail_free_address(&copied_adr
);
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
);
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));
269 if(save_nesting_level
)
270 fs_give((void **)&save_nesting_level
);
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.
282 address_in_abook(MAILSTREAM
*stream
, SEARCHSET
*searchset
,
283 int inabook
, PATTERN_S
*abooks
)
289 ADDRESS
*from
, *reply_to
, *sender
, *to
, *cc
;
290 int is_there
, adrbknum
, *abooklist
= NULL
, positive_match
;
295 jmp_buf save_jmp_buf
;
296 int *save_nesting_level
;
301 /* everything that matches remains a match */
302 if(inabook
== IAB_EITHER
)
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
;
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
){
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.
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
)){
352 fs_give((void **)&(state
.savep
));
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..."));
360 "RESETTING address book... address_in_abook()!\n"));
362 ab_nesting_level
= *save_nesting_level
;
368 if(pith_opt_save_and_restore
)
369 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
372 abooklist
= (int *) fs_get(as
.n_addrbk
* sizeof(*abooklist
));
373 memset((void *) abooklist
, 0, as
.n_addrbk
* sizeof(*abooklist
));
377 switch(inabook
& IAB_TYPE_MASK
){
380 for(adrbknum
= 0; adrbknum
< as
.n_addrbk
; adrbknum
++)
381 abooklist
[adrbknum
] = 1;
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;
406 switch(inabook
& IAB_TYPE_MASK
){
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
,
440 for(s
= ss
; s
; s
= s
->next
){
441 for(i
= s
->first
; i
<= s
->last
; i
++){
442 if(i
<= 0L || i
> stream
->nmsgs
)
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
;
454 for(adrbknum
= 0; !is_there
&& adrbknum
< as
.n_addrbk
; adrbknum
++){
455 if(!abooklist
[adrbknum
])
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
));
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
472 if(!is_there
&& i
> 0L && i
<= stream
->nmsgs
&& (mc
= mail_elt(stream
, i
)))
476 if(is_there
&& i
> 0L && i
<= stream
->nmsgs
&& (mc
= mail_elt(stream
, i
)))
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));
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
);
501 mail_free_searchset(&ss
);
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
;
517 char abuf
[MAX_ADDR_FIELD
+1];
519 if(!(pab
&& addr
&& addr
->mailbox
))
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
);
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).
557 adrbk_lookup_with_opens_by_nick(char *nickname
, int clearrefs
, int *which_addrbook
, int not_here
)
559 AdrBk_Entry
*abe
= (AdrBk_Entry
*)NULL
;
563 dprint((5, "- adrbk_lookup_with_opens_by_nick(%s) -\n",
564 nickname
? nickname
: "?"));
566 for(i
= 0; i
< as
.n_addrbk
; i
++){
573 if(pab
->ostatus
!= Open
&& pab
->ostatus
!= NoDisplay
)
574 init_abook(pab
, NoDisplay
);
577 adrbk_clearrefs(pab
->address_book
);
579 abe
= adrbk_lookup_by_nick(pab
->address_book
,
581 (adrbk_cntr_t
*)NULL
);
586 if(abe
&& which_addrbook
)
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
605 address_to_abe(struct mail_address
*addr
)
607 register PerAddrBook
*pab
;
609 AdrBk_Entry
*abe
= 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
,
634 (adrbk_cntr_t
*)NULL
);
640 fs_give((void **)&abuf
);
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
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
;
669 fullname
= (abe
->fullname
&& abe
->fullname
[0]) ? abe
->fullname
: NULL
;
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
);
678 fs_give((void **)&tmp_a_string
);
680 if(addr
&& fullname
){
682 if(strncmp(addr
->mailbox
, RUN_LDAP
, LEN_RL
) != 0)
683 #endif /* ENABLE_LDAP */
686 fs_give((void **)&addr
->personal
);
688 addr
->personal
= adrbk_formatname(fullname
, NULL
, NULL
);
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
);
702 fs_give((void **)&tmp_a_string
);
711 for(l2
= abe
->addr
.list
; *l2
; l2
++)
712 length
+= (strlen(*l2
) + 1);
714 list
= (char *)fs_get(length
+ 1);
716 for(l2
= abe
->addr
.list
; *l2
; l2
++){
717 if(l1
!= list
&& length
-(l1
-list
) > 0)
720 strncpy(l1
, *l2
, length
-(l1
-list
));
726 rfc822_parse_adrlist(&addr
, list
, fakedomain
);
728 fs_give((void **)&list
);
733 dprint((1, "default case in abe_to_address, shouldn't happen\n"));
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
755 abe_to_nick_or_addr_string(AdrBk_Entry
*abe
, AddrScrn_Disp
*dl
, int abook_num
)
763 if((dl
->type
== Simple
|| dl
->type
== ListHead
)
764 && abe
->nickname
&& abe
->nickname
[0]){
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
));
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 */
790 mail_free_address(&addr
);
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,
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
)
827 if(!a
|| a
->mailbox
== NULL
|| !ps
)
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, */
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)))))
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 */
863 if(a
&& a
->host
&& a
->mailbox
)
864 snprintf(addrstr
, sizeof(addrstr
), "%s@%s", a
->mailbox
, a
->host
);
868 for(t
= ps_global
->VAR_ALT_ADDRS
; !ret
&& t
[0] && t
[0][0]; t
++){
876 if(F_ON(F_DISABLE_REGEX
, ps_global
) || !contains_regex_special_chars(alt
)){
882 rfc822_parse_adrlist(&alt_addr
, alt2
, ps_global
->maildomain
);
884 fs_give((void **) &alt2
);
886 if(address_is_same(a
, alt_addr
))
890 mail_free_address(&alt_addr
);
893 /* treat alt as a regular expression */
895 if(!(err
=regcomp(®
, alt
, REG_ICASE
| REG_NOSUB
| REG_EXTENDED
))){
896 err
= regexec(®
, addrstr
, 0, NULL
, 0);
899 else if(err
!= REG_NOMATCH
){
900 regerror(err
, ®
, ebuf
, sizeof(ebuf
));
902 dprint((2, "- address_is_us regexec error: %s (%s)", ebuf
, alt
));
908 regerror(err
, ®
, ebuf
, sizeof(ebuf
));
910 dprint((2, "- address_is_us regcomp error: %s (%s)", ebuf
, alt
));
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.
928 contains_regex_special_chars(char *str
)
930 char special_chars
[] = {'*', '|', '+', '?', '{', '[', '^', '$', '\\', '\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
))
948 * Compare the two addresses, and return true if they're the same,
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
)
973 char **alist
, **blist
;
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. */
989 result
= strcmp(a
->addr
.addr
,b
->addr
.addr
) == 0;
991 alist
= a
->addr
.list
;
992 blist
= b
->addr
.list
;
996 /* compare the whole lists */
999 while(addra
&& addrb
&& strcmp(addra
,addrb
) == 0){
1006 if(!addra
&& !addrb
)
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.
1030 addr_lookup(char *nickname
, int *which_addrbook
, int not_here
)
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
);
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.
1075 adrbk_list_of_completions(char *query
, MAILSTREAM
*stream
, imapuid_t uid
, int flags
)
1080 ABOOK_ENTRY_S
*list
, *list2
, *biglist
= NULL
;
1081 COMPLETE_S
*return_list
= NULL
, *last_one_added
= NULL
, *new, *cp
, *dp
, *dprev
;
1085 char *newaddr
= NULL
, *simple_addr
= NULL
, *fcc
= NULL
;
1086 ENVELOPE
*env
= 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
){
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
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]){
1147 char *fakedomain
= "@";
1149 tmp_a_string
= cpystr(toaddr
.arg
.abe
->addr
.addr
);
1151 rfc822_parse_adrlist(&addr
, tmp_a_string
, fakedomain
);
1153 fs_give((void **) &tmp_a_string
);
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
){
1172 last_one_added
= new;
1175 last_one_added
->next
= new;
1176 last_one_added
= new;
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
);
1190 if(flags
& ALC_INCLUDE_LDAP
){
1191 LDAP_SERV_RES_S
*head_of_result_list
= NULL
, *res
;
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
);
1208 e
= ldap_next_entry(res
->ld
, e
)){
1209 simple_addr
= newaddr
= NULL
;
1211 cs
.selected_entry
= e
;
1212 cs
.info_used
= res
->info_used
;
1213 cs
.serv
= res
->serv
;
1214 addr
= address_from_ldap(&cs
);
1216 add_addr_to_return_list(addr
, ALC_LDAP
, query
, flags
, &return_list
);
1217 mail_free_address(&addr
);
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 */
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.
1256 TA_S
*talist
= NULL
, *tp
;
1258 if(grab_addrs_from_body(stream
, mail_msgno(stream
,uid
), body
, &talist
) > 0){
1261 /* rewind to start */
1263 talist
= talist
->prev
;
1265 for(tp
= talist
; tp
; tp
= tp
->next
){
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
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
;
1306 free_complete_s(&dp
);
1314 return(return_list
);
1319 add_addr_to_return_list(ADDRESS
*addr
, unsigned bitmap
, char *query
,
1320 int flags
, COMPLETE_S
**return_list
)
1323 char *newaddr
= NULL
;
1324 char *simple_addr
= NULL
;
1325 COMPLETE_S
*new = NULL
, *cp
;
1328 if(return_list
&& query
&& addr
&& addr
->mailbox
&& addr
->host
){
1330 savenext
= addr
->next
;
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
)))
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])
1351 if(simple_addr
&& !struncmp(simple_addr
, query
, strlen(query
)))
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
){
1370 for(cp
= *return_list
; cp
->next
; cp
= cp
->next
)
1378 fs_give((void **) &newaddr
);
1385 * full = whole thing, like Some Body <someb@there.org>
1386 * addr = address part, like someb@there.org
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
;
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
);
1427 fs_give((void **) &(*compptr
)->fcc
);
1429 fs_give((void **) compptr
);
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));
1445 new->entrynum
= entrynum
;
1446 new->matches_bitmap
= bit
;
1453 free_abook_entry_s(ABOOK_ENTRY_S
**aep
)
1457 free_abook_entry_s(&(*aep
)->next
);
1459 fs_give((void **) aep
);
1465 * Add the second list to the end of the first.
1468 combine_abook_entry_lists(ABOOK_ENTRY_S
**first
, ABOOK_ENTRY_S
*second
)
1477 for(sl
= *first
; sl
->next
; sl
= sl
->next
)
1489 adrbk_list_of_possible_completions(AdrBk
*ab
, char *prefix
)
1491 ABOOK_ENTRY_S
*list
= NULL
, *biglist
= NULL
;
1497 list
= adrbk_list_of_possible_trie_completions(ab
->nick_trie
, ab
, prefix
, ALC_NICK
);
1498 combine_abook_entry_lists(&biglist
, list
);
1502 list
= adrbk_list_of_possible_trie_completions(ab
->full_trie
, ab
, prefix
, ALC_FULL
);
1503 combine_abook_entry_lists(&biglist
, list
);
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
);
1521 * Look in this address book for all nicknames, addresses, or fullnames
1522 * which begin with the prefix prefix, and return an allocated
1526 adrbk_list_of_possible_trie_completions(AdrBk_Trie
*trie
, AdrBk
*ab
, char *prefix
,
1530 char *p
, *lookthisup
;
1532 ABOOK_ENTRY_S
*list
= NULL
;
1534 if(!ab
|| !prefix
|| !trie
)
1539 /* make lookup case independent */
1541 for(p
= prefix
; *p
&& !(*p
& 0x80) && islower((unsigned char) *p
); 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
))
1554 lookthisup
= prefix
;
1559 /* search for character at this level */
1560 while(t
->value
!= *p
){
1561 if(t
->right
== NULL
)
1562 return(list
); /* no match */
1567 if(*++p
== '\0') /* matched through end of prefix */
1570 /* need to go down to match next character */
1571 if(t
->down
== NULL
) /* no match */
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
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
);
1597 gather_abook_entry_list(AdrBk
*ab
, AdrBk_Trie
*node
, char *prefix
, ABOOK_ENTRY_S
**list
, unsigned bit
)
1599 char *next_prefix
= NULL
;
1601 ABOOK_ENTRY_S
*newlist
= NULL
;
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 */
1616 gather_abook_entry_list(ab
, node
->right
, prefix
, list
, bit
);
1618 /* prefix is one longer for 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
);
1627 fs_give((void **) &next_prefix
);