2 * Copyright 1987 by the Massachusetts Institute of Technology. For copying
3 * and distribution information, see the file "mit-copyright.h".
12 static char *rcsid_chpobox_c = "$Header$";
16 * Talk to the SMS database to change a person's home mail machine. This may
17 * be an Athena machine, or a completely arbitrary address.
19 * chpobox with no modifiers reports all current mailboxes.
21 * chpobox -a [address] means add (not replace) a mailbox to the ones
22 * the user already has. Complains if the user tries to give herself
23 * more than one mailbox of type pop.
25 * chpobox -d [address] means delete the specified mailbox from the list.
26 * Complains if this would mean leaving the user with no mailbox at all.
28 * chpobox -u [user] is needed if you are logged in as one user, but
29 * are trying to change the email address of another. You must have
30 * Kerberos tickets as the person whose address you are trying to
31 * change, or the attempt will fail.
33 * [address] must always have an @ sign in it.
37 #include <sys/types.h>
48 #include "mit-copyright.h"
63 static struct pobox_values boxes[MAXBOX];
64 static int nboxes = 0;
68 #define DOMAIN ".MIT.EDU"
69 #define NET_ADDRESS_SIZE 500 /* You would not believe the length of some
76 struct pobox_values getnewmach(), pobox;
77 char *smsarg[1], buf[BUFSIZ];
78 char *ds(), *trim(), *in(), *canon();
79 char *address, *uname, *machine;
80 char **return_args, **crunch_pobox_args();
82 int get_machine(), scream();
83 int c, delflag, add, usageflag;
90 c = delflag = add = usageflag = 0;
91 address = uname = (char *) NULL;
94 if ((whoami = rindex(argv[0], '/')) == NULL)
103 while ((c = getopt(argc, argv, "d:a:u:")) != EOF)
111 address = ds(optarg);
119 address = ds(optarg);
129 if (argc == 2 && optind == 1 && !uname) {
130 uname = argv[optind++];
132 if (usageflag || optind != argc) {
136 if ((uname = getlogin()) == NULL) {
139 if (uname[0] == '\0') {
140 pwd = getpwuid((int) u);
141 (void) strcpy(uname, pwd->pw_name);
146 status = sms_connect();
148 (void) sprintf(buf, "\nConnection to SMS server failed.");
154 (void) sprintf(buf, "\nAuthorization failed -- please \
155 run \"kinit\" and try again.");
160 * set up some bogus arguments to feed to sms_access
163 pobox.type = "FOREIGN";
165 pobox.machine = "baz.bat.quux";
166 return_args = crunch_pobox_args(pobox);
168 * do an access check.
170 status = sms_access("add_pobox", 4, return_args);
172 (void) sprintf(buf, "\nUnauthorized attempt to modify %s's \
173 email address.", uname);
178 * get a list of current boxes
180 status = sms_query("get_pobox", 1, smsarg, get_machine, NULL);
181 if (status && status != SMS_NO_MATCH) {
182 com_err(whoami, status, "while retrieving current mailboxes\n");
187 * address, if it exists, is of form user@host. It needs to be split up.
190 machine = index(address, '@');
192 *machine++ = '\0'; /* get rid of the @ sign */
193 machine = trim(machine); /* get rid of whitespace */
196 fprintf(stderr, "%s: no at sign (@) in address\n",
200 } /* now machine points to the machine name,
201 * and address points to the "box" name */
202 pobox.machine = canon(machine); /* canonicalize the machine name */
203 if (pobox.machine == (char *) NULL) {/* nameserver failed in canon */
204 (void) sprintf(buf, "\nNameserver lookup \
205 failed.\nI cannot change your mailbox at this time. Please try again \
209 pobox.type = in(pobox.machine); /* find out the type */
210 pobox.login = uname; /* whose is changing? */
211 pobox.box = address; /* to what mailbox? */
215 if (strcmp(pobox.type, "pop") == 0) {
218 * check to be sure that they're not getting more than one. If
221 for (i = 0; i < nboxes; i++) {
222 if (!strcmp(boxes[i].type, "POP")) {
223 printf("%s already has a pobox on %s\n",
224 uname, boxes[i].machine);
229 printf("Adding email address %s@%s for %s.",
230 pobox.box, pobox.machine, uname);
232 return_args = crunch_pobox_args(pobox);
233 status = sms_query("add_pobox", 4, return_args, scream,
236 (void) sprintf(buf, "\nWrite failed to SMS \
245 /* check to make sure that the
246 * user isn't being left without a mailbox. */
248 printf("That would leave %s without a mailbox\n", uname);
251 printf("Deleting email address %s@%s for %s.", pobox.box,
252 pobox.machine, uname);
253 return_args = crunch_pobox_args(pobox);
254 status = sms_query("delete_pobox", 4, return_args, scream,
257 (void) sprintf(buf, "\nWrite failed to SMS \
266 printf("Current mail address%s for %s %s:\n",
267 nboxes < 2 ? "" : "es",
269 nboxes < 2 ? "is" : "are");
274 for (i = 0; i < nboxes; i++)
275 printf(" type: %s, address: %s@%s\n", boxes[i].type,
276 boxes[i].box, boxes[i].machine);
284 com_err(whoami, status, buf);
291 com_err(whoami, status, "Unexpected return value from SMS -- \
292 programmer botch\n");
298 * get_machine gets all your poboxes and displays them.
303 get_machine(argc, argv, callarg)
305 char **argv, *callarg;
307 struct pobox_values *pobox = &boxes[nboxes++];
309 pobox->type = ds(argv[1]);
310 pobox->machine = ds(argv[2]);
311 pobox->box = ds(argv[3]);
320 register char *newstr = malloc((unsigned) strlen(str) + 1);
322 if (newstr == (char *) NULL)
323 return ((char *) NULL);
325 return (strcpy(newstr, str));
329 crunch_pobox_args(in)
330 struct pobox_values in;
334 out = (char **) malloc((unsigned) sizeof(char *) * 4);
343 * Trim whitespace off of cp. Side-effects cp.
357 for (--ep; isspace(*ep); --ep)
366 * given a canonicalized machine name, ask the SMS server if it is of type
367 * pop, or of type local -- if neither, we assume that it's of type foreign.
373 char *service[1], buf[BUFSIZ];
377 service[0] = ds("pop");
378 status = sms_query("get_server_locations", 1, service,
379 check_match, machine);
380 if (status && (status != SMS_NO_MATCH)) {
381 (void) sprintf(buf, "\nRead failed from SMS \
388 service[0] = ds("local");
389 status = sms_query("get_server_locations", 1, service,
390 check_match, machine);
391 if (status && (status != SMS_NO_MATCH)) {
392 (void) sprintf(buf, "\nRead failed from SMS \
401 com_err(whoami, status, buf);
408 check_match(argc, argv, callback)
410 char **argv, *callback;
415 if (strcmp(argv[1], callback) == 0)
422 * given a machine name, canonicalize it and return it. Returns (char *)
423 * NULL if the nameserver returns any error.
429 struct hostent *hostinfo;
431 hostinfo = gethostbyname(machine);
432 if (hostinfo != (struct hostent *) NULL)
433 machine = ds(hostinfo->h_name);
434 else /* gethostbyname failed; this should be very
435 * rare, since we're dealing with local
436 * hosts, so no fancy error recovery.
438 machine = (char *) NULL;
444 fprintf(stderr, "Usage: %s [-d|a address] [-u user]\n", whoami);
452 * c-continued-statement-offset: 4
454 * c-argdecl-indent: 4