1 | /***************************************
2 | $Revision: 1.5 $
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 int * reading_from_mail;
46 | extern int networkupdate;
47 | extern up_subject_struct subject_result;
48 | extern int count_successful;
49 | extern int count_unsuccessful;
50 |
51 | /*
52 |
53 | AK_add_to_ack: writes a message to the acknowledgement file.
54 | Also, prints it out to the stdout if it was a networkupdate
55 | (networkupdate is run through inetd, so stdout is our socket)
56 |
57 | */
58 |
59 | void AK_add_to_ack(const char * filename, char * fmt, ...){
60 |
61 | va_list ap; /* points to each unnamed arg in turn */
62 | char *p, *sval;
63 | int ival;
64 | double dval;
65 | FILE * ack_file;
66 |
67 | if(( ack_file = fopen(filename, "a")) == NULL){
68 | fprintf(stderr, "Can't open ack file, %s", filename);
69 | }
70 |
71 |
72 | /* if this is a network update, print it out first to the
73 | stdout (which is socket) */
74 | if(networkupdate){
75 | va_start(ap, fmt);
76 | vprintf(fmt, ap);
77 | fflush(stdout);
78 | va_end(ap);
79 | }
80 |
81 | /* and then to the file */
82 | va_start(ap, fmt);
83 |
84 | for(p = fmt; *p; p++){
85 | if (*p != '%') {
86 | fprintf(ack_file, "%c", *p);
87 | continue;
88 | }
89 | switch(*++p) {
90 | case 'd':
91 | ival = va_arg(ap, int);
92 | fprintf(ack_file, "%d", ival);
93 | break;
94 | case 'f':
95 | dval = va_arg(ap, double);
96 | fprintf(ack_file, "%f", dval);
97 | break;
98 | case 'X':
99 | ival = va_arg(ap, int);
100 | fprintf(ack_file, "%X", ival);
101 | break;
102 | case 'x':
103 | ival = va_arg(ap, int);
104 | fprintf(ack_file, "%x", ival);
105 | break;
106 | case 's':
107 | sval = va_arg(ap, char *);
108 | fprintf(ack_file, "%s", sval);
109 | break;
110 | default:
111 | putchar(*p);
112 | break;
113 | }
114 | }
115 |
116 | va_end(ap); /* clean up */
117 | fclose(ack_file);
118 | }
119 |
120 |
121 |
122 | /* Adds a complete file to the ack file */
123 |
124 | void AK_add_file_to_ack(const char * ackfile, const char * filetoadd){
125 |
126 | FILE * ack_file, * file_to_add;
127 | char buf[1024];
128 |
129 | if(( ack_file = fopen(ackfile, "a")) == NULL){
130 | fprintf(stderr, "AK_add_file_to_ack: Can't open ack file, %s\n", ackfile);
131 | }
132 |
133 | if(( file_to_add = fopen(filetoadd, "r")) == NULL){
134 |
135 | fprintf(stderr, "AK_add_file_to_ack: Can't open file, %s\n", filetoadd);
136 | fprintf(ack_file, "\nHelp file could not be found.\nPlease notify the database administrator.\n");
137 | fclose(ack_file);
138 | free(buf);
139 |
140 | }else{
141 |
142 | while(fgets(buf, 1023, file_to_add) != NULL){
143 | fprintf(ack_file, "%s", buf);
144 | }
145 |
146 | fclose(ack_file);
147 | fclose(file_to_add);
148 | }
149 | }
150 |
151 |
152 | /*
153 |
154 | AK_ack_file_name_generate: Generates a unique name for temporary acknowledgement
155 | files, and also creates it.
156 |
157 | tmpdir: temporary directory (without a trailing '/')
158 | prefix: prefix for the temp file
159 |
160 | returns: the generated name.
161 | */
162 |
163 | char * AK_ack_file_name_generate( const char * tmpdir, const char * prefix)
164 | {
165 | FILE * ack_file;
166 | char * name;
167 |
168 | /* allocate space for name. 32 should be enough for PID */
169 | name = (char*)malloc(strlen(tmpdir) + strlen(prefix) + 35);
170 |
171 | sprintf(name, "%s/%s.%i", tmpdir, prefix, (int)(getpid()) );
172 |
173 | /* create the file */
174 | if (( ack_file = fopen(name, "w")) == NULL)
175 | {
176 | fprintf(stderr, "Can't open ack file, %s", name);
177 | }
178 |
179 | /* close it */
180 | fclose(ack_file);
181 |
182 | return name;
183 | }
184 |
185 |
186 | /*
187 |
188 | AK_send_ack: post-processes and sends the ack message contained in the temp file.
189 |
190 |
191 | */
192 |
193 | void AK_send_ack( const char * filename, const char * to_address, const char * mailercommand)
194 | {
195 | char * mail_command_line = NULL;
196 | char * supress_file = NULL, * temp_file = NULL;
197 | FILE * ack_file, * supr_file_hdl, * temp_file_hdl;
198 | char *txt_replaced;
199 | char buf[1024];
200 |
201 | /* first check if we the user specified some non-keyword words in
202 | the subject line (in addition to some valid keywords)
203 | If so, we will add a warning to the ack file */
204 | if (subject_result.result == UP_SUBJ_UNRECOG)
205 | {
206 | if (( ack_file = fopen(filename, "a")) == NULL)
207 | {
208 | fprintf(stderr, "Can't open ack file for appending, %s", filename);
209 | }
210 | else
211 | {
212 | fprintf(ack_file, "\nWarning: unknown keywords found in subject line:\n"
213 | "%s\n"
214 | "Thus, all keywords in subject line were ignored.\n",
215 | subject_result.word_list ? subject_result.word_list : "" );
216 | fclose(ack_file);
217 | }
218 |
219 | /* and now check if the user specified an invalid combination of keywords
220 | in the subject line, and if so, print an appropriate warning to ack */
221 | }
222 | else if (subject_result.result == UP_SUBJ_INVALID_COMB)
223 | {
224 | if (( ack_file = fopen(filename, "a")) == NULL)
225 | {
226 | fprintf(stderr, "Can't open ack file for appending, %s", filename);
227 | }
228 | else
229 | {
230 | fprintf(ack_file, "\nWarning: This combination of keywords in subject line is not allowed.\n"
231 | "Thus, all keywords in subject line were ignored.\n");
232 | fclose(ack_file);
233 | }
234 | }
235 |
236 | /* if the update didn't contain any objects and was not a request for help, put a warning */
237 | if (count_successful == 0 && count_unsuccessful == 0 && subject_result.result != UP_SUBJ_HELP_REQ)
238 | {
239 | AK_add_to_ack(filename, "*** Warning: No objects were found in the message ***\n");
240 | }
241 |
242 | /* add the ACKSIG to the ack */
243 | AK_add_to_ack(filename ,"\n%s", acksig);
244 |
245 | /* Here, we will print out the header of the ACK message. It cannot be
246 | prepared before, since we wouldn't know if the header should use
247 | SUCCESSTXT or FAILURETXT */
248 | temp_file = (char *)malloc(strlen(filename) + strlen(".temp") + 2);
249 | sprintf(temp_file, "%s.temp", filename);
250 | if(( temp_file_hdl = fopen(temp_file, "w")) == NULL)
251 | {
252 | fprintf(stderr, "Can't open temp ack file, %s\n", temp_file);
253 | }
254 | else
255 | {
256 | if ( subject_result.result == UP_SUBJ_HELP_REQ )
257 | {
258 | /* this is a request for help, so we will use the HELPHEADER */
259 | /* replace the global variables in helpheader */
260 | txt_replaced = UP_replace_globals(helpheader);
261 | }
262 | else if (count_unsuccessful > 0 || (count_successful + count_unsuccessful) == 0)
263 | {
264 | /* At least one of the objects failed or there wasn't any object in the
265 | update message. We will use FAILURETXT */
266 | /* replace the global variables in failuretxt */
267 | txt_replaced = UP_replace_globals(failuretxt);
268 | }
269 | else
270 | {
271 | /* All the objects in the update message were successful. So, we will
272 | use SUCCESSTXT */
273 | /* replace the global variables in successtxt */
274 | txt_replaced = UP_replace_globals(successtxt);
275 | }
276 |
277 | /* print out the success/failure/help txt */
278 | fprintf(temp_file_hdl, "To: %s\n%s\n\n", to_address, txt_replaced);
279 | free(txt_replaced);
280 | /* and now copy over the rest of the ack message */
281 | if (( ack_file = fopen(filename, "r")) == NULL)
282 | {
283 | fprintf(stderr, "Can't open ack file for reading, %s", filename);
284 | }
285 | else
286 | {
287 | while (fgets(buf, 1024, ack_file) != NULL)
288 | {
289 | fprintf(temp_file_hdl, "%s", buf);
290 | }
291 | fclose(ack_file);
292 | }
293 | fclose(temp_file_hdl);
294 | /* and copy rename the temp file */
295 | rename(temp_file, filename);
296 | free(temp_file);
297 | }
298 |
299 | /* if we are not supressing acks and notifs, send the ack */
300 | if (!supress_ack_notif)
301 | {
302 | if (to_address != NULL)
303 | {
304 | mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(to_address)
305 | + strlen(filename) + 128);
306 | sprintf(mail_command_line, "%s %s < %s", mailercommand, to_address, filename);
307 | system(mail_command_line);
308 | }
309 | }
310 | else
311 | {
312 | /* if we are supressing acks and notifs, send ack to DEFMAIL */
313 | supress_file = (char *)malloc(strlen(filename) + strlen(".supress") + 2);
314 | sprintf(supress_file, "%s.supress", filename);
315 | if (( supr_file_hdl = fopen(supress_file, "w")) == NULL)
316 | {
317 | fprintf(stderr, "Can't open supress ack file, %s", supress_file);
318 | }
319 | else
320 | {
321 | fprintf(supr_file_hdl, "From: %s\nTo: %s\nSubject: Supressed ack mail\n\n",
322 | humailbox, defmail);
323 | if (( ack_file = fopen(filename, "r")) == NULL)
324 | {
325 | fprintf(stderr, "Can't open ack file for reading, %s", filename);
326 | }
327 | else
328 | {
329 | while (fgets(buf, 1024, ack_file) != NULL)
330 | {
331 | fprintf(supr_file_hdl, "%s", buf);
332 | }
333 | fclose(ack_file);
334 | }
335 | fclose(supr_file_hdl);
336 | mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(defmail)
337 | + strlen(supress_file) + 128);
338 | sprintf(mail_command_line, "%s %s < %s", mailercommand, defmail, supress_file);
339 | system(mail_command_line);
340 | unlink(supress_file);
341 | }
342 | free(supress_file);
343 | }
344 | }
345 |
346 |
347 |
348 | /*
349 |
350 | AK_print_ack: Prints out the given file (the ack file) to the standard output
351 |
352 | */
353 | void AK_print_ack( const char * filename )
354 | {
355 | FILE * ack_file;
356 | char buf[1024];
357 |
358 | if (( ack_file = fopen(filename, "r")) == NULL)
359 | {
360 | fprintf(stderr, "Can't open ack file for reading, %s", filename);
361 | }
362 | else
363 | {
364 | while (fgets(buf, 1024, ack_file) != NULL)
365 | {
366 | printf("%s", buf);
367 | }
368 | fclose(ack_file);
369 | }
370 | }
371 |
372 |
373 |
374 | /*
375 |
376 | AK_delete_ack: deletes the temporary acknowledgement file.
377 |
378 | */
379 |
380 | void AK_delete_ack( const char * filename )
381 | {
382 | unlink(filename);
383 | }
384 |
385 |
386 | /*
387 |
388 | AK_log_ack: logs the acknowledgements in the "logfilename.date".
389 |
390 | */
391 |
392 | void AK_log_ack(const char * filename, const char * logfilename)
393 | {
394 | FILE * ack_file, * log_file;
395 | char buf[1024];
396 | time_t cur_time;
397 | char * time_str;
398 | char * logfile_date;
399 | char * date;
400 |
401 | if (( ack_file = fopen(filename, "r")) == NULL)
402 | {
403 | fprintf(stderr, "Can't open ack file for reading, %s\n", filename);
404 | return;
405 | }
406 |
407 |
408 | /* construct the "logfilename.date" string */
409 | logfile_date = (char *)malloc(strlen(logfilename) + 10);
410 | date = UP_get_current_date();
411 | snprintf(logfile_date, strlen(logfilename) + 10, "%s.%s", logfilename, date);
412 | free(date);
413 |
414 | if (( log_file = fopen(logfile_date, "a")) == NULL)
415 | {
416 | fprintf(stderr, "Can't open log file for appending, %s\n", logfile_date);
417 | free(logfile_date);
418 | return;
419 | }
420 | free(logfile_date);
421 |
422 | /* get time */
423 | cur_time = time(NULL);
424 | time_str = strdup(ctime(&cur_time));
425 | /* cut the '\n' at the end */
426 | time_str[strlen(time_str) - 1] = '\0';
427 |
428 | if (reading_from_mail)
429 | {
430 | fprintf(log_file, ">>> time: %s MAIL ACK <<<\n\n", time_str);
431 | }
432 | else if (networkupdate)
433 | {
434 | fprintf(log_file, ">>> time: %s NETWORKUPDATE ACK <<<\n\n", time_str);
435 | }
436 | else
437 | {
438 | fprintf(log_file, ">>> time: %s ACK <<<\n\n", time_str);
439 | }
440 |
441 | while (fgets(buf, 1023, ack_file) != NULL)
442 | {
443 | fprintf(log_file, "%s", buf);
444 | }
445 |
446 | free(time_str);
447 | fclose(ack_file);
448 | fclose(log_file);
449 | }
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |