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 |