1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2  *@ Names (read: addresses), including `alternates' and `alias' lists.
3  *@ TODO It should be solely that, parsing etc. should be in header.c,
4  *@ TODO or rfc5322.c or something like this.
5  *
6  * Copyright (c) 2012 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
7  * SPDX-License-Identifier: ISC
8  *
9  * Permission to use, copy, modify, and/or distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 #ifndef mx_NAMES_H
22 #define mx_NAMES_H /* XXX a lie - it is rather n_ yet */
23 
24 #include <mx/nail.h>
25 
26 #define mx_HEADER
27 #include <su/code-in.h>
28 
29 struct mx_name;
30 
31 enum mx_name_flags{
32    mx_NAME_SKINNED = 1u<<0, /* Has been skin()ned */
33    mx_NAME_IDNA = 1u<<1, /* IDNA has been applied */
34    mx_NAME_NAME_SALLOC = 1u<<2, /* .n_name in detached memory */
35 
36    mx_NAME_ADDRSPEC_ISFILE = 1u<<3, /* ..is a file path */
37    mx_NAME_ADDRSPEC_ISPIPE = 1u<<4, /* ..is a command for piping */
38    mx_NAME_ADDRSPEC_ISFILEORPIPE = mx_NAME_ADDRSPEC_ISFILE |
39          mx_NAME_ADDRSPEC_ISPIPE,
40    mx_NAME_ADDRSPEC_ISNAME = 1u<<5, /* ..is an alias name */
41    mx_NAME_ADDRSPEC_ISADDR = 1u<<6, /* ..is a mail network address.. */
42    mx_NAME_ADDRSPEC_ISMASK = su_BITENUM_MASK(3,6),
43    mx_NAME_ADDRSPEC_WITHOUT_DOMAIN = 1u<<7, /* ISADDR: without domain name */
44 
45    /* Bits not values for easy & testing */
46    mx_NAME_ADDRSPEC_ERR_EMPTY = 1u<<9, /* An empty string (or NIL) */
47    mx_NAME_ADDRSPEC_ERR_ATSEQ = 1u<<10, /* Weird @ sequence */
48    mx_NAME_ADDRSPEC_ERR_CHAR = 1u<<11, /* Invalid character */
49    mx_NAME_ADDRSPEC_ERR_IDNA = 1u<<12, /* IDNA conversion failed */
50    mx_NAME_ADDRSPEC_ERR_NAME = 1u<<13, /* Alias with invalid content */
51    mx_NAME_ADDRSPEC_INVALID = mx_NAME_ADDRSPEC_ERR_EMPTY |
52          mx_NAME_ADDRSPEC_ERR_ATSEQ | mx_NAME_ADDRSPEC_ERR_CHAR |
53          mx_NAME_ADDRSPEC_ERR_IDNA | mx_NAME_ADDRSPEC_ERR_NAME,
54 
55    /* Error storage (we must fit in 31-bit!) */
56    mx__NAME_SHIFTWC = 14,
57    mx__NAME_MAXWC = 0x1FFFF,
58    mx__NAME_MASKWC = mx__NAME_MAXWC << mx__NAME_SHIFTWC
59    /* Bit 31 (32) == S32_MIN temporarily used */
60 };
61 
62 struct mx_name{
63    struct mx_name *n_flink;
64    struct mx_name *n_blink;
65    enum gfield n_type; /* Header field this comes from */
66    u32 n_flags; /* enum mx_name_flags */
67    char *n_name;
68    char *n_fullname; /* .n_name, unless GFULL: +comments, etc */
69    char *n_fullextra; /* GFULL, without address */
70 };
71 
72 /* In the !_ERR_EMPTY case, the failing character can be queried */
mx_name_flags_get_err_wc(u32 flags)73 INLINE s32 mx_name_flags_get_err_wc(u32 flags){
74    return (((flags & mx__NAME_MASKWC) >> mx__NAME_SHIFTWC) & mx__NAME_MAXWC);
75 }
76 
77 /* ..where err is mx_name_flags (mix) */
mx_name_flags_set_err(u32 flags,u32 err,s32 e_wc)78 INLINE u32 mx_name_flags_set_err(u32 flags, u32 err, s32 e_wc){
79    return ((flags & ~(mx_NAME_ADDRSPEC_INVALID | mx__NAME_MASKWC)) |
80       S(u32,err) | ((S(u32,e_wc) & mx__NAME_MAXWC) << mx__NAME_SHIFTWC));
81 }
82 
83 /* Allocate a single element of a name list, initialize its name field to the
84  * passed name and return it.
85  * May return NULL with GNULL_OK (only, unfortunately) */
86 EXPORT struct mx_name *nalloc(char const *str, enum gfield ntype);
87 
88 /* Alloc an Fcc: entry TODO temporary only i hope */
89 EXPORT struct mx_name *nalloc_fcc(char const *file);
90 
91 /* Like nalloc(), but initialize from content of np */
92 EXPORT struct mx_name *ndup(struct mx_name *np, enum gfield ntype);
93 
94 /* Concatenate the two passed name lists, return the result */
95 EXPORT struct mx_name *cat(struct mx_name *n1, struct mx_name *n2);
96 
97 /* Duplicate np */
98 EXPORT struct mx_name *n_namelist_dup(struct mx_name const *np,
99       enum gfield ntype);
100 
101 /* Determine the number of undeleted elements in a name list and return it;
102  * the latter also doesn't count file and pipe addressees in addition */
103 EXPORT u32 count(struct mx_name const *np);
104 EXPORT u32 count_nonlocal(struct mx_name const *np);
105 
106 /* Extract a list of names from a line, and make a list of names from it.
107  * Return the list or NULL if none found */
108 EXPORT struct mx_name *extract(char const *line, enum gfield ntype);
109 
110 /* Like extract() unless line contains anyof ",\"\\(<|", in which case
111  * comma-separated list extraction is used instead */
112 EXPORT struct mx_name *lextract(char const *line, enum gfield ntype);
113 
114 /* Interprets the entire line as one address: identical to extract() and
115  * lextract() but only returns one (or none) name.
116  * GSKIN will be added to ntype as well as GNULL_OK: may return NULL! */
117 EXPORT struct mx_name *n_extract_single(char const *line, enum gfield ntype);
118 
119 /* Turn a list of names into a string of the same names */
120 EXPORT char *detract(struct mx_name *np, enum gfield ntype);
121 
122 /* Get a lextract() list via n_go_input_cp(), reassigning to *np* */
123 EXPORT struct mx_name *grab_names(enum n_go_input_flags gif, char const *field,
124       struct mx_name *np, int comma, enum gfield gflags);
125 
126 /* Check whether n1 & n2 are the same address, effectively.
127  * Takes *allnet* into account */
128 EXPORT boole mx_name_is_same_address(struct mx_name const *n1,
129       struct mx_name const *n2);
130 
131 /* Check whether n1 & n2 share the domain name */
132 EXPORT boole mx_name_is_same_domain(struct mx_name const *n1,
133       struct mx_name const *n2);
134 
135 /* Check all addresses in np and delete invalid ones; if set_on_error is not
136  * NULL it'll be set to TRU1 for error or -1 for "hard fail" error */
137 EXPORT struct mx_name *checkaddrs(struct mx_name *np,
138       enum expand_addr_check_mode eacm, s8 *set_on_error);
139 
140 /* Vaporise all duplicate addresses in hp (.h_(to|cc|bcc)) so that an address
141  * that "first" occurs in To: is solely in there, ditto Cc:, after expanding
142  * aliases etc.  eacm and set_on_error are passed to checkaddrs().
143  * After updating hp to the new state this returns a flat list of all
144  * addressees, which may be NIL */
145 EXPORT struct mx_name *n_namelist_vaporise_head(struct header *hp,
146       boole metoo, boole strip_alternates,
147       enum expand_addr_check_mode eacm, s8 *set_on_error);
148 
149 /* Map all of the aliased users in the invoker's mailrc file and insert them
150  * into the list */
151 EXPORT struct mx_name *usermap(struct mx_name *names, boole force_metoo);
152 
153 /* Remove all of the duplicates from the passed name list by insertion sorting
154  * them, then checking for dups.  Return the head of the new list */
155 EXPORT struct mx_name *elide(struct mx_name *names);
156 
157 /* `(un)?alias' */
158 EXPORT int c_alias(void *vp);
159 EXPORT int c_unalias(void *vp);
160 
161 /* Is name a valid alias name (as opposed to: "is an alias") */
162 EXPORT boole mx_alias_is_valid_name(char const *name);
163 
164 /* `(un)?alternates' deal with the list of alternate names */
165 EXPORT int c_alternates(void *vp);
166 EXPORT int c_unalternates(void *vp);
167 
168 /* If keep_single is set one alternates member will be allowed in np */
169 EXPORT struct mx_name *mx_alternates_remove(struct mx_name *np,
170       boole keep_single);
171 
172 /* Likewise, is name an alternate in broadest sense? */
173 EXPORT boole mx_name_is_mine(char const *name);
174 
175 #include <su/code-ou.h>
176 #endif /* mx_NAMES_H */
177 /* s-it-mode */
178