1
2 static char rcsid[] = "@(#)$Id: answer.c,v 1.5 1999/03/24 14:04:12 wfp5p Exp $";
3
4 /*******************************************************************************
5 * The Elm Mail System - $Revision: 1.5 $ $State: Exp $
6 *
7 * Copyright (c) 1988-1995 USENET Community Trust
8 * Copyright (c) 1986,1987 Dave Taylor
9 *******************************************************************************
10 * Bug reports, patches, comments, suggestions should be sent to:
11 *
12 * Bill Pemberton, Elm Coordinator
13 * flash@virginia.edu
14 *
15 *******************************************************************************
16 * $Log: answer.c,v $
17 * Revision 1.5 1999/03/24 14:04:12 wfp5p
18 * elm 2.5PL0
19 *
20 * Revision 1.4 1996/03/14 17:30:06 wfp5p
21 * Alpha 9
22 *
23 * Revision 1.3 1995/09/29 17:42:41 wfp5p
24 * Alpha 8 (Chip's big changes)
25 *
26 * Revision 1.2 1995/04/20 21:02:04 wfp5p
27 * Added the showreply feature and emacs key bindings.
28 *
29 * Revision 1.1.1.1 1995/04/19 20:38:40 wfp5p
30 * Initial import of elm 2.4 PL0 as base for elm 2.5.
31 *
32 ******************************************************************************/
33
34 /** This program is a phone message transcription system, and
35 is designed for secretaries and the like, to allow them to
36 painlessly generate electronic mail instead of paper forms.
37
38 Note: this program ONLY uses the local alias file, and does not
39 even read in the system alias file at all.
40
41 **/
42
43 #define INTERN
44 #include "elm_defs.h"
45 #include "s_answer.h"
46 #include "ndbz.h"
47
48 #define ELM "elm" /* where the elm program lives */
49
50 int user_data; /* fileno of user data file */
51 DBZ *hash; /* dbz file for same */
52
53 char *get_alias_address(), *get_token(), *strip_parens(), *shift_lower();
54 static void open_alias_file(void);
55
56 static const char *quit_word, *exit_word, *done_word, *bye_word;
57
main(argc,argv)58 main(argc, argv)
59 int argc;
60 char *argv[];
61 {
62 FILE *fd;
63 char *address, buffer[LONG_STRING], tempfile[SLEN], *cp;
64 char name[SLEN], recip_name[SLEN], in_line[SLEN];
65 int msgnum = 0, eof, allow_name = 0, phone_slip = 0;
66 int ans_pid = getpid();
67
68 initialize_common();
69
70 quit_word = catgets(elm_msg_cat, AnswerSet, AnswerQuitWord, "quit");
71 exit_word = catgets(elm_msg_cat, AnswerSet, AnswerExitWord, "exit");
72 done_word = catgets(elm_msg_cat, AnswerSet, AnswerDoneWord, "done");
73 bye_word = catgets(elm_msg_cat, AnswerSet, AnswerByeWord, "bye");
74 /*
75 * simplistic crack arguments, looking for -u/-p
76 * -u = allow user names not in alias table
77 * -p = prompt for phone slip messages
78 */
79 for (msgnum = 1; msgnum < argc; msgnum++) {
80 if (istrcmp(argv[msgnum], "-u") == 0)
81 allow_name = 1;
82 if (istrcmp(argv[msgnum], "-p") == 0)
83 phone_slip = 1;
84 if (istrcmp(argv[msgnum], "-pu") == 0) {
85 allow_name = 1;
86 phone_slip = 1;
87 }
88 if (istrcmp(argv[msgnum], "-up") == 0) {
89 allow_name = 1;
90 phone_slip = 1;
91 }
92 }
93
94 open_alias_file();
95
96 while (1) {
97 if (msgnum > 9999) msgnum = 0;
98
99 printf("\n-------------------------------------------------------------------------------\n");
100
101 prompt: printf(catgets(elm_msg_cat, AnswerSet, AnswerMessageTo, "\nMessage to: "));
102 if (fgets(recip_name, SLEN, stdin) == NULL) {
103 putchar('\n');
104 exit(0);
105 }
106 if(recip_name[0] == '\0')
107 goto prompt;
108
109 cp = &recip_name[strlen(recip_name)-1];
110 if(*cp == '\n') *cp = '\0';
111 if(recip_name[0] == '\0')
112 goto prompt;
113
114 if ((istrcmp(recip_name, quit_word) == 0) ||
115 (istrcmp(recip_name, exit_word) == 0) ||
116 (istrcmp(recip_name, done_word) == 0) ||
117 (istrcmp(recip_name, bye_word) == 0))
118 exit(0);
119
120 if (translate(recip_name, name) == 0)
121 goto prompt;
122
123 address = get_alias_address(name, 1, 0);
124
125 if (address == NULL || strlen(address) == 0) {
126 if (allow_name)
127 address = name;
128 else {
129 printf(catgets(elm_msg_cat, AnswerSet, AnswerSorryNotFound,
130 "Sorry, could not find '%s' [%s] in list!\n"),
131 recip_name, name);
132 goto prompt;
133 }
134 }
135
136 printf("address '%s'\n", address);
137
138 sprintf(tempfile, "%sans.%d.%d", default_temp, ans_pid, msgnum++);
139
140 if ((fd = fopen(tempfile,"w")) == NULL)
141 exit(printf(catgets(elm_msg_cat, AnswerSet, AnswerCouldNotOpenWrite,
142 "** Fatal Error: could not open %s to write\n"),
143 tempfile));
144
145
146 /** Enter standard phone message fields **/
147 if (phone_slip) {
148 strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerCaller, "Caller: "));
149 printf("\n%s",buffer);
150 fflush(stdout);
151 fgets(in_line, SLEN, stdin);
152 if (strlen(in_line) > 1)
153 fprintf(fd,"%s%s",buffer,in_line);
154
155 strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerOf, "of: "));
156 printf("%s",buffer);
157 fflush(stdout);
158 fgets(in_line, SLEN, stdin);
159 if (strlen(in_line) > 1)
160 fprintf(fd,"%s%s",buffer,in_line);
161
162 strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerPhone, "Phone: "));
163 printf("%s",buffer);
164 fflush(stdout);
165 fgets(in_line, SLEN, stdin);
166 if (strlen(in_line) > 1)
167 fprintf(fd,"%s%s\n",buffer,in_line);
168
169 strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerTelephoned, "TELEPHONED - "));
170 printf("\n%s",buffer);
171 fflush(stdout);
172 fgets(in_line, SLEN, stdin);
173 if (strlen(in_line) > 1)
174 fprintf(fd,"%s%s",buffer,in_line);
175
176 strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerCalledToSeeYou, "CALLED TO SEE YOU - "));
177 printf("%s",buffer);
178 fflush(stdout);
179 fgets(in_line, SLEN, stdin);
180 if (strlen(in_line) > 1)
181 fprintf(fd,"%s%s",buffer,in_line);
182
183 strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerWantsToSeeYou, "WANTS TO SEE YOU - "));
184 printf("%s",buffer);
185 fflush(stdout);
186 fgets(in_line, SLEN, stdin);
187 if (strlen(in_line) > 1)
188 fprintf(fd,"%s%s",buffer,in_line);
189
190 strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerReturnedYourCall, "RETURNED YOUR CALL - "));
191 printf("%s",buffer);
192 fflush(stdout);
193 fgets(in_line, SLEN, stdin);
194 if (strlen(in_line) > 1)
195 fprintf(fd,"%s%s",buffer,in_line);
196
197 strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerPleaseCall, "PLEASE CALL - "));
198 printf("%s",buffer);
199 fflush(stdout);
200 fgets(in_line, SLEN, stdin);
201 if (strlen(in_line) > 1)
202 fprintf(fd,"%s%s",buffer,in_line);
203
204 strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerWillCallAgain, "WILL CALL AGAIN - "));
205 printf("%s",buffer);
206 fflush(stdout);
207 fgets(in_line, SLEN, stdin);
208 if (strlen(in_line) > 1)
209 fprintf(fd,"%s%s",buffer,in_line);
210
211 strcpy(buffer, catgets(elm_msg_cat, AnswerSet, AnswerUrgent, "*****URGENT****** - "));
212 printf("%s",buffer);
213 fflush(stdout);
214 fgets(in_line, SLEN, stdin);
215 if (strlen(in_line) > 1)
216 fprintf(fd,"%s%s",buffer,in_line);
217 }
218
219 printf(catgets(elm_msg_cat, AnswerSet, AnswerEnterMessage,
220 "\n\nEnter message for %s ending with a blank line.\n\n"),
221 recip_name);
222
223 fprintf(fd,"\n\n");
224
225 do {
226 printf("> ");
227 if (! (eof = (fgets(buffer, SLEN, stdin) == NULL)))
228 fprintf(fd, "%s", buffer);
229 } while (! eof && strlen(buffer) > 1);
230
231 fclose(fd);
232
233 sprintf(buffer, catgets(elm_msg_cat, AnswerSet, AnswerElmCommand,
234 "( ( %s -s \"While You Were Out\" %s < %s ; %s %s) & ) > /dev/null"),
235 ELM, strip_parens(address), tempfile, remove_cmd, tempfile);
236
237 system(buffer);
238 }
239 }
240
241 int
translate(fullname,name)242 translate(fullname, name)
243 char *fullname, *name;
244 {
245 /** translate fullname into name..
246 'first last' translated to first_initial - underline - last
247 'initial last' translated to initial - underline - last
248 Return 0 if error.
249 **/
250 register int i, lastname = 0, len;
251
252 for (i=0, len = strlen(fullname); i < len; i++) {
253
254 fullname[i] = tolower(fullname[i]);
255
256 if (fullname[i] == ' ')
257 if (lastname) {
258 printf(catgets(elm_msg_cat, AnswerSet, AnswerCannotHaveMoreNames,
259 "** Can't have more than 'FirstName LastName' as address!\n"));
260 return(0);
261 }
262 else
263 lastname = i+1;
264
265 }
266
267 if (lastname)
268 sprintf(name, "%c_%s", fullname[0], (char *) fullname + lastname);
269 else
270 strcpy(name, fullname);
271
272 return(1);
273 }
274
275 static void
open_alias_file()276 open_alias_file()
277 {
278 /** open the user alias file **/
279
280 char fname[SLEN];
281
282 sprintf(fname, "%s/.elm/aliases", getenv("HOME"));
283
284 if ((hash = dbz_open(fname, O_RDONLY, 0)) == NULL)
285 exit(printf("** Fatal Error: Could not open %s!\n", fname));
286
287 if ((user_data = open(fname, O_RDONLY)) == -1)
288 return;
289 }
290
get_alias_address(name,mailing,depth)291 char *get_alias_address(name, mailing, depth)
292 char *name;
293 int mailing, depth;
294 {
295 /** return the line from either datafile that corresponds
296 to the specified name. If 'mailing' specified, then
297 fully expand group names. Returns NULL if not found.
298 Depth is the nesting depth, and varies according to the
299 nesting level of the routine. **/
300
301 static char buffer[VERY_LONG_STRING];
302 static char sprbuffer[VERY_LONG_STRING];
303 datum key, value;
304 int loc;
305 struct alias_disk_rec entry;
306
307 name = shift_lower(name);
308 key.dptr = name;
309 key.dsize = strlen(name);
310 value = dbz_fetch(hash, key);
311 if (value.dptr == NULL)
312 return( (char *) NULL); /* not found */
313
314 bcopy(value.dptr, (char *) &loc, sizeof(loc));
315 loc -= sizeof(entry);
316 lseek(user_data, loc, SEEK_SET);
317 read(user_data, (char *) &entry, sizeof(entry));
318 read(user_data, buffer, entry.length > VERY_LONG_STRING ? VERY_LONG_STRING : entry.length);
319 if ((entry.type & GROUP) != 0 && mailing) {
320 if (expand_group(sprbuffer, buffer + entry.address,
321 depth) < 0)
322 return NULL;
323 } else {
324 sprintf(sprbuffer, "%s (%s)", buffer + entry.address,
325 buffer + entry.name);
326 }
327 return sprbuffer;
328 }
329
expand_group(target,members,depth)330 int expand_group(target, members, depth)
331 char *target;
332 char *members;
333 int depth;
334 {
335 /** given a group of names separated by commas, this routine
336 will return a string that is the full addresses of each
337 member separated by spaces. Depth is the current recursion
338 depth of the expansion (for the 'get_token' routine) **/
339
340 char buf[VERY_LONG_STRING], *word, *address, *bufptr;
341
342 strcpy(buf, members); /* parameter safety! */
343 target[0] = '\0'; /* nothing in yet! */
344 bufptr = (char *) buf; /* grab the address */
345 depth++; /* one more deeply into stack */
346
347 while ((word = (char *) get_token(bufptr, "!, ", depth)) != NULL) {
348 if ((address = (char *) get_alias_address(word, 1, depth)) == NULL) {
349 fprintf(stderr, catgets(elm_msg_cat, AnswerSet, AnswerNotFoundForGroup,
350 "Alias %s not found for group expansion!\n"), word);
351 return -1;
352 }
353 else if (strcmp(target,address) != 0) {
354 sprintf(target + strlen(target), " %s", address);
355 }
356
357 bufptr = NULL;
358 }
359 return 0;
360 }
361
print_long(buffer,init_len)362 print_long(buffer, init_len)
363 char *buffer;
364 int init_len;
365 {
366 /** print buffer out, 80 characters (or less) per line, for
367 as many lines as needed. If 'init_len' is specified,
368 it is the length that the first line can be.
369 **/
370
371 register int i, loc=0, space, length, len;
372
373 /* In general, go to 80 characters beyond current character
374 being processed, and then work backwards until space found! */
375
376 length = init_len;
377
378 do {
379 if (strlen(buffer) > loc + length) {
380 space = loc + length;
381 while (buffer[space] != ' ' && space > loc + 50) space--;
382 for (i=loc;i <= space;i++)
383 putchar(buffer[i]);
384 putchar('\n');
385 loc = space;
386 }
387 else {
388 for (i=loc, len = strlen(buffer);i < len;i++)
389 putchar(buffer[i]);
390 putchar('\n');
391 loc = len;
392 }
393 length = 80;
394 } while (loc < strlen(buffer));
395 }
396
397 /****
398 The following is a newly chopped version of the 'strtok' routine
399 that can work in a recursive way (up to 20 levels of recursion) by
400 changing the character buffer to an array of character buffers....
401 ****/
402
403 #define MAX_RECURSION 20 /* up to 20 deep recursion */
404
405 #undef NULL
406 #define NULL (char *) 0 /* for this routine only */
407
408
get_token(string,sepset,depth)409 char *get_token(string, sepset, depth)
410 char *string, *sepset;
411 int depth;
412 {
413
414 /** string is the string pointer to break up, sepstr are the
415 list of characters that can break the line up and depth
416 is the current nesting/recursion depth of the call **/
417
418 register char *p, *q, *r;
419 static char *savept[MAX_RECURSION];
420
421 /** is there space on the recursion stack? **/
422
423 if (depth >= MAX_RECURSION) {
424 fprintf(stderr, catgets(elm_msg_cat, AnswerSet, AnswerRecursionTooDeep,
425 "Error: Get_token calls nested greater than %d deep!\n"),
426 MAX_RECURSION);
427 exit(1);
428 }
429
430 /* set up the pointer for the first or subsequent call */
431 p = (string == NULL)? savept[depth]: string;
432
433 if(p == 0) /* return if no tokens remaining */
434 return(NULL);
435
436 q = p + strspn(p, sepset); /* skip leading separators */
437
438 if (*q == '\0') /* return if no tokens remaining */
439 return(NULL);
440
441 if ((r = strpbrk(q, sepset)) == NULL) /* move past token */
442 savept[depth] = 0; /* indicate this is last token */
443 else {
444 *r = '\0';
445 savept[depth] = ++r;
446 }
447 return(q);
448 }
449