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  |