2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2009 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 #include "../pith/headers.h" /* for os-dep and pith defs/includes */
16 #include "../pith/debug.h"
17 #include "../pith/util.h"
18 #include "../pith/adrbklib.h"
19 #include "../pith/copyaddr.h"
20 #include "../pith/status.h"
21 #include "../pith/conf.h"
22 #include "../pith/search.h"
23 #include "../pith/abdlc.h"
24 #include "../pith/addrstring.h"
25 #include "../pith/ablookup.h"
26 #include "../pith/options.h"
27 #include "../pith/takeaddr.h"
29 #include "../pith/ldap.h"
30 #endif /* ENABLE_LDAP */
36 int addr_is_in_addrbook(PerAddrBook
*, ADDRESS
*);
37 ABOOK_ENTRY_S
*adrbk_list_of_possible_trie_completions(AdrBk_Trie
*, AdrBk
*, char *, unsigned);
38 void gather_abook_entry_list(AdrBk
*, AdrBk_Trie
*, char *, ABOOK_ENTRY_S
**, unsigned);
39 void add_addr_to_return_list(ADDRESS
*, unsigned, char *, int, COMPLETE_S
**);
43 * Given an address, try to find the first nickname that goes with it.
44 * Copies that nickname into the passed in buffer, which is assumed to
45 * be at least MAX_NICKNAME+1 in length. Returns NULL if it can't be found,
46 * else it returns a pointer to the buffer.
49 get_nickname_from_addr(struct mail_address
*adr
, char *buffer
, size_t buflen
)
55 int *save_nesting_level
;
60 state
.dlc_to_warp_to
= NULL
;
61 copied_adr
= copyaddr(adr
);
63 if(ps_global
->remote_abook_validity
> 0)
64 (void)adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0);
66 save_nesting_level
= cpyint(ab_nesting_level
);
67 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
68 if(setjmp(addrbook_changed_unexpectedly
)){
71 fs_give((void **)&(state
.savep
));
73 fs_give((void **)&(state
.stp
));
74 if(state
.dlc_to_warp_to
)
75 fs_give((void **)&(state
.dlc_to_warp_to
));
77 q_status_message(SM_ORDER
, 3, 5, _("Resetting address book..."));
79 "RESETTING address book... get_nickname_from_addr()!\n"));
81 ab_nesting_level
= *save_nesting_level
;
87 if(pith_opt_save_and_restore
)
88 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
90 abe
= address_to_abe(copied_adr
);
93 mail_free_address(&copied_adr
);
95 if(abe
&& abe
->nickname
&& abe
->nickname
[0]){
96 strncpy(buffer
, abe
->nickname
, buflen
-1);
97 buffer
[buflen
-1] = '\0';
101 if(pith_opt_save_and_restore
)
102 (*pith_opt_save_and_restore
)(SAR_RESTORE
, &state
);
104 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
107 if(save_nesting_level
)
108 fs_give((void **)&save_nesting_level
);
115 * Given an address, try to find the first fcc that goes with it.
116 * Copies that fcc into the passed in buffer.
117 * Returns NULL if it can't be found, else it returns a pointer to the buffer.
120 get_fcc_from_addr(struct mail_address
*adr
, char *buffer
, size_t buflen
)
125 jmp_buf save_jmp_buf
;
126 int *save_nesting_level
;
131 state
.dlc_to_warp_to
= NULL
;
132 copied_adr
= copyaddr(adr
);
134 if(ps_global
->remote_abook_validity
> 0)
135 (void)adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0);
137 save_nesting_level
= cpyint(ab_nesting_level
);
138 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
139 if(setjmp(addrbook_changed_unexpectedly
)){
142 fs_give((void **)&(state
.savep
));
144 fs_give((void **)&(state
.stp
));
145 if(state
.dlc_to_warp_to
)
146 fs_give((void **)&(state
.dlc_to_warp_to
));
148 q_status_message(SM_ORDER
, 3, 5, _("Resetting address book..."));
150 "RESETTING address book... get_fcc_from_addr()!\n"));
152 ab_nesting_level
= *save_nesting_level
;
158 if(pith_opt_save_and_restore
)
159 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
161 abe
= address_to_abe(copied_adr
);
164 mail_free_address(&copied_adr
);
166 if(abe
&& abe
->fcc
&& abe
->fcc
[0]){
167 if(!strcmp(abe
->fcc
, "\"\""))
170 strncpy(buffer
, abe
->fcc
, buflen
-1);
171 buffer
[buflen
-1] = '\0';
177 if(pith_opt_save_and_restore
)
178 (*pith_opt_save_and_restore
)(SAR_RESTORE
, &state
);
180 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
183 if(save_nesting_level
)
184 fs_give((void **)&save_nesting_level
);
191 * Given an address, try to find the first address book entry that
192 * matches it and return all the other fields in the passed in pointers.
193 * Caller needs to free the four fields.
194 * Returns -1 if it can't be found, 0 if it is found.
197 get_contactinfo_from_addr(struct mail_address
*adr
, char **nick
, char **full
, char **fcc
, char **comment
)
202 jmp_buf save_jmp_buf
;
203 int *save_nesting_level
;
208 state
.dlc_to_warp_to
= NULL
;
209 copied_adr
= copyaddr(adr
);
211 if(ps_global
->remote_abook_validity
> 0)
212 (void)adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0);
214 save_nesting_level
= cpyint(ab_nesting_level
);
215 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
216 if(setjmp(addrbook_changed_unexpectedly
)){
219 fs_give((void **)&(state
.savep
));
221 fs_give((void **)&(state
.stp
));
222 if(state
.dlc_to_warp_to
)
223 fs_give((void **)&(state
.dlc_to_warp_to
));
225 q_status_message(SM_ORDER
, 3, 5, _("Resetting address book..."));
227 "RESETTING address book... get_contactinfo_from_addr()!\n"));
229 ab_nesting_level
= *save_nesting_level
;
235 if(pith_opt_save_and_restore
)
236 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
238 abe
= address_to_abe(copied_adr
);
241 mail_free_address(&copied_adr
);
244 if(nick
&& abe
->nickname
&& abe
->nickname
[0])
245 *nick
= cpystr(abe
->nickname
);
247 if(full
&& abe
->fullname
&& abe
->fullname
[0])
248 *full
= cpystr(abe
->fullname
);
250 if(fcc
&& abe
->fcc
&& abe
->fcc
[0])
251 *fcc
= cpystr(abe
->fcc
);
253 if(comment
&& abe
->extra
&& abe
->extra
[0])
254 *comment
= cpystr(abe
->extra
);
259 if(pith_opt_save_and_restore
)
260 (*pith_opt_save_and_restore
)(SAR_RESTORE
, &state
);
262 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
265 if(save_nesting_level
)
266 fs_give((void **)&save_nesting_level
);
273 * This is a very special-purpose routine.
274 * It implements the From or Reply-To address is in the Address Book
275 * part of Pattern matching.
278 address_in_abook(MAILSTREAM
*stream
, SEARCHSET
*searchset
,
279 int inabook
, PATTERN_S
*abooks
)
285 ADDRESS
*from
, *reply_to
, *sender
, *to
, *cc
;
286 int is_there
, adrbknum
, *abooklist
= NULL
, positive_match
;
291 jmp_buf save_jmp_buf
;
292 int *save_nesting_level
;
297 /* everything that matches remains a match */
298 if(inabook
== IAB_EITHER
)
303 state
.dlc_to_warp_to
= NULL
;
306 * This may call build_header_line recursively because we may be in
307 * build_header_line now. So we have to preserve and restore the
308 * sequence bits since we want to use them here.
310 savebits
= (char *) fs_get((stream
->nmsgs
+1) * sizeof(char));
312 for(i
= 1L; i
<= stream
->nmsgs
; i
++){
313 if((mc
= mail_elt(stream
, i
)) != NULL
){
314 savebits
[i
] = mc
->sequence
;
320 * Build a searchset so we can look at all the envelopes
321 * we need to look at but only those we need to look at.
322 * Everything with the searched bit set is still a
323 * possibility, so restrict to that set.
326 for(s
= searchset
; s
; s
= s
->next
)
327 for(i
= s
->first
; i
<= s
->last
; i
++)
328 if(i
> 0L && i
<= stream
->nmsgs
329 && (mc
=mail_elt(stream
, i
)) && mc
->searched
){
334 ss
= build_searchset(stream
);
337 * We save the address book state here so we don't have to do it
338 * each time through the loop below.
341 if(ps_global
->remote_abook_validity
> 0)
342 (void)adrbk_check_and_fix_all(ab_nesting_level
== 0, 0, 0);
344 save_nesting_level
= cpyint(ab_nesting_level
);
345 memcpy(save_jmp_buf
, addrbook_changed_unexpectedly
, sizeof(jmp_buf));
346 if(setjmp(addrbook_changed_unexpectedly
)){
348 fs_give((void **)&(state
.savep
));
350 fs_give((void **)&(state
.stp
));
351 if(state
.dlc_to_warp_to
)
352 fs_give((void **)&(state
.dlc_to_warp_to
));
354 q_status_message(SM_ORDER
, 3, 5, _("Resetting address book..."));
356 "RESETTING address book... address_in_abook()!\n"));
358 ab_nesting_level
= *save_nesting_level
;
364 if(pith_opt_save_and_restore
)
365 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
368 abooklist
= (int *) fs_get(as
.n_addrbk
* sizeof(*abooklist
));
369 memset((void *) abooklist
, 0, as
.n_addrbk
* sizeof(*abooklist
));
373 switch(inabook
& IAB_TYPE_MASK
){
376 for(adrbknum
= 0; adrbknum
< as
.n_addrbk
; adrbknum
++)
377 abooklist
[adrbknum
] = 1;
383 /* figure out which address books we're going to look in */
384 for(adrbknum
= 0; adrbknum
< as
.n_addrbk
; adrbknum
++){
385 pab
= &as
.adrbks
[adrbknum
];
387 * For each address book, check all of the address books
388 * in the pattern's list to see if they are it.
390 for(pat
= abooks
; pat
; pat
= pat
->next
){
391 if(!strcmp(pab
->abnick
, pat
->substring
)
392 || !strcmp(pab
->filename
, pat
->substring
)){
393 abooklist
[adrbknum
] = 1;
402 switch(inabook
& IAB_TYPE_MASK
){
418 mail_parameters(NULL
, SET_FETCHLOOKAHEADLIMIT
, (void *) count
);
421 * This causes the lookahead to fetch precisely
422 * the messages we want (in the searchset) instead
423 * of just fetching the next 20 sequential
424 * messages. If the searching so far has caused
425 * a sparse searchset in a large mailbox, the
426 * difference can be substantial.
427 * This resets automatically after the first fetch.
429 sset
= (SEARCHSET
**) mail_parameters(stream
,
436 for(s
= ss
; s
; s
= s
->next
){
437 for(i
= s
->first
; i
<= s
->last
; i
++){
438 if(i
<= 0L || i
> stream
->nmsgs
)
441 e
= pine_mail_fetchenvelope(stream
, i
);
443 from
= e
? e
->from
: NULL
;
444 reply_to
= e
? e
->reply_to
: NULL
;
445 sender
= e
? e
->sender
: NULL
;
446 to
= e
? e
->to
: NULL
;
447 cc
= e
? e
->cc
: NULL
;
450 for(adrbknum
= 0; !is_there
&& adrbknum
< as
.n_addrbk
; adrbknum
++){
451 if(!abooklist
[adrbknum
])
454 pab
= &as
.adrbks
[adrbknum
];
455 is_there
= ((inabook
& IAB_FROM
) && addr_is_in_addrbook(pab
, from
))
456 || ((inabook
& IAB_REPLYTO
) && addr_is_in_addrbook(pab
, reply_to
))
457 || ((inabook
& IAB_SENDER
) && addr_is_in_addrbook(pab
, sender
))
458 || ((inabook
& IAB_TO
) && addr_is_in_addrbook(pab
, to
))
459 || ((inabook
& IAB_CC
) && addr_is_in_addrbook(pab
, cc
));
464 * We matched up until now. If it isn't there, then it
465 * isn't a match. If it is there, leave the searched bit
468 if(!is_there
&& i
> 0L && i
<= stream
->nmsgs
&& (mc
= mail_elt(stream
, i
)))
472 if(is_there
&& i
> 0L && i
<= stream
->nmsgs
&& (mc
= mail_elt(stream
, i
)))
479 if(pith_opt_save_and_restore
)
480 (*pith_opt_save_and_restore
)(SAR_RESTORE
, &state
);
482 memcpy(addrbook_changed_unexpectedly
, save_jmp_buf
, sizeof(jmp_buf));
485 if(save_nesting_level
)
486 fs_give((void **)&save_nesting_level
);
489 /* restore sequence bits */
490 for(i
= 1L; i
<= stream
->nmsgs
; i
++)
491 if((mc
= mail_elt(stream
, i
)) != NULL
)
492 mc
->sequence
= savebits
[i
];
494 fs_give((void **) &savebits
);
497 mail_free_searchset(&ss
);
500 fs_give((void **) &abooklist
);
505 * Given two addresses, check to see if either is in the address book.
506 * Returns 1 if yes, 0 if not found.
509 addr_is_in_addrbook(PerAddrBook
*pab
, struct mail_address
*addr
)
511 AdrBk_Entry
*abe
= NULL
;
513 char abuf
[MAX_ADDR_FIELD
+1];
515 if(!(pab
&& addr
&& addr
->mailbox
))
519 strncpy(abuf
, addr
->mailbox
, sizeof(abuf
)-1);
520 abuf
[sizeof(abuf
)-1] = '\0';
521 if(addr
->host
&& addr
->host
[0]){
522 strncat(abuf
, "@", sizeof(abuf
)-strlen(abuf
)-1);
523 strncat(abuf
, addr
->host
, sizeof(abuf
)-strlen(abuf
)-1);
526 if(pab
->ostatus
!= Open
&& pab
->ostatus
!= NoDisplay
)
527 init_abook(pab
, NoDisplay
);
529 abe
= adrbk_lookup_by_addr(pab
->address_book
, abuf
,
530 (adrbk_cntr_t
*) NULL
);
540 * Look through addrbooks for nickname, opening addrbooks first
541 * if necessary. It is assumed that the caller will restore the
542 * state of the addrbooks if desired.
544 * Args: nickname -- the nickname to lookup
545 * clearrefs -- clear reference bits before lookup
546 * which_addrbook -- If matched, addrbook number it was found in.
547 * not_here -- If non-negative, skip looking in this abook.
549 * Results: A pointer to an AdrBk_Entry is returned, or NULL if not found.
550 * Stop at first match (so order of addrbooks is important).
553 adrbk_lookup_with_opens_by_nick(char *nickname
, int clearrefs
, int *which_addrbook
, int not_here
)
555 AdrBk_Entry
*abe
= (AdrBk_Entry
*)NULL
;
559 dprint((5, "- adrbk_lookup_with_opens_by_nick(%s) -\n",
560 nickname
? nickname
: "?"));
562 for(i
= 0; i
< as
.n_addrbk
; i
++){
569 if(pab
->ostatus
!= Open
&& pab
->ostatus
!= NoDisplay
)
570 init_abook(pab
, NoDisplay
);
573 adrbk_clearrefs(pab
->address_book
);
575 abe
= adrbk_lookup_by_nick(pab
->address_book
,
577 (adrbk_cntr_t
*)NULL
);
582 if(abe
&& which_addrbook
)
590 * Find the addressbook entry that matches the argument address.
591 * Searches through all addressbooks looking for the match.
592 * Opens addressbooks if necessary. It is assumed that the caller
593 * will restore the state of the addrbooks if desired.
595 * Args: addr -- the address we're trying to match
597 * Returns: NULL -- no match found
598 * abe -- a pointer to the addrbook entry that matches
601 address_to_abe(struct mail_address
*addr
)
603 register PerAddrBook
*pab
;
605 AdrBk_Entry
*abe
= NULL
;
608 if(!(addr
&& addr
->mailbox
))
609 return (AdrBk_Entry
*)NULL
;
611 abuf
= (char *)fs_get((MAX_ADDR_FIELD
+ 1) * sizeof(char));
613 strncpy(abuf
, addr
->mailbox
, MAX_ADDR_FIELD
);
614 abuf
[MAX_ADDR_FIELD
] = '\0';
615 if(addr
->host
&& addr
->host
[0]){
616 strncat(abuf
, "@", MAX_ADDR_FIELD
+1-1-strlen(abuf
));
617 strncat(abuf
, addr
->host
, MAX_ADDR_FIELD
+1-1-strlen(abuf
));
620 /* for each addressbook */
621 for(adrbk_number
= 0; adrbk_number
< as
.n_addrbk
; adrbk_number
++){
623 pab
= &as
.adrbks
[adrbk_number
];
625 if(pab
->ostatus
!= Open
&& pab
->ostatus
!= NoDisplay
)
626 init_abook(pab
, NoDisplay
);
628 abe
= adrbk_lookup_by_addr(pab
->address_book
,
630 (adrbk_cntr_t
*)NULL
);
636 fs_give((void **)&abuf
);
643 * Turn an AdrBk_Entry into an address list
645 * Args: abe -- the AdrBk_Entry
646 * dl -- the corresponding dl
647 * abook -- which addrbook the abe is in (only used for type ListEnt)
648 * how_many -- The number of addresses is returned here
650 * Result: allocated address list or NULL
653 abe_to_address(AdrBk_Entry
*abe
, AddrScrn_Disp
*dl
, AdrBk
*abook
, int *how_many
)
655 char *fullname
, *tmp_a_string
;
656 char *list
, *l1
, **l2
;
657 char *fakedomain
= "@";
658 ADDRESS
*addr
= NULL
;
665 fullname
= (abe
->fullname
&& abe
->fullname
[0]) ? abe
->fullname
: NULL
;
669 /* rfc822_parse_adrlist feels free to destroy input so send copy */
670 tmp_a_string
= cpystr(abe
->addr
.addr
);
671 rfc822_parse_adrlist(&addr
, tmp_a_string
, fakedomain
);
674 fs_give((void **)&tmp_a_string
);
676 if(addr
&& fullname
){
678 if(strncmp(addr
->mailbox
, RUN_LDAP
, LEN_RL
) != 0)
679 #endif /* ENABLE_LDAP */
682 fs_give((void **)&addr
->personal
);
684 addr
->personal
= adrbk_formatname(fullname
, NULL
, NULL
);
694 /* rfc822_parse_adrlist feels free to destroy input so send copy */
695 tmp_a_string
= cpystr(listmem_from_dl(abook
, dl
));
696 rfc822_parse_adrlist(&addr
, tmp_a_string
, fakedomain
);
698 fs_give((void **)&tmp_a_string
);
707 for(l2
= abe
->addr
.list
; *l2
; l2
++)
708 length
+= (strlen(*l2
) + 1);
710 list
= (char *)fs_get(length
+ 1);
712 for(l2
= abe
->addr
.list
; *l2
; l2
++){
713 if(l1
!= list
&& length
-(l1
-list
) > 0)
716 strncpy(l1
, *l2
, length
-(l1
-list
));
722 rfc822_parse_adrlist(&addr
, list
, fakedomain
);
724 fs_give((void **)&list
);
729 dprint((1, "default case in abe_to_address, shouldn't happen\n"));
741 * Turn an AdrBk_Entry into a nickname (if it has a nickname) or a
742 * formatted addr_string which has been rfc1522 decoded.
744 * Args: abe -- the AdrBk_Entry
745 * dl -- the corresponding dl
746 * abook -- which addrbook the abe is in (only used for type ListEnt)
748 * Result: allocated string is returned
751 abe_to_nick_or_addr_string(AdrBk_Entry
*abe
, AddrScrn_Disp
*dl
, int abook_num
)
759 if((dl
->type
== Simple
|| dl
->type
== ListHead
)
760 && abe
->nickname
&& abe
->nickname
[0]){
765 * We prefer to pass back the nickname since that allows the
766 * caller to keep track of which entry the address came from.
767 * This is useful in build_address so that the fcc line can
768 * be kept correct. However, if the nickname is also present in
769 * another addressbook then we have to be careful. If that other
770 * addressbook comes before this one then passing back the nickname
771 * will cause the wrong entry to get used. So check for that
772 * and pass back the addr_string in that case.
774 if((fname
= addr_lookup(abe
->nickname
, &which_addrbook
, abook_num
)) != NULL
){
775 fs_give((void **)&fname
);
776 if(which_addrbook
>= abook_num
)
777 return(cpystr(abe
->nickname
));
780 return(cpystr(abe
->nickname
));
783 addr
= abe_to_address(abe
, dl
, as
.adrbks
[abook_num
].address_book
, NULL
);
784 a_string
= addr_list_string(addr
, NULL
, 0); /* always returns a string */
786 mail_free_address(&addr
);
793 * Check to see if address is that of the current user running pine
795 * Args: a -- Address to check
796 * ps -- The pine_state structure
798 * Result: returns 1 if it matches, 0 otherwise.
800 * The mailbox must match the user name and the hostname must match.
801 * In matching the hostname, matches occur if the hostname in the address
802 * is blank, or if it matches the local hostname, or the full hostname
803 * with qualifying domain, or the qualifying domain without a specific host.
804 * Note, there is a very small chance that we will err on the
805 * non-conservative side here. That is, we may decide two addresses are
806 * the same even though they are different (because we do case-insensitive
807 * compares on the mailbox). That might cause a reply not to be sent to
808 * somebody because they look like they are us. This should be very,
811 * It is also considered a match if any of the addresses in alt-addresses
812 * matches a. The check there is simpler. It parses each address in
813 * the list, adding maildomain if there wasn't a domain, and compares
814 * mailbox and host in the ADDRESS's for equality.
817 address_is_us(struct mail_address
*a
, struct pine
*ps
)
823 if(!a
|| a
->mailbox
== NULL
|| !ps
)
826 /* at least LHS must match, but case-independent */
827 else if(strucmp(a
->mailbox
, ps
->VAR_USER_ID
) == 0
829 && /* and hostname matches */
831 /* hostname matches if it's not there, */
833 /* or if hostname and userdomain (the one user sets) match exactly, */
834 ((ps
->userdomain
&& a
->host
&& strucmp(a
->host
,ps
->userdomain
) == 0) ||
837 * or if(userdomain is either not set or it is set to be
838 * the same as the localdomain or hostname) and (the hostname
839 * of the address matches either localdomain or hostname)
841 ((ps
->userdomain
== NULL
||
842 strucmp(ps
->userdomain
, ps
->localdomain
) == 0 ||
843 strucmp(ps
->userdomain
, ps
->hostname
) == 0) &&
844 (strucmp(a
->host
, ps
->hostname
) == 0 ||
845 strucmp(a
->host
, ps
->localdomain
) == 0)))))
849 * If no match yet, check to see if it matches any of the alternate
850 * addresses the user has specified.
852 else if(!ps_global
->VAR_ALT_ADDRS
||
853 !ps_global
->VAR_ALT_ADDRS
[0] ||
854 !ps_global
->VAR_ALT_ADDRS
[0][0])
855 ret
= 0; /* none defined */
859 if(a
&& a
->host
&& a
->mailbox
)
860 snprintf(addrstr
, sizeof(addrstr
), "%s@%s", a
->mailbox
, a
->host
);
864 for(t
= ps_global
->VAR_ALT_ADDRS
; !ret
&& t
[0] && t
[0][0]; t
++){
872 if(F_ON(F_DISABLE_REGEX
, ps_global
) || !contains_regex_special_chars(alt
)){
878 rfc822_parse_adrlist(&alt_addr
, alt2
, ps_global
->maildomain
);
880 fs_give((void **) &alt2
);
882 if(address_is_same(a
, alt_addr
))
886 mail_free_address(&alt_addr
);
889 /* treat alt as a regular expression */
891 if(!(err
=regcomp(®
, alt
, REG_ICASE
| REG_NOSUB
| REG_EXTENDED
))){
892 err
= regexec(®
, addrstr
, 0, NULL
, 0);
895 else if(err
!= REG_NOMATCH
){
896 regerror(err
, ®
, ebuf
, sizeof(ebuf
));
898 dprint((2, "- address_is_us regexec error: %s (%s)", ebuf
, alt
));
904 regerror(err
, ®
, ebuf
, sizeof(ebuf
));
906 dprint((2, "- address_is_us regcomp error: %s (%s)", ebuf
, alt
));
917 * In an ad hoc way try to decide if str is meant to be a regular
918 * expression or not. Dot doesn't count * as regex stuff because
919 * we're worried about addresses.
924 contains_regex_special_chars(char *str
)
926 char special_chars
[] = {'*', '|', '+', '?', '{', '[', '^', '$', '\\', '\0'};
933 * If any of special_chars are in str consider it a regex expression.
935 for(c
= special_chars
; *c
; c
++)
936 if(strindex(str
, *c
))
944 * Compare the two addresses, and return true if they're the same,
947 * Args: a -- First address for comparison
948 * b -- Second address for comparison
950 * Result: returns 1 if it matches, 0 otherwise.
953 address_is_same(struct mail_address
*a
, struct mail_address
*b
)
955 return(a
&& b
&& a
->mailbox
&& b
->mailbox
&& a
->host
&& b
->host
956 && strucmp(a
->mailbox
, b
->mailbox
) == 0
957 && strucmp(a
->host
, b
->host
) == 0);
962 * Returns nonzero if the two address book entries are equal.
963 * Returns zero if not equal.
966 abes_are_equal(AdrBk_Entry
*a
, AdrBk_Entry
*b
)
969 char **alist
, **blist
;
974 ((!a
->nickname
&& !b
->nickname
) ||
975 (a
->nickname
&& b
->nickname
&& strcmp(a
->nickname
,b
->nickname
) == 0)) &&
976 ((!a
->fullname
&& !b
->fullname
) ||
977 (a
->fullname
&& b
->fullname
&& strcmp(a
->fullname
,b
->fullname
) == 0)) &&
978 ((!a
->fcc
&& !b
->fcc
) ||
979 (a
->fcc
&& b
->fcc
&& strcmp(a
->fcc
,b
->fcc
) == 0)) &&
980 ((!a
->extra
&& !b
->extra
) ||
981 (a
->extra
&& b
->extra
&& strcmp(a
->extra
,b
->extra
) == 0))){
983 /* If we made it in here, they still might be equal. */
985 result
= strcmp(a
->addr
.addr
,b
->addr
.addr
) == 0;
987 alist
= a
->addr
.list
;
988 blist
= b
->addr
.list
;
992 /* compare the whole lists */
995 while(addra
&& addrb
&& strcmp(addra
,addrb
) == 0){
1002 if(!addra
&& !addrb
)
1013 * Interface to address book lookups for callers outside or inside this file.
1015 * Args: nickname -- The nickname to look up
1016 * which_addrbook -- If matched, addrbook number it was found in.
1017 * not_here -- If non-negative, skip looking in this abook.
1019 * Result: returns NULL or the corresponding fullname. The fullname is
1020 * allocated here so the caller must free it.
1022 * This opens the address books if they haven't been opened and restores
1023 * them to the state they were in upon entry.
1026 addr_lookup(char *nickname
, int *which_addrbook
, int not_here
)
1032 dprint((9, "- addr_lookup(%s) -\n",nickname
? nickname
: "nil"));
1034 init_ab_if_needed();
1036 if(pith_opt_save_and_restore
)
1037 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
1039 abe
= adrbk_lookup_with_opens_by_nick(nickname
,0,which_addrbook
,not_here
);
1041 fullname
= (abe
&& abe
->fullname
) ? cpystr(abe
->fullname
) : NULL
;
1043 if(pith_opt_save_and_restore
)
1044 (*pith_opt_save_and_restore
)(SAR_RESTORE
, &state
);
1051 * Look in all of the address books for all of the possible entries
1052 * that match the query string. The matches can be for the nickname,
1053 * for the fullname, or for the address@host part of the address.
1054 * All of the matches are at the starts of the strings, not a general
1055 * substring match. This is not true anymore. Fullname matches can be
1056 * at the start of the fullname or starting after a space in the fullname.
1057 * If flags has ALC_INCLUDE_LDAP defined then LDAP
1058 * entries are added to the end of the list. The LDAP queries are done
1059 * only for those servers that have the 'impl' feature turned on, which
1060 * means that lookups should be done implicitly. This feature also
1061 * controls whether or not lookups should be done when typing carriage
1062 * return (instead of this which is TAB).
1064 * Args query -- What the user has typed so far
1066 * Returns a list of possibilities for the given query string.
1068 * Caller needs to free the answer.
1071 adrbk_list_of_completions(char *query
, MAILSTREAM
*stream
, imapuid_t uid
, int flags
)
1076 ABOOK_ENTRY_S
*list
, *list2
, *biglist
= NULL
;
1077 COMPLETE_S
*return_list
= NULL
, *last_one_added
= NULL
, *new, *cp
, *dp
, *dprev
;
1081 char *newaddr
= NULL
, *simple_addr
= NULL
, *fcc
= NULL
;
1082 ENVELOPE
*env
= NULL
;
1085 init_ab_if_needed();
1087 if(pith_opt_save_and_restore
)
1088 (*pith_opt_save_and_restore
)(SAR_SAVE
, &state
);
1090 for(i
= 0; i
< as
.n_addrbk
; i
++){
1092 pab
= &as
.adrbks
[i
];
1094 if(pab
->ostatus
!= Open
&& pab
->ostatus
!= NoDisplay
)
1095 init_abook(pab
, NoDisplay
);
1097 list
= adrbk_list_of_possible_completions(pab
? pab
->address_book
: NULL
, query
);
1098 combine_abook_entry_lists(&biglist
, list
);
1102 * Eliminate duplicates by NO_NEXTing the entrynums.
1104 for(list
= biglist
; list
; list
= list
->next
)
1105 /* eliminate any dups further along in the list */
1106 if(list
->entrynum
!= NO_NEXT
)
1107 for(list2
= list
->next
; list2
; list2
= list2
->next
)
1108 if(list2
->entrynum
== list
->entrynum
){
1109 list2
->entrynum
= NO_NEXT
;
1110 list
->matches_bitmap
|= list2
->matches_bitmap
;
1113 /* build the return list */
1114 for(list
= biglist
; list
; list
= list
->next
)
1115 if(list
->entrynum
!= NO_NEXT
){
1118 toaddr
.arg
.abe
= adrbk_get_ae(list
->ab
, list
->entrynum
);
1119 if(our_build_address(toaddr
, &newaddr
, NULL
, &fcc
, NULL
) == 0){
1120 char *reverse_fullname
= NULL
;
1123 * ALC_FULL is a regular FullName match and that will be
1124 * captured in the full_address field. If there was also
1125 * an ALC_REVFULL match that means that the user has the
1126 * FullName entered in their addrbook as Last, First and
1127 * that is where the match was. We want to put that in
1128 * the completions structure in the rev_fullname field.
1130 if(list
->matches_bitmap
& ALC_REVFULL
1132 && toaddr
.arg
.abe
->fullname
&& toaddr
.arg
.abe
->fullname
[0]
1133 && toaddr
.arg
.abe
->fullname
[0] != '"'
1134 && strindex(toaddr
.arg
.abe
->fullname
, ',') != NULL
){
1136 reverse_fullname
= toaddr
.arg
.abe
->fullname
;
1139 if(flags
& ALC_INCLUDE_ADDRS
){
1140 if(toaddr
.arg
.abe
&& toaddr
.arg
.abe
->tag
== Single
1141 && toaddr
.arg
.abe
->addr
.addr
&& toaddr
.arg
.abe
->addr
.addr
[0]){
1143 char *fakedomain
= "@";
1145 tmp_a_string
= cpystr(toaddr
.arg
.abe
->addr
.addr
);
1147 rfc822_parse_adrlist(&addr
, tmp_a_string
, fakedomain
);
1149 fs_give((void **) &tmp_a_string
);
1152 if(addr
->mailbox
&& addr
->host
1153 && !(addr
->host
[0] == '@' && addr
->host
[1] == '\0'))
1154 simple_addr
= simple_addr_string(addr
, buf
, sizeof(buf
));
1156 mail_free_address(&addr
);
1161 new = new_complete_s(toaddr
.arg
.abe
? toaddr
.arg
.abe
->nickname
: NULL
,
1162 newaddr
, simple_addr
, reverse_fullname
, fcc
,
1163 list
->matches_bitmap
| ALC_ABOOK
);
1165 /* add to end of list */
1166 if(return_list
== NULL
){
1168 last_one_added
= new;
1171 last_one_added
->next
= new;
1172 last_one_added
= new;
1177 fs_give((void **) &newaddr
);
1180 if(pith_opt_save_and_restore
)
1181 (*pith_opt_save_and_restore
)(SAR_RESTORE
, &state
);
1183 free_abook_entry_s(&biglist
);
1186 if(flags
& ALC_INCLUDE_LDAP
){
1187 LDAP_SERV_RES_S
*head_of_result_list
= NULL
, *res
;
1192 memset(&wp_err
, 0, sizeof(wp_err
));
1195 * This lookup covers all servers with the impl bit set.
1196 * It uses the regular LDAP search parameters that the
1197 * user has set, not necessarily just a prefix match
1198 * like the rest of the address completion above.
1200 head_of_result_list
= ldap_lookup_all_work(query
, as
.n_serv
, 0, NULL
, &wp_err
);
1201 for(res
= head_of_result_list
; res
; res
= res
->next
){
1202 for(e
= ldap_first_entry(res
->ld
, res
->res
);
1204 e
= ldap_next_entry(res
->ld
, e
)){
1205 simple_addr
= newaddr
= NULL
;
1207 cs
.selected_entry
= e
;
1208 cs
.info_used
= res
->info_used
;
1209 cs
.serv
= res
->serv
;
1210 addr
= address_from_ldap(&cs
);
1212 add_addr_to_return_list(addr
, ALC_LDAP
, query
, flags
, &return_list
);
1213 mail_free_address(&addr
);
1219 fs_give((void **) &wp_err
.error
);
1221 if(head_of_result_list
)
1222 free_ldap_result_list(&head_of_result_list
);
1224 #endif /* ENABLE_LDAP */
1226 /* add from current message */
1227 if(uid
> 0 && stream
)
1228 env
= pine_mail_fetch_structure(stream
, uid
, &body
, FT_UID
);
1230 /* from the envelope addresses */
1232 for(addr
= env
->from
; addr
; addr
= addr
->next
)
1233 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1235 for(addr
= env
->reply_to
; addr
; addr
= addr
->next
)
1236 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1238 for(addr
= env
->sender
; addr
; addr
= addr
->next
)
1239 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1241 for(addr
= env
->to
; addr
; addr
= addr
->next
)
1242 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1244 for(addr
= env
->cc
; addr
; addr
= addr
->next
)
1245 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1248 * May as well search the body for addresses.
1249 * Use this function written for TakeAddr.
1252 TA_S
*talist
= NULL
, *tp
;
1254 if(grab_addrs_from_body(stream
, mail_msgno(stream
,uid
), body
, &talist
) > 0){
1257 /* rewind to start */
1259 talist
= talist
->prev
;
1261 for(tp
= talist
; tp
; tp
= tp
->next
){
1264 add_addr_to_return_list(addr
, ALC_CURR
, query
, flags
, &return_list
);
1267 free_talines(&talist
);
1275 * Check for and eliminate some duplicates.
1276 * The criteria for deciding what is a duplicate is
1279 for(cp
= return_list
; cp
; cp
= cp
->next
)
1280 for(dprev
= cp
, dp
= cp
->next
; dp
; ){
1281 if(cp
->full_address
&& dp
->full_address
1282 && !strucmp(dp
->full_address
, cp
->full_address
)
1283 && (((cp
->matches_bitmap
& ALC_ABOOK
)
1284 && (dp
->matches_bitmap
& ALC_ABOOK
)
1285 && (!(dp
->matches_bitmap
& ALC_NICK
&& dp
->nickname
&& dp
->nickname
[0])
1286 || ((!cp
->addr
&& !dp
->addr
) || (cp
->addr
&& dp
->addr
&& !strucmp(cp
->addr
, dp
->addr
)))))
1288 (dp
->matches_bitmap
& ALC_CURR
)
1290 (dp
->matches_bitmap
& ALC_LDAP
1291 && dp
->matches_bitmap
& (ALC_FULL
| ALC_ADDR
))
1293 (cp
->matches_bitmap
== dp
->matches_bitmap
1294 && (!(dp
->matches_bitmap
& ALC_NICK
&& dp
->nickname
&& dp
->nickname
[0])
1295 || (dp
->nickname
&& cp
->nickname
1296 && !strucmp(cp
->nickname
, dp
->nickname
)))))){
1298 * dp is equivalent to cp so eliminate dp
1300 dprev
->next
= dp
->next
;
1302 free_complete_s(&dp
);
1310 return(return_list
);
1315 add_addr_to_return_list(ADDRESS
*addr
, unsigned bitmap
, char *query
,
1316 int flags
, COMPLETE_S
**return_list
)
1319 char *newaddr
= NULL
;
1320 char *simple_addr
= NULL
;
1321 COMPLETE_S
*new = NULL
, *cp
;
1324 if(return_list
&& query
&& addr
&& addr
->mailbox
&& addr
->host
){
1326 savenext
= addr
->next
;
1328 newaddr
= addr_list_string(addr
, NULL
, 0);
1329 addr
->next
= savenext
;
1332 * If the start of the full_address actually matches the query
1333 * string then mark this as ALC_FULL. This might be helpful
1334 * when deciding on the longest unambiguous match.
1336 if(newaddr
&& newaddr
[0] && !struncmp(newaddr
, query
, strlen(query
)))
1339 if(newaddr
&& newaddr
[0] && flags
& ALC_INCLUDE_ADDRS
){
1340 if(addr
->mailbox
&& addr
->host
1341 && !(addr
->host
[0] == '@' && addr
->host
[1] == '\0'))
1342 simple_addr
= simple_addr_string(addr
, buf
, sizeof(buf
));
1344 if(simple_addr
&& !simple_addr
[0])
1347 if(simple_addr
&& !struncmp(simple_addr
, query
, strlen(query
)))
1352 * We used to require && bitmap & (ALC_FULL | ALC_ADDR) before
1353 * we would add a match but we think that we should match
1354 * other stuff that matches (like middle names), too, unless we
1355 * are adding an address from the current message.
1357 if((newaddr
&& newaddr
[0])
1358 && (!(bitmap
& ALC_CURR
) || bitmap
& (ALC_FULL
| ALC_ADDR
))){
1359 new = new_complete_s(NULL
, newaddr
, simple_addr
, NULL
, NULL
, bitmap
);
1361 /* add to end of list */
1362 if(*return_list
== NULL
){
1366 for(cp
= *return_list
; cp
->next
; cp
= cp
->next
)
1374 fs_give((void **) &newaddr
);
1381 * full = whole thing, like Some Body <someb@there.org>
1382 * addr = address part, like someb@there.org
1385 new_complete_s(char *nick
, char *full
, char *addr
,
1386 char *rev_fullname
, char *fcc
, unsigned matches_bitmap
)
1388 COMPLETE_S
*new = NULL
;
1390 new = (COMPLETE_S
*) fs_get(sizeof(*new));
1391 memset((void *) new, 0, sizeof(*new));
1392 new->nickname
= nick
? cpystr(nick
) : NULL
;
1393 new->full_address
= full
? cpystr(full
) : NULL
;
1394 new->addr
= addr
? cpystr(addr
) : NULL
;
1395 new->rev_fullname
= rev_fullname
? cpystr(rev_fullname
) : NULL
;
1396 new->fcc
= fcc
? cpystr(fcc
) : NULL
;
1397 new->matches_bitmap
= matches_bitmap
;
1404 free_complete_s(COMPLETE_S
**compptr
)
1406 if(compptr
&& *compptr
){
1407 if((*compptr
)->next
)
1408 free_complete_s(&(*compptr
)->next
);
1410 if((*compptr
)->nickname
)
1411 fs_give((void **) &(*compptr
)->nickname
);
1413 if((*compptr
)->full_address
)
1414 fs_give((void **) &(*compptr
)->full_address
);
1416 if((*compptr
)->addr
)
1417 fs_give((void **) &(*compptr
)->addr
);
1419 if((*compptr
)->rev_fullname
)
1420 fs_give((void **) &(*compptr
)->rev_fullname
);
1423 fs_give((void **) &(*compptr
)->fcc
);
1425 fs_give((void **) compptr
);
1431 new_abook_entry_s(AdrBk
*ab
, a_c_arg_t numarg
, unsigned bit
)
1433 ABOOK_ENTRY_S
*new = NULL
;
1434 adrbk_cntr_t entrynum
;
1436 entrynum
= (adrbk_cntr_t
) numarg
;
1438 new = (ABOOK_ENTRY_S
*) fs_get(sizeof(*new));
1439 memset((void *) new, 0, sizeof(*new));
1441 new->entrynum
= entrynum
;
1442 new->matches_bitmap
= bit
;
1449 free_abook_entry_s(ABOOK_ENTRY_S
**aep
)
1453 free_abook_entry_s(&(*aep
)->next
);
1455 fs_give((void **) aep
);
1461 * Add the second list to the end of the first.
1464 combine_abook_entry_lists(ABOOK_ENTRY_S
**first
, ABOOK_ENTRY_S
*second
)
1473 for(sl
= *first
; sl
->next
; sl
= sl
->next
)
1485 adrbk_list_of_possible_completions(AdrBk
*ab
, char *prefix
)
1487 ABOOK_ENTRY_S
*list
= NULL
, *biglist
= NULL
;
1493 list
= adrbk_list_of_possible_trie_completions(ab
->nick_trie
, ab
, prefix
, ALC_NICK
);
1494 combine_abook_entry_lists(&biglist
, list
);
1498 list
= adrbk_list_of_possible_trie_completions(ab
->full_trie
, ab
, prefix
, ALC_FULL
);
1499 combine_abook_entry_lists(&biglist
, list
);
1503 list
= adrbk_list_of_possible_trie_completions(ab
->addr_trie
, ab
, prefix
, ALC_ADDR
);
1504 combine_abook_entry_lists(&biglist
, list
);
1507 if(ab
->revfull_trie
){
1508 list
= adrbk_list_of_possible_trie_completions(ab
->revfull_trie
, ab
, prefix
, ALC_REVFULL
);
1509 combine_abook_entry_lists(&biglist
, list
);
1517 * Look in this address book for all nicknames, addresses, or fullnames
1518 * which begin with the prefix prefix, and return an allocated
1522 adrbk_list_of_possible_trie_completions(AdrBk_Trie
*trie
, AdrBk
*ab
, char *prefix
,
1526 char *p
, *lookthisup
;
1528 ABOOK_ENTRY_S
*list
= NULL
;
1530 if(!ab
|| !prefix
|| !trie
)
1535 /* make lookup case independent */
1537 for(p
= prefix
; *p
&& !(*p
& 0x80) && islower((unsigned char) *p
); p
++)
1541 strncpy(buf
, prefix
, sizeof(buf
));
1542 buf
[sizeof(buf
)-1] = '\0';
1543 for(p
= buf
; *p
; p
++)
1544 if(!(*p
& 0x80) && isupper((unsigned char) *p
))
1550 lookthisup
= prefix
;
1555 /* search for character at this level */
1556 while(t
->value
!= *p
){
1557 if(t
->right
== NULL
)
1558 return(list
); /* no match */
1563 if(*++p
== '\0') /* matched through end of prefix */
1566 /* need to go down to match next character */
1567 if(t
->down
== NULL
) /* no match */
1574 * If we get here that means we found at least
1575 * one entry that matches up through prefix.
1576 * Gather_abook_list recursively adds the nicknames starting at
1579 if(t
->entrynum
!= NO_NEXT
){
1581 * Add it to the list.
1583 list
= new_abook_entry_s(ab
, t
->entrynum
, bit
);
1586 gather_abook_entry_list(ab
, t
->down
, prefix
, &list
, bit
);
1593 gather_abook_entry_list(AdrBk
*ab
, AdrBk_Trie
*node
, char *prefix
, ABOOK_ENTRY_S
**list
, unsigned bit
)
1595 char *next_prefix
= NULL
;
1597 ABOOK_ENTRY_S
*newlist
= NULL
;
1600 if(node
->entrynum
!= NO_NEXT
|| node
->down
|| node
->right
){
1601 l
= strlen(prefix
? prefix
: "");
1602 if(node
->entrynum
!= NO_NEXT
){
1604 * Add it to the list.
1606 newlist
= new_abook_entry_s(ab
, node
->entrynum
, bit
);
1607 combine_abook_entry_lists(list
, newlist
);
1610 /* same prefix for node->right */
1612 gather_abook_entry_list(ab
, node
->right
, prefix
, list
, bit
);
1614 /* prefix is one longer for node->down */
1616 next_prefix
= (char *) fs_get((l
+2) * sizeof(char));
1617 strncpy(next_prefix
, prefix
? prefix
: "", l
+2);
1618 next_prefix
[l
] = node
->value
;
1619 next_prefix
[l
+1] = '\0';
1620 gather_abook_entry_list(ab
, node
->down
, next_prefix
, list
, bit
);
1623 fs_give((void **) &next_prefix
);