1 | /***************************************
2 | $Revision: 1.7 $
3 |
4 | AK (Acknowledgement) module
5 |
6 | Status: REVIEWED, NOT TESTED
7 |
8 | Author(s): Engin Gunduz
9 |
10 | ******************/ /******************
11 | Modification History:
12 | engin (10/06/2000) Created.
13 | denis (25/09/2001) modified for new API
14 | ******************/ /******************
15 | Copyright (c) 2000,2001,2002 RIPE NCC
16 |
17 | All Rights Reserved
18 |
19 | Permission to use, copy, modify, and distribute this software and its
20 | documentation for any purpose and without fee is hereby granted,
21 | provided that the above copyright notice appear in all copies and that
22 | both that copyright notice and this permission notice appear in
23 | supporting documentation, and that the name of the author not be
24 | used in advertising or publicity pertaining to distribution of the
25 | software without specific, written prior permission.
26 |
27 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
28 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
29 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
30 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
31 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
32 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 | ***************************************/
34 |
35 |
36 |
37 | #include "ack.h"
38 | extern int supress_ack_notif;
39 | extern char * humailbox;
40 | extern char * failuretxt;
41 | extern char * helpheader;
42 | extern char * successtxt;
43 | extern char * defmail;
44 | extern char * acksig;
45 | extern up_subject_struct subject_result;
46 | extern int count_successful;
47 | extern int count_unsuccessful;
48 | extern char *netupdclientIP;
49 |
50 | extern int reading_from_mail;
51 | extern int networkupdate;
52 |
53 | /* web update flags */
54 | extern int webupdate;
55 | extern int help_requested;
56 | extern int enforced_new;
57 |
58 | /*
59 |
60 | AK_add_to_ack: writes a message to the acknowledgement file.
61 | Also, prints it out to the stdout if it was a networkupdate
62 | (networkupdate is run through inetd, so stdout is our socket)
63 |
64 | */
65 |
66 | void AK_add_to_ack(const char * filename, char * fmt, ...){
67 |
68 | va_list ap; /* points to each unnamed arg in turn */
69 | char *p, *sval;
70 | int ival;
71 | double dval;
72 | FILE * ack_file;
73 |
74 | if(( ack_file = fopen(filename, "a")) == NULL){
75 | fprintf(stderr, "Can't open ack file, %s", filename);
76 | }
77 |
78 |
79 | /* if this is a network update, print it out first to the
80 | stdout (which is socket) */
81 | if(networkupdate){
82 | va_start(ap, fmt);
83 | vprintf(fmt, ap);
84 | fflush(stdout);
85 | va_end(ap);
86 | }
87 |
88 | /* and then to the file */
89 | va_start(ap, fmt);
90 |
91 | for(p = fmt; *p; p++){
92 | if (*p != '%') {
93 | fprintf(ack_file, "%c", *p);
94 | continue;
95 | }
96 | switch(*++p) {
97 | case 'd':
98 | ival = va_arg(ap, int);
99 | fprintf(ack_file, "%d", ival);
100 | break;
101 | case 'f':
102 | dval = va_arg(ap, double);
103 | fprintf(ack_file, "%f", dval);
104 | break;
105 | case 'X':
106 | ival = va_arg(ap, int);
107 | fprintf(ack_file, "%X", ival);
108 | break;
109 | case 'x':
110 | ival = va_arg(ap, int);
111 | fprintf(ack_file, "%x", ival);
112 | break;
113 | case 's':
114 | sval = va_arg(ap, char *);
115 | fprintf(ack_file, "%s", sval);
116 | break;
117 | default:
118 | putchar(*p);
119 | break;
120 | }
121 | }
122 |
123 | va_end(ap); /* clean up */
124 | fclose(ack_file);
125 | }
126 |
127 |
128 |
129 | /* Adds a complete file to the ack file */
130 |
131 | void AK_add_file_to_ack(const char * ackfile, const char * filetoadd){
132 |
133 | FILE * ack_file, * file_to_add;
134 | char buf[1024];
135 |
136 | if(( ack_file = fopen(ackfile, "a")) == NULL){
137 | fprintf(stderr, "AK_add_file_to_ack: Can't open ack file, %s\n", ackfile);
138 | }
139 |
140 | if(( file_to_add = fopen(filetoadd, "r")) == NULL){
141 |
142 | fprintf(stderr, "AK_add_file_to_ack: Can't open file, %s\n", filetoadd);
143 | fprintf(ack_file, "\nHelp file could not be found.\nPlease notify the database administrator.\n");
144 | fclose(ack_file);
145 | free(buf);
146 |
147 | }else{
148 |
149 | while(fgets(buf, 1023, file_to_add) != NULL){
150 | fprintf(ack_file, "%s", buf);
151 | }
152 |
153 | fclose(ack_file);
154 | fclose(file_to_add);
155 | }
156 | }
157 |
158 |
159 | /*
160 |
161 | AK_ack_file_name_generate: Generates a unique name for temporary acknowledgement
162 | files, and also creates it.
163 |
164 | tmpdir: temporary directory (without a trailing '/')
165 | prefix: prefix for the temp file
166 |
167 | returns: the generated name.
168 | */
169 |
170 | char * AK_ack_file_name_generate( const char * tmpdir, const char * prefix)
171 | {
172 | FILE * ack_file;
173 | char * name;
174 |
175 | /* allocate space for name. 32 should be enough for PID */
176 | name = (char*)malloc(strlen(tmpdir) + strlen(prefix) + 35);
177 |
178 | sprintf(name, "%s/%s.%i", tmpdir, prefix, (int)(getpid()) );
179 |
180 | /* create the file */
181 | if (( ack_file = fopen(name, "w")) == NULL)
182 | {
183 | fprintf(stderr, "Can't open ack file, %s", name);
184 | }
185 |
186 | /* close it */
187 | fclose(ack_file);
188 |
189 | return name;
190 | }
191 |
192 |
193 | /*
194 |
195 | AK_send_ack: post-processes and sends the ack message contained in the temp file.
196 |
197 |
198 | */
199 |
200 | void AK_send_ack( const char * filename, const char * to_address, const char * mailercommand)
201 | {
202 | char * mail_command_line = NULL;
203 | char * supress_file = NULL, * temp_file = NULL;
204 | FILE * ack_file, * supr_file_hdl, * temp_file_hdl;
205 | char *txt_replaced;
206 | char buf[1024];
207 |
208 | /* first check if we the user specified some non-keyword words in
209 | the subject line (in addition to some valid keywords)
210 | If so, we will add a warning to the ack file */
211 | if (subject_result.result == UP_SUBJ_UNRECOG)
212 | {
213 | if (( ack_file = fopen(filename, "a")) == NULL)
214 | {
215 | fprintf(stderr, "Can't open ack file for appending, %s", filename);
216 | }
217 | else
218 | {
219 | fprintf(ack_file, "\nWarning: unknown keywords found in subject line:\n"
220 | "%s\n"
221 | "Thus, all keywords in subject line were ignored.\n",
222 | subject_result.word_list ? subject_result.word_list : "" );
223 | fclose(ack_file);
224 | }
225 |
226 | /* and now check if the user specified an invalid combination of keywords
227 | in the subject line, and if so, print an appropriate warning to ack */
228 | }
229 | else if (subject_result.result == UP_SUBJ_INVALID_COMB)
230 | {
231 | if (( ack_file = fopen(filename, "a")) == NULL)
232 | {
233 | fprintf(stderr, "Can't open ack file for appending, %s", filename);
234 | }
235 | else
236 | {
237 | if ( webupdate )
238 | {
239 | fprintf(ack_file, "\nWarning: This combination of options of 'help' and 'new' is not allowed.\n"
240 | "Thus, all options were ignored.\n");
241 | }
242 | else
243 | {
244 | fprintf(ack_file, "\nWarning: This combination of keywords in subject line is not allowed.\n"
245 | "Thus, all keywords in subject line were ignored.\n");
246 | }
247 | fclose(ack_file);
248 | }
249 | }
250 |
251 | /* if the update didn't contain any objects and was not a request for help, put a warning */
252 | if (count_successful == 0 && count_unsuccessful == 0 && subject_result.result != UP_SUBJ_HELP_REQ)
253 | {
254 | AK_add_to_ack(filename, "*** Warning: No objects were found in the message ***\n");
255 | }
256 |
257 | /* add the ACKSIG to the ack */
258 | AK_add_to_ack(filename ,"\n%s", acksig);
259 |
260 | /* Here, we will print out the header of the ACK message. It cannot be
261 | prepared before, since we wouldn't know if the header should use
262 | SUCCESSTXT or FAILURETXT */
263 | temp_file = (char *)malloc(strlen(filename) + strlen(".temp") + 2);
264 | sprintf(temp_file, "%s.temp", filename);
265 | if(( temp_file_hdl = fopen(temp_file, "w")) == NULL)
266 | {
267 | fprintf(stderr, "Can't open temp ack file, %s\n", temp_file);
268 | }
269 | else
270 | {
271 | if ( subject_result.result == UP_SUBJ_HELP_REQ )
272 | {
273 | /* this is a request for help, so we will use the HELPHEADER */
274 | /* replace the global variables in helpheader */
275 | txt_replaced = UP_replace_globals(helpheader);
276 | }
277 | else if (count_unsuccessful > 0 || (count_successful + count_unsuccessful) == 0)
278 | {
279 | /* At least one of the objects failed or there wasn't any object in the
280 | update message. We will use FAILURETXT */
281 | /* replace the global variables in failuretxt */
282 | txt_replaced = UP_replace_globals(failuretxt);
283 | }
284 | else
285 | {
286 | /* All the objects in the update message were successful. So, we will
287 | use SUCCESSTXT */
288 | /* replace the global variables in successtxt */
289 | txt_replaced = UP_replace_globals(successtxt);
290 | }
291 |
292 | /* print out the success/failure/help txt */
293 | fprintf(temp_file_hdl, "To: %s\n%s\n\n", to_address, txt_replaced);
294 | free(txt_replaced);
295 | /* and now copy over the rest of the ack message */
296 | if (( ack_file = fopen(filename, "r")) == NULL)
297 | {
298 | fprintf(stderr, "Can't open ack file for reading, %s", filename);
299 | }
300 | else
301 | {
302 | while (fgets(buf, 1024, ack_file) != NULL)
303 | {
304 | fprintf(temp_file_hdl, "%s", buf);
305 | }
306 | fclose(ack_file);
307 | }
308 | fclose(temp_file_hdl);
309 | /* and copy rename the temp file */
310 | rename(temp_file, filename);
311 | free(temp_file);
312 | }
313 |
314 | /* if we are not supressing acks and notifs, send the ack */
315 | if (!supress_ack_notif)
316 | {
317 | if (to_address != NULL)
318 | {
319 | mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(to_address)
320 | + strlen(filename) + 128);
321 | sprintf(mail_command_line, "%s %s < %s", mailercommand, to_address, filename);
322 | system(mail_command_line);
323 | }
324 | }
325 | else
326 | {
327 | /* if we are supressing acks and notifs, send ack to DEFMAIL */
328 | supress_file = (char *)malloc(strlen(filename) + strlen(".supress") + 2);
329 | sprintf(supress_file, "%s.supress", filename);
330 | if (( supr_file_hdl = fopen(supress_file, "w")) == NULL)
331 | {
332 | fprintf(stderr, "Can't open supress ack file, %s", supress_file);
333 | }
334 | else
335 | {
336 | fprintf(supr_file_hdl, "From: %s\nTo: %s\nSubject: Supressed ack mail\n\n",
337 | humailbox, defmail);
338 | if (( ack_file = fopen(filename, "r")) == NULL)
339 | {
340 | fprintf(stderr, "Can't open ack file for reading, %s", filename);
341 | }
342 | else
343 | {
344 | while (fgets(buf, 1024, ack_file) != NULL)
345 | {
346 | fprintf(supr_file_hdl, "%s", buf);
347 | }
348 | fclose(ack_file);
349 | }
350 | fclose(supr_file_hdl);
351 | mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(defmail)
352 | + strlen(supress_file) + 128);
353 | sprintf(mail_command_line, "%s %s < %s", mailercommand, defmail, supress_file);
354 | system(mail_command_line);
355 | unlink(supress_file);
356 | }
357 | free(supress_file);
358 | }
359 | }
360 |
361 |
362 |
363 | /*
364 |
365 | AK_print_ack: Prints out the given file (the ack file) to the standard output
366 |
367 | */
368 | void AK_print_ack( const char * filename )
369 | {
370 | FILE * ack_file;
371 | char buf[1024];
372 |
373 | if (subject_result.result == UP_SUBJ_INVALID_COMB && webupdate)
374 | {
375 | if (( ack_file = fopen(filename, "a")) == NULL)
376 | {
377 | fprintf(stderr, "Can't open ack file for appending, %s", filename);
378 | }
379 | else
380 | {
381 | fprintf(ack_file, "\nWarning: This combination of options of 'help' and 'new' is not allowed.\n"
382 | "Thus, all options were ignored.\n");
383 | fclose(ack_file);
384 | }
385 | }
386 |
387 | /* if the update didn't contain any objects and was not a request for help, put a warning */
388 | if (count_successful == 0 && count_unsuccessful == 0 && subject_result.result != UP_SUBJ_HELP_REQ)
389 | {
390 | AK_add_to_ack(filename, "*** Warning: No objects were found in the message ***\n");
391 | }
392 |
393 | if (( ack_file = fopen(filename, "r")) == NULL)
394 | {
395 | fprintf(stderr, "Can't open ack file for reading, %s", filename);
396 | }
397 | else
398 | {
399 | while (fgets(buf, 1024, ack_file) != NULL)
400 | {
401 | printf("%s", buf);
402 | }
403 | fclose(ack_file);
404 | }
405 | }
406 |
407 |
408 |
409 | /*
410 |
411 | AK_delete_ack: deletes the temporary acknowledgement file.
412 |
413 | */
414 |
415 | void AK_delete_ack( const char * filename )
416 | {
417 | unlink(filename);
418 | }
419 |
420 |
421 | /*
422 |
423 | AK_log_ack: logs the acknowledgements in the "logfilename.date".
424 |
425 | */
426 |
427 | void AK_log_ack(const char * filename, const char * logfilename)
428 | {
429 | FILE * ack_file, * log_file;
430 | char buf[1024];
431 | time_t cur_time;
432 | char * time_str;
433 | char * logfile_date;
434 | char * date;
435 |
436 | if (( ack_file = fopen(filename, "r")) == NULL)
437 | {
438 | fprintf(stderr, "Can't open ack file for reading, %s\n", filename);
439 | return;
440 | }
441 |
442 |
443 | /* construct the "logfilename.date" string */
444 | logfile_date = (char *)malloc(strlen(logfilename) + 10);
445 | date = UP_get_current_date();
446 | snprintf(logfile_date, strlen(logfilename) + 10, "%s.%s", logfilename, date);
447 | free(date);
448 |
449 | if (( log_file = fopen(logfile_date, "a")) == NULL)
450 | {
451 | fprintf(stderr, "Can't open log file for appending, %s\n", logfile_date);
452 | free(logfile_date);
453 | return;
454 | }
455 | free(logfile_date);
456 |
457 | /* get time */
458 | cur_time = time(NULL);
459 | time_str = strdup(ctime(&cur_time));
460 | /* cut the '\n' at the end */
461 | time_str[strlen(time_str) - 1] = '\0';
462 |
463 | if (reading_from_mail)
464 | {
465 | fprintf(log_file, ">>> time: %s MAIL ACK <<<\n\n", time_str);
466 | }
467 | else if (networkupdate)
468 | {
469 | fprintf(log_file, ">>> time: %s NETWORKUPDATE (%s) ACK <<<\n\n",
470 | time_str, netupdclientIP ? netupdclientIP : "NULL" );
471 | }
472 | else if (webupdate)
473 | {
474 | fprintf(log_file, ">>> time: %s WEB UPDATE (%s) ACK <<<\n\n",
475 | time_str, netupdclientIP ? netupdclientIP : "NULL" );
476 | }
477 | else
478 | {
479 | fprintf(log_file, ">>> time: %s ACK <<<\n\n", time_str);
480 | }
481 |
482 | while (fgets(buf, 1023, ack_file) != NULL)
483 | {
484 | fprintf(log_file, "%s", buf);
485 | }
486 |
487 | free(time_str);
488 | fclose(ack_file);
489 | fclose(log_file);
490 | }
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |