]> diplodocus.org Git - nmh/blob - sbr/addrsbr.c
Just reworded the bit about '%s' being safe not to quote (it's only safe not to
[nmh] / sbr / addrsbr.c
1
2 /*
3 * addrsbr.c -- parse addresses 822-style
4 *
5 * $Id$
6 */
7
8 #include <h/mh.h>
9 #include <h/addrsbr.h>
10 #include <zotnet/mf/mf.h>
11
12 /* High level parsing of addresses:
13
14 The routines in zotnet/mf/mf.c parse the syntactic representations of
15 addresses. The routines in sbr/addrsbr.c associate semantics with those
16 addresses.
17
18 If #ifdef DUMB is in effect, a full 822-style parser is called
19 for syntax recongition. This breaks each address into its components.
20 Note however that no semantics are assumed about the parts or their
21 totality. This means that implicit hostnames aren't made explicit,
22 and explicit hostnames aren't expanded to their "official" represenations.
23
24 If DUMB is not in effect, then this module does some
25 high-level thinking about what the addresses are.
26
27 1. for MMDF systems:
28
29 string%<uucp>@<local> -> string
30
31 2. for non-MMDF systems:
32
33 string@host.<uucp> -> host!string
34
35 3. for any system, an address interpreted relative to the local host:
36
37 string@<uucp> -> string
38
39 For cases (1) and (3) above, the leftmost host is extracted. If it's not
40 present, the local host is used. If the tests above fail, the address is
41 considered to be a real 822-style address.
42
43 If an explicit host is not present, then MH checks for a bang to indicate
44 an explicit UUCP-style address. If so, this is noted. If not, the host is
45 defaulted, typically to the local host. The lack of an explict host is
46 also noted.
47
48 If an explicit 822-style host is present, then MH checks to see if it
49 can expand this to the official name for the host. If the hostname is
50 unknown, the address is so typed.
51
52 To summarize, when we're all done, here's what MH knows about the address:
53
54 DUMB - type: local, uucp, or network
55 host: not locally defaulted, not explicitly expanded
56 everything else
57
58 other - type: local, uucp, network, unknown
59 everything else
60 */
61
62
63 static int ingrp = 0;
64 static char *pers = NULL;
65 static char *mbox = NULL;
66 static char *host = NULL;
67 static char *route = NULL;
68 static char *grp = NULL;
69 static char *note = NULL;
70 static char err[BUFSIZ];
71 static char adr[BUFSIZ];
72
73
74 extern boolean username_extension_masquerading; /* defined in mts.c */
75
76
77 /*
78 * external prototypes
79 */
80 char *getusername (void);
81
82
83 char *
84 getname (char *addrs)
85 {
86 struct adrx *ap;
87
88 pers = mbox = host = route = grp = note = NULL;
89 err[0] = '\0';
90
91 if ((ap = getadrx (addrs ? addrs : "")) == NULL)
92 return NULL;
93
94 strncpy (adr, ap->text, sizeof(adr));
95 pers = ap->pers;
96 mbox = ap->mbox;
97 host = ap->host;
98 route = ap->path;
99 grp = ap->grp;
100 ingrp = ap->ingrp;
101 note = ap->note;
102 if (ap->err && *ap->err)
103 strncpy (err, ap->err, sizeof(err));
104
105 return adr;
106 }
107
108
109 struct mailname *
110 getm (char *str, char *dfhost, int dftype, int wanthost, char *eresult)
111 {
112 char *pp;
113 struct mailname *mp;
114 #ifndef DUMB
115 char *dp;
116 #endif /* not DUMB */
117
118 if (err && err[0]) {
119 if (eresult)
120 strcpy (eresult, err);
121 else
122 if (wanthost == AD_HOST)
123 admonish (NULL, "bad address '%s' - %s", str, err);
124 return NULL;
125 }
126 if (pers == NULL
127 && mbox == NULL && host == NULL && route == NULL
128 && grp == NULL) {
129 if (eresult)
130 strcpy (eresult, "null address");
131 else
132 if (wanthost == AD_HOST)
133 admonish (NULL, "null address '%s'", str);
134 return NULL;
135 }
136 if (mbox == NULL && grp == NULL) {
137 if (eresult)
138 strcpy (eresult, "no mailbox in address");
139 else
140 if (wanthost == AD_HOST)
141 admonish (NULL, "no mailbox in address '%s'", str);
142 return NULL;
143 }
144
145 if (dfhost == NULL) {
146 dfhost = LocalName ();
147 dftype = LOCALHOST;
148 }
149
150 mp = (struct mailname *) calloc ((size_t) 1, sizeof(*mp));
151 if (mp == NULL) {
152 if (eresult)
153 strcpy (eresult, "insufficient memory to represent address");
154 else
155 if (wanthost == AD_HOST)
156 adios (NULL, "insufficient memory to represent address");
157 return NULL;
158 }
159
160 mp->m_next = NULL;
161 mp->m_text = getcpy (str);
162 if (pers)
163 mp->m_pers = getcpy (pers);
164
165 if (mbox == NULL) {
166 mp->m_type = BADHOST;
167 mp->m_nohost = 1;
168 mp->m_ingrp = ingrp;
169 mp->m_gname = getcpy (grp);
170 if (note)
171 mp->m_note = getcpy (note);
172 return mp;
173 }
174
175 if (host) {
176 mp->m_mbox = getcpy (mbox);
177 mp->m_host = getcpy (host);
178 }
179 else {
180 if ((pp = strchr(mbox, '!'))) {
181 *pp++ = '\0';
182 mp->m_mbox = getcpy (pp);
183 mp->m_host = getcpy (mbox);
184 mp->m_type = UUCPHOST;
185 }
186 else {
187 mp->m_nohost = 1;
188 mp->m_mbox = getcpy (mbox);
189 #ifdef DUMB
190 if (route == NULL && dftype == LOCALHOST) {
191 mp->m_host = NULL;
192 mp->m_type = dftype;
193 }
194 else
195 #endif /* DUMB */
196 {
197 mp->m_host = route ? NULL : getcpy (dfhost);
198 mp->m_type = route ? NETHOST : dftype;
199 }
200 }
201 goto got_host;
202 }
203
204 if (wanthost == AD_NHST)
205 mp->m_type = !strcasecmp (LocalName (), mp->m_host)
206 ? LOCALHOST : NETHOST;
207 #ifdef DUMB
208 else
209 mp->m_type = strcasecmp (LocalName(), mp->m_host) ? NETHOST : LOCALHOST;
210 #else /* not DUMB */
211 else
212 if (pp = OfficialName (mp->m_host)) {
213 got_real_host: ;
214 free (mp->m_host);
215 mp->m_host = getcpy (pp);
216 mp->m_type = strcasecmp (LocalName(), mp->m_host) ? NETHOST : LOCALHOST;
217 }
218 else {
219 if (dp = strchr(mp->m_host, '.')) {
220 *dp = NULL;
221 if (pp = OfficialName (mp->m_host))
222 goto got_real_host;
223 *dp = '.';
224 }
225 mp->m_type = BADHOST;
226 }
227 #endif /* not DUMB */
228
229 got_host: ;
230 if (route)
231 mp->m_path = getcpy (route);
232 mp->m_ingrp = ingrp;
233 if (grp)
234 mp->m_gname = getcpy (grp);
235 if (note)
236 mp->m_note = getcpy (note);
237
238 return mp;
239 }
240
241
242 void
243 mnfree (struct mailname *mp)
244 {
245 if (!mp)
246 return;
247
248 if (mp->m_text)
249 free (mp->m_text);
250 if (mp->m_pers)
251 free (mp->m_pers);
252 if (mp->m_mbox)
253 free (mp->m_mbox);
254 if (mp->m_host)
255 free (mp->m_host);
256 if (mp->m_path)
257 free (mp->m_path);
258 if (mp->m_gname)
259 free (mp->m_gname);
260 if (mp->m_note)
261 free (mp->m_note);
262
263 free ((char *) mp);
264 }
265
266
267 #define empty(s) ((s) ? (s) : "")
268
269 char *
270 auxformat (struct mailname *mp, int extras)
271 {
272 static char addr[BUFSIZ];
273 static char buffer[BUFSIZ];
274
275 #ifdef DUMB
276 if (mp->m_nohost)
277 strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
278 else
279 #endif /* DUMB */
280
281 #ifndef BANG
282 if (mp->m_type != UUCPHOST)
283 snprintf (addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
284 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
285 else
286 #endif /* not BANG */
287 snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
288
289 if (!extras)
290 return addr;
291
292 if (mp->m_pers || mp->m_path) {
293 if (mp->m_note)
294 snprintf (buffer, sizeof(buffer), "%s %s <%s>",
295 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
296 mp->m_note, addr);
297 else
298 snprintf (buffer, sizeof(buffer), "%s <%s>",
299 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
300 addr);
301 }
302 else
303 if (mp->m_note)
304 snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
305 else
306 strncpy (buffer, addr, sizeof(buffer));
307
308 return buffer;
309 }
310
311
312 /*
313 * address specific "sprintf"
314 */
315
316 char *
317 adrsprintf (char *username, char *domain)
318 {
319 int snprintf_return;
320 static char addr[BUFSIZ];
321
322 if (username == NULL)
323 username = getusername();
324
325 if (username_extension_masquerading) {
326 /* mts.conf contains "masquerade:[...]username_extension[...]", so tack
327 on the value of the $USERNAME_EXTENSION environment variable, if set,
328 to username. */
329 char* extension = getenv("USERNAME_EXTENSION");
330 static char username_with_extension[BUFSIZ];
331
332 if (extension != NULL && *extension != '\0') {
333 snprintf_return = snprintf(username_with_extension,
334 sizeof(username_with_extension),
335 "%s%s", username, extension);
336
337 if (snprintf_return < 0 ||
338 snprintf_return >= sizeof(username_with_extension))
339 adios(NULL, "snprintf() error writing username (%d chars) and"
340 " $USERNAME_EXTENSION (%d chars) to array of BUFSIZ (%d)"
341 " chars",
342 strlen(username), strlen(extension), BUFSIZ);
343
344 username = username_with_extension;
345 }
346 }
347
348 #ifdef REALLYDUMB
349 return username;
350 #endif
351
352 if (domain == NULL)
353 domain = LocalName();
354
355 #ifndef BANG
356 snprintf_return = snprintf (addr, sizeof(addr), "%s@%s", username, domain);
357 #else /* BANG */
358 snprintf_return = snprintf (addr, sizeof(addr), "%s!%s", domain, username);
359 #endif /* BANG */
360
361 if (snprintf_return < 0 || snprintf_return >= sizeof(addr))
362 adios(NULL, "snprintf() error writing username (%d chars), domain (%d"
363 " chars), and 1 separator char to array of BUFSIZ (%d) chars",
364 strlen(username), strlen(domain), BUFSIZ);
365
366 return addr;
367 }
368
369
370 #define W_NIL 0x0000
371 #define W_MBEG 0x0001
372 #define W_MEND 0x0002
373 #define W_MBOX (W_MBEG | W_MEND)
374 #define W_HBEG 0x0004
375 #define W_HEND 0x0008
376 #define W_HOST (W_HBEG | W_HEND)
377 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
378
379 /*
380 * Check if this is my address
381 */
382
383 int
384 ismymbox (struct mailname *np)
385 {
386 int oops;
387 register int len, i;
388 register char *cp;
389 register char *pp;
390 char buffer[BUFSIZ];
391 struct mailname *mp;
392 static char *am = NULL;
393 static struct mailname mq={NULL};
394
395 /*
396 * If this is the first call, initialize
397 * list of alternate mailboxes.
398 */
399 if (am == NULL) {
400 mq.m_next = NULL;
401 mq.m_mbox = getusername ();
402 if ((am = context_find ("alternate-mailboxes")) == NULL)
403 am = getusername();
404 else {
405 mp = &mq;
406 oops = 0;
407 while ((cp = getname (am))) {
408 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
409 admonish (NULL, "illegal address: %s", cp);
410 oops++;
411 } else {
412 mp = mp->m_next;
413 mp->m_type = W_NIL;
414 if (*mp->m_mbox == '*') {
415 mp->m_type |= W_MBEG;
416 mp->m_mbox++;
417 }
418 if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
419 mp->m_type |= W_MEND;
420 *cp = '\0';
421 }
422 if (mp->m_host) {
423 if (*mp->m_host == '*') {
424 mp->m_type |= W_HBEG;
425 mp->m_host++;
426 }
427 if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
428 mp->m_type |= W_HEND;
429 *cp = '\0';
430 }
431 }
432 if ((cp = getenv ("MHWDEBUG")) && *cp)
433 fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
434 mp->m_mbox, mp->m_host,
435 snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
436 }
437 }
438 if (oops)
439 advise (NULL, "please fix the %s: entry in your %s file",
440 "alternate-mailboxes", mh_profile);
441 }
442 }
443
444 if (np == NULL) /* XXX */
445 return 0;
446
447 switch (np->m_type) {
448 case NETHOST:
449 len = strlen (cp = LocalName ());
450 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
451 break;
452 goto local_test;
453
454 case UUCPHOST:
455 if (strcasecmp (np->m_host, SystemName()))
456 break; /* fall */
457 case LOCALHOST:
458 local_test: ;
459 if (!strcasecmp (np->m_mbox, mq.m_mbox))
460 return 1;
461 break;
462
463 default:
464 break;
465 }
466
467 /*
468 * Now scan through list of alternate
469 * mailboxes, and check for a match.
470 */
471 for (mp = &mq; mp->m_next;) {
472 mp = mp->m_next;
473 if (!np->m_mbox)
474 continue;
475 if ((len = strlen (cp = np->m_mbox))
476 < (i = strlen (pp = mp->m_mbox)))
477 continue;
478 switch (mp->m_type & W_MBOX) {
479 case W_NIL:
480 if (strcasecmp (cp, pp))
481 continue;
482 break;
483 case W_MBEG:
484 if (strcasecmp (cp + len - i, pp))
485 continue;
486 break;
487 case W_MEND:
488 if (!uprf (cp, pp))
489 continue;
490 break;
491 case W_MBEG | W_MEND:
492 if (stringdex (pp, cp) < 0)
493 continue;
494 break;
495 }
496
497 if (mp->m_nohost)
498 return 1;
499 if (np->m_host == NULL)
500 continue;
501 if ((len = strlen (cp = np->m_host))
502 < (i = strlen (pp = mp->m_host)))
503 continue;
504 switch (mp->m_type & W_HOST) {
505 case W_NIL:
506 if (strcasecmp (cp, pp))
507 continue;
508 break;
509 case W_HBEG:
510 if (strcasecmp (cp + len - i, pp))
511 continue;
512 break;
513 case W_HEND:
514 if (!uprf (cp, pp))
515 continue;
516 break;
517 case W_HBEG | W_HEND:
518 if (stringdex (pp, cp) < 0)
519 continue;
520 break;
521 }
522 return 1;
523 }
524
525 return 0;
526 }