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 2006-2009 University of Washington
8 * Copyright 2013-2015 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" /* 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
);
866 for(t
= ps_global
->VAR_ALT_ADDRS
; !ret
&& t
[0] && t
[0][0]; t
++){
874 if(F_ON(F_DISABLE_REGEX
, ps_global
) || !contains_regex_special_chars(alt
)){
880 rfc822_parse_adrlist(&alt_addr
, alt2
, ps_global
->maildomain
);
882 fs_give((void **) &alt2
);
884 if(address_is_same(a
, alt_addr
))
888 mail_free_address(&alt_addr
);
891 /* treat alt as a regular expression */
893 if(!(err
=regcomp(®
, alt
, REG_ICASE
| REG_NOSUB
| REG_EXTENDED
))){
894 err
= regexec(®
, addrstr
, 0, NULL
, 0);
897 else if(err
!= REG_NOMATCH
){
898 regerror(err
, ®
, ebuf
, sizeof(ebuf
));
900 dprint((2, "- address_is_us regexec error: %s (%s)", ebuf
, alt
));
906 regerror(err
, ®
, ebuf
, sizeof(ebuf
));
908 dprint((2, "- address_is_us regcomp error: %s (%s)", ebuf
, alt
));
919 * In an ad hoc way try to decide if str is meant to be a regular
920 * expression or not. Dot doesn't count * as regex stuff because
921 * we're worried about addresses.
926 contains_regex_special_chars(char *str
)
928 char special_chars
[] = {'*', '|', '+', '?', '{', '[', '^', '$', '\\', '\0'};
935 * If any of special_chars are in str consider it a regex expression.
937 for(c
= special_chars
; *c
; c
++)
938 if(strindex(str
, *c
))
946 * Compare the two addresses, and return true if they're the same,
949 * Args: a -- First address for comparison
950 * b -- Second address for comparison
952 * Result: returns 1 if it matches, 0 otherwise.
955 address_is_same(struct mail_address
*a
, struct mail_address
*b
)
957 return(a
&& b
&& a
->mailbox
&& b
->mailbox
&& a
->host
&& b
->host
958 && strucmp(a
->mailbox
, b
->mailbox
) == 0
959 && strucmp(a
->host
, b
->host
) == 0);
964 * Returns nonzero if the two address book entries are equal.
965 * Returns zero if not equal.
968 abes_are_equal(AdrBk_Entry
*a
, AdrBk_Entry
*b
)
971 char **alist
, **blist
;
976 ((!a
->nickname
&& !b
->nickname
) ||
977 (a
->nickname
&& b
->nickname
&& strcmp(a
->nickname
,b
->nickname
) == 0)) &&
978 ((!a
->fullname
&& !b
->fullname
) ||
979 (a
->fullname
&& b
->fullname
&& strcmp(a
->fullname
,b
->fullname
) == 0)) &&
980 ((!a
->fcc
&& !b
->fcc
) ||
981 (a
->fcc
&& b
->fcc
&& strcmp(a
->fcc
,b
->fcc
) == 0)) &&
982 ((!a
->extra
&& !b
->extra
) ||
983 (a
->extra
&& b
->extra
&& strcmp(a
->extra
,b
->extra
) == 0))){
985 /* If we made it in here, they still might be equal. */
987 result
= strcmp(a
->addr
.addr
,b
->addr
.addr
) == 0;
989 alist
= a
->addr
.list
;
990 blist
= b
->addr
.list
;
994 /* compare the whole lists */
997 while(addra
&& addrb
&& strcmp(addra
,addrb
) == 0){
1004 if(!addra
&& !addrb
)
1015 * Interface to address book lookups for callers outside or inside this file.
1017 * Args: nickname -- The nickname to look up
1018 * which_addrbook -- If matched, addrbook number it was found in.
1019 * not_here -- If non-negative, skip looking in this abook.
1021 * Result: returns NULL or the corresponding fullname. The fullname is
1022 * allocated here so the caller must free it.
1024 * This opens the address books if they haven't been opened and restores
1025 * them to the state they were in upon entry.
1028 addr_lookup(char *nickname
, int *which_addrbook
, int not_here
)
1034 dprint((9, "- addr_lookup(%s) -\n",nickname
? nickname
: "nil"));
1036 init_ab_if_needed();
1038 if(pith_opt_save_and_restore
)
1039 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
1041 abe
= adrbk_lookup_with_opens_by_nick(nickname
,0,which_addrbook
,not_here
);
1043 fullname
= (abe
&& abe
->fullname
) ? cpystr(abe
->fullname
) : NULL
;
1045 if(pith_opt_save_and_restore
)
1046 (*pith_opt_save_and_restore
)(SAR_RESTORE
, &state
);
1053 * Look in all of the address books for all of the possible entries
1054 * that match the query string. The matches can be for the nickname,
1055 * for the fullname, or for the address@host part of the address.
1056 * All of the matches are at the starts of the strings, not a general
1057 * substring match. This is not true anymore. Fullname matches can be
1058 * at the start of the fullname or starting after a space in the fullname.
1059 * If flags has ALC_INCLUDE_LDAP defined then LDAP
1060 * entries are added to the end of the list. The LDAP queries are done
1061 * only for those servers that have the 'impl' feature turned on, which
1062 * means that lookups should be done implicitly. This feature also
1063 * controls whether or not lookups should be done when typing carriage
1064 * return (instead of this which is TAB).
1066 * Args query -- What the user has typed so far
1068 * Returns a list of possibilities for the given query string.
1070 * Caller needs to free the answer.
1073 adrbk_list_of_completions(char *query
, MAILSTREAM
*stream
, imapuid_t uid
, int flags
)
1078 ABOOK_ENTRY_S
*list
, *list2
, *biglist
= NULL
;
1079 COMPLETE_S
*return_list
= NULL
, *last_one_added
= NULL
, *new, *cp
, *dp
, *dprev
;
1083 char *newaddr
= NULL
, *simple_addr
= NULL
, *fcc
= NULL
;
1084 ENVELOPE
*env
= NULL
;
1087 init_ab_if_needed();
1089 if(pith_opt_save_and_restore
)
1090 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
1092 for(i
= 0; i
< as
.n_addrbk
; i
++){
1094 pab
= &as
.adrbks
[i
];
1096 if(pab
->ostatus
!= Open
&& pab
->ostatus
!= NoDisplay
)
1097 init_abook(pab
, NoDisplay
);
1099 list
= adrbk_list_of_possible_completions(pab
? pab
->address_book
: NULL
, query
);
1100 combine_abook_entry_lists(&biglist
, list
);
1104 * Eliminate duplicates by NO_NEXTing the entrynums.
1106 for(list
= biglist
; list
; list
= list
->next
)
1107 /* eliminate any dups further along in the list */
1108 if(list
->entrynum
!= NO_NEXT
)
1109 for(list2
= list
->next
; list2
; list2
= list2
->next
)
1110 if(list2
->entrynum
== list
->entrynum
){
1111 list2
->entrynum
= NO_NEXT
;
1112 list
->matches_bitmap
|= list2
->matches_bitmap
;
1115 /* build the return list */
1116 for(list
= biglist
; list
; list
= list
->next
)
1117 if(list
->entrynum
!= NO_NEXT
){
1120 toaddr
.arg
.abe
= adrbk_get_ae(list
->ab
, list
->entrynum
);
1121 if(our_build_address(toaddr
, &newaddr
, NULL
, &fcc
, NULL
) == 0){
1122 char *reverse_fullname
= NULL
;
1125 * ALC_FULL is a regular FullName match and that will be
1126 * captured in the full_address field. If there was also
1127 * an ALC_REVFULL match that means that the user has the
1128 * FullName entered in their addrbook as Last, First and
1129 * that is where the match was. We want to put that in
1130 * the completions structure in the rev_fullname field.
1132 if(list
->matches_bitmap
& ALC_REVFULL
1134 && toaddr
.arg
.abe
->fullname
&& toaddr
.arg
.abe
->fullname
[0]
1135 && toaddr
.arg
.abe
->fullname
[0] != '"'
1136 && strindex(toaddr
.arg
.abe
->fullname
, ',') != NULL
){
1138 reverse_fullname
= toaddr
.arg
.abe
->fullname
;
1141 if(flags
& ALC_INCLUDE_ADDRS
){
1142 if(toaddr
.arg
.abe
&& toaddr
.arg
.abe
->tag
== Single
1143 && toaddr
.arg
.abe
->addr
.addr
&& toaddr
.arg
.abe
->addr
.addr
[0]){
1145 char *fakedomain
= "@";
1147 tmp_a_string
= cpystr(toaddr
.arg
.abe
->addr
.addr
);
1149 rfc822_parse_adrlist(&addr
, tmp_a_string
, fakedomain
);
1151 fs_give((void **) &tmp_a_string
);
1154 if(addr
->mailbox
&& addr
->host
1155 && !(addr
->host
[0] == '@' && addr
->host
[1] == '\0'))
1156 simple_addr
= simple_addr_string(addr
, buf
, sizeof(buf
));
1158 mail_free_address(&addr
);
1163 new = new_complete_s(toaddr
.arg
.abe
? toaddr
.arg
.abe
->nickname
: NULL
,
1164 newaddr
, simple_addr
, reverse_fullname
, fcc
,
1165 list
->matches_bitmap
| ALC_ABOOK
);
1167 /* add to end of list */
1168 if(return_list
== NULL
){
1170 last_one_added
= new;
1173 last_one_added
->next
= new;
1174 last_one_added
= new;
1179 fs_give((void **) &newaddr
);
1182 if(pith_opt_save_and_restore
)
1183 (*pith_opt_save_and_restore
)(SAR_RESTORE
, &state
);
1185 free_abook_entry_s(&biglist
);
1188 if(flags
& ALC_INCLUDE_LDAP
){
1189 LDAP_SERV_RES_S
*head_of_result_list
= NULL
, *res
;
1194 memset(&wp_err
, 0, sizeof(wp_err
));
1197 * This lookup covers all servers with the impl bit set.
1198 * It uses the regular LDAP search parameters that the
1199 * user has set, not necessarily just a prefix match
1200 * like the rest of the address completion above.
1202 head_of_result_list
= ldap_lookup_all_work(query
, as
.n_serv
, 0, NULL
, &wp_err
);
1203 for(res
= head_of_result_list
; res
; res
= res
->next
){
1204 for(e
= ldap_first_entry(res
->ld
, res
->res
);
1206 e
= ldap_next_entry(res
->ld
, e
)){
1207 simple_addr
= newaddr
= NULL
;
1209 cs
.selected_entry
= e
;
1210 cs
.info_used
= res
->info_used
;
1211 cs
.serv
= res
->serv
;
1212 addr
= address_from_ldap(&cs
);
1214 add_addr_to_return_list(addr
, ALC_LDAP
, query
, flags
, &return_list
);
1215 mail_free_address(&addr
);
1221 fs_give((void **) &wp_err
.error
);
1223 if(head_of_result_list
)
1224 free_ldap_result_list(&head_of_result_list
);
1226 #endif /* ENABLE_LDAP */
1228 /* add from current message */
1229 if(uid
> 0 && stream
)
1230 env
= pine_mail_fetch_structure(stream
, uid
, &body
, FT_UID
);
1232 /* from the envelope addresses */
1234 for(addr
= env
->from
; addr
; addr
= addr
->next
)
1235 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1237 for(addr
= env
->reply_to
; addr
; addr
= addr
->next
)
1238 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1240 for(addr
= env
->sender
; addr
; addr
= addr
->next
)
1241 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1243 for(addr
= env
->to
; addr
; addr
= addr
->next
)
1244 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1246 for(addr
= env
->cc
; addr
; addr
= addr
->next
)
1247 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1250 * May as well search the body for addresses.
1251 * Use this function written for TakeAddr.
1254 TA_S
*talist
= NULL
, *tp
;
1256 if(grab_addrs_from_body(stream
, mail_msgno(stream
,uid
), body
, &talist
) > 0){
1259 /* rewind to start */
1261 talist
= talist
->prev
;
1263 for(tp
= talist
; tp
; tp
= tp
->next
){
1266 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1269 free_talines(&talist
);
1277 * Check for and eliminate some duplicates.
1278 * The criteria for deciding what is a duplicate is
1281 for(cp
= return_list
; cp
; cp
= cp
->next
)
1282 for(dprev
= cp
, dp
= cp
->next
; dp
; ){
1283 if(cp
->full_address
&& dp
->full_address
1284 && !strucmp(dp
->full_address
, cp
->full_address
)
1285 && (((cp
->matches_bitmap
& ALC_ABOOK
)
1286 && (dp
->matches_bitmap
& ALC_ABOOK
)
1287 && (!(dp
->matches_bitmap
& ALC_NICK
&& dp
->nickname
&& dp
->nickname
[0])
1288 || ((!cp
->addr
&& !dp
->addr
) || (cp
->addr
&& dp
->addr
&& !strucmp(cp
->addr
, dp
->addr
)))))
1290 (dp
->matches_bitmap
& ALC_CURR
)
1292 (dp
->matches_bitmap
& ALC_LDAP
1293 && dp
->matches_bitmap
& (ALC_FULL
| ALC_ADDR
))
1295 (cp
->matches_bitmap
== dp
->matches_bitmap
1296 && (!(dp
->matches_bitmap
& ALC_NICK
&& dp
->nickname
&& dp
->nickname
[0])
1297 || (dp
->nickname
&& cp
->nickname
1298 && !strucmp(cp
->nickname
, dp
->nickname
)))))){
1300 * dp is equivalent to cp so eliminate dp
1302 dprev
->next
= dp
->next
;
1304 free_complete_s(&dp
);
1312 return(return_list
);
1317 add_addr_to_return_list(ADDRESS
*addr
, unsigned bitmap
, char *query
,
1318 int flags
, COMPLETE_S
**return_list
)
1321 char *newaddr
= NULL
;
1322 char *simple_addr
= NULL
;
1323 COMPLETE_S
*new = NULL
, *cp
;
1326 if(return_list
&& query
&& addr
&& addr
->mailbox
&& addr
->host
){
1328 savenext
= addr
->next
;
1330 newaddr
= addr_list_string(addr
, NULL
, 0);
1331 addr
->next
= savenext
;
1334 * If the start of the full_address actually matches the query
1335 * string then mark this as ALC_FULL. This might be helpful
1336 * when deciding on the longest unambiguous match.
1338 if(newaddr
&& newaddr
[0] && !struncmp(newaddr
, query
, strlen(query
)))
1341 if(newaddr
&& newaddr
[0] && flags
& ALC_INCLUDE_ADDRS
){
1342 if(addr
->mailbox
&& addr
->host
1343 && !(addr
->host
[0] == '@' && addr
->host
[1] == '\0'))
1344 simple_addr
= simple_addr_string(addr
, buf
, sizeof(buf
));
1346 if(simple_addr
&& !simple_addr
[0])
1349 if(simple_addr
&& !struncmp(simple_addr
, query
, strlen(query
)))
1354 * We used to require && bitmap & (ALC_FULL | ALC_ADDR) before
1355 * we would add a match but we think that we should match
1356 * other stuff that matches (like middle names), too, unless we
1357 * are adding an address from the current message.
1359 if((newaddr
&& newaddr
[0])
1360 && (!(bitmap
& ALC_CURR
) || bitmap
& (ALC_FULL
| ALC_ADDR
))){
1361 new = new_complete_s(NULL
, newaddr
, simple_addr
, NULL
, NULL
, bitmap
);
1363 /* add to end of list */
1364 if(*return_list
== NULL
){
1368 for(cp
= *return_list
; cp
->next
; cp
= cp
->next
)
1376 fs_give((void **) &newaddr
);
1383 * full = whole thing, like Some Body <someb@there.org>
1384 * addr = address part, like someb@there.org
1387 new_complete_s(char *nick
, char *full
, char *addr
,
1388 char *rev_fullname
, char *fcc
, unsigned matches_bitmap
)
1390 COMPLETE_S
*new = NULL
;
1392 new = (COMPLETE_S
*) fs_get(sizeof(*new));
1393 memset((void *) new, 0, sizeof(*new));
1394 new->nickname
= nick
? cpystr(nick
) : NULL
;
1395 new->full_address
= full
? cpystr(full
) : NULL
;
1396 new->addr
= addr
? cpystr(addr
) : NULL
;
1397 new->rev_fullname
= rev_fullname
? cpystr(rev_fullname
) : NULL
;
1398 new->fcc
= fcc
? cpystr(fcc
) : NULL
;
1399 new->matches_bitmap
= matches_bitmap
;
1406 free_complete_s(COMPLETE_S
**compptr
)
1408 if(compptr
&& *compptr
){
1409 if((*compptr
)->next
)
1410 free_complete_s(&(*compptr
)->next
);
1412 if((*compptr
)->nickname
)
1413 fs_give((void **) &(*compptr
)->nickname
);
1415 if((*compptr
)->full_address
)
1416 fs_give((void **) &(*compptr
)->full_address
);
1418 if((*compptr
)->addr
)
1419 fs_give((void **) &(*compptr
)->addr
);
1421 if((*compptr
)->rev_fullname
)
1422 fs_give((void **) &(*compptr
)->rev_fullname
);
1425 fs_give((void **) &(*compptr
)->fcc
);
1427 fs_give((void **) compptr
);
1433 new_abook_entry_s(AdrBk
*ab
, a_c_arg_t numarg
, unsigned bit
)
1435 ABOOK_ENTRY_S
*new = NULL
;
1436 adrbk_cntr_t entrynum
;
1438 entrynum
= (adrbk_cntr_t
) numarg
;
1440 new = (ABOOK_ENTRY_S
*) fs_get(sizeof(*new));
1441 memset((void *) new, 0, sizeof(*new));
1443 new->entrynum
= entrynum
;
1444 new->matches_bitmap
= bit
;
1451 free_abook_entry_s(ABOOK_ENTRY_S
**aep
)
1455 free_abook_entry_s(&(*aep
)->next
);
1457 fs_give((void **) aep
);
1463 * Add the second list to the end of the first.
1466 combine_abook_entry_lists(ABOOK_ENTRY_S
**first
, ABOOK_ENTRY_S
*second
)
1475 for(sl
= *first
; sl
->next
; sl
= sl
->next
)
1487 adrbk_list_of_possible_completions(AdrBk
*ab
, char *prefix
)
1489 ABOOK_ENTRY_S
*list
= NULL
, *biglist
= NULL
;
1495 list
= adrbk_list_of_possible_trie_completions(ab
->nick_trie
, ab
, prefix
, ALC_NICK
);
1496 combine_abook_entry_lists(&biglist
, list
);
1500 list
= adrbk_list_of_possible_trie_completions(ab
->full_trie
, ab
, prefix
, ALC_FULL
);
1501 combine_abook_entry_lists(&biglist
, list
);
1505 list
= adrbk_list_of_possible_trie_completions(ab
->addr_trie
, ab
, prefix
, ALC_ADDR
);
1506 combine_abook_entry_lists(&biglist
, list
);
1509 if(ab
->revfull_trie
){
1510 list
= adrbk_list_of_possible_trie_completions(ab
->revfull_trie
, ab
, prefix
, ALC_REVFULL
);
1511 combine_abook_entry_lists(&biglist
, list
);
1519 * Look in this address book for all nicknames, addresses, or fullnames
1520 * which begin with the prefix prefix, and return an allocated
1524 adrbk_list_of_possible_trie_completions(AdrBk_Trie
*trie
, AdrBk
*ab
, char *prefix
,
1528 char *p
, *lookthisup
;
1530 ABOOK_ENTRY_S
*list
= NULL
;
1532 if(!ab
|| !prefix
|| !trie
)
1537 /* make lookup case independent */
1539 for(p
= prefix
; *p
&& !(*p
& 0x80) && islower((unsigned char) *p
); p
++)
1543 strncpy(buf
, prefix
, sizeof(buf
));
1544 buf
[sizeof(buf
)-1] = '\0';
1545 for(p
= buf
; *p
; p
++)
1546 if(!(*p
& 0x80) && isupper((unsigned char) *p
))
1552 lookthisup
= prefix
;
1557 /* search for character at this level */
1558 while(t
->value
!= *p
){
1559 if(t
->right
== NULL
)
1560 return(list
); /* no match */
1565 if(*++p
== '\0') /* matched through end of prefix */
1568 /* need to go down to match next character */
1569 if(t
->down
== NULL
) /* no match */
1576 * If we get here that means we found at least
1577 * one entry that matches up through prefix.
1578 * Gather_abook_list recursively adds the nicknames starting at
1581 if(t
->entrynum
!= NO_NEXT
){
1583 * Add it to the list.
1585 list
= new_abook_entry_s(ab
, t
->entrynum
, bit
);
1588 gather_abook_entry_list(ab
, t
->down
, prefix
, &list
, bit
);
1595 gather_abook_entry_list(AdrBk
*ab
, AdrBk_Trie
*node
, char *prefix
, ABOOK_ENTRY_S
**list
, unsigned bit
)
1597 char *next_prefix
= NULL
;
1599 ABOOK_ENTRY_S
*newlist
= NULL
;
1602 if(node
->entrynum
!= NO_NEXT
|| node
->down
|| node
->right
){
1603 l
= strlen(prefix
? prefix
: "");
1604 if(node
->entrynum
!= NO_NEXT
){
1606 * Add it to the list.
1608 newlist
= new_abook_entry_s(ab
, node
->entrynum
, bit
);
1609 combine_abook_entry_lists(list
, newlist
);
1612 /* same prefix for node->right */
1614 gather_abook_entry_list(ab
, node
->right
, prefix
, list
, bit
);
1616 /* prefix is one longer for node->down */
1618 next_prefix
= (char *) fs_get((l
+2) * sizeof(char));
1619 strncpy(next_prefix
, prefix
? prefix
: "", l
+2);
1620 next_prefix
[l
] = node
->value
;
1621 next_prefix
[l
+1] = '\0';
1622 gather_abook_entry_list(ab
, node
->down
, next_prefix
, list
, bit
);
1625 fs_give((void **) &next_prefix
);