1    | /***************************************
2    |   $Revision: 1.11 $
3    | 
4    |   NT (Notifications) module
5    | 
6    |   Status: REVIEWED, NOT TESTED
7    | 
8    |   Author(s):       Engin Gunduz
9    | 
10   |   ******************/ /******************
11   |   Modification History:
12   |         engin (06/07/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   | 
38   | 
39   | 
40   | #include "notification.h"
41   | extern int supress_ack_notif;
42   | extern char * defmail;
43   | extern int reading_from_mail;
44   | extern char * forwlog;
45   | 
46   | /*  Generates a unique file name and returns the full path of the filename 
47   |     for storing notification message.  Creates the file at the same time. 
48   |     May use PID or time or both to ensure uniqueness.  */
49   |       
50   | char * NT_ntfy_filename_generate( const char * tmpdir, const char * e_mail)
51   | {
52   |    FILE * ntfy_file;
53   |    char * name;
54   |    char * replaced_notimailtxt;
55   |    char * replaced_notinetworktxt;
56   |        
57   |    /* allocate space for name.  32 should be enough for PID */
58   |    name = (char*)malloc(strlen(tmpdir) + strlen(e_mail) + strlen("notify") +36 ); 
59   |  
60   |    sprintf(name, "%s/%s-%s.%i", tmpdir, "notify", e_mail, (int)(getpid()) );
61   | 
62   |    /* create the file */
63   |    if (( ntfy_file = fopen(name, "w")) == NULL)
64   |    {
65   |      fprintf(stderr, "Can't open notification file for creating, %s", name);
66   |    }
67   | 
68   |    fprintf(ntfy_file, "To: %s\nFrom: %s\nSubject: Notification of RIPE Database changes\nReply-To: %s\n\n%s\n", e_mail, humailbox, humailbox, notitxt);
69   |    if (reading_from_mail)
70   |    {
71   |      replaced_notimailtxt = UP_replace_globals(notimailtxt);
72   |      fprintf(ntfy_file, "%s\n\n", replaced_notimailtxt);
73   |      free(replaced_notimailtxt);
74   |    }
75   | 
76   |    if (networkupdate)
77   |    {
78   |      replaced_notinetworktxt = UP_replace_globals(notinetworktxt);
79   |      fprintf(ntfy_file, "%s\n\n", replaced_notinetworktxt);
80   |      free(replaced_notinetworktxt);
81   |    }
82   |    
83   |    /* close it */
84   |    fclose(ntfy_file);
85   |     
86   |    return name;
87   | }
88   | 
89   | 
90   | 
91   | 
92   | /* Generates a unique file name and returns the full path of the filename 
93   |    for storing forwarded message. Creates the file at the same time.  */ 
94   | char * NT_forwd_filename_generate( const char * tmpdir, const char * e_mail)
95   | {
96   |    FILE * forwd_file;
97   |    char * name;
98   |    char * replaced_fwmailtxt;
99   |           
100  |    /* allocate space for name.  32 should be enough for PID */
101  |    name = (char*)malloc(strlen(tmpdir) + strlen(e_mail) + strlen("forwd") +36 ); 
102  |    
103  |    sprintf(name, "%s/%s-%s.%i", tmpdir, "forwd", e_mail, (int)(getpid()) );
104  |    /* create the file */
105  |    if (( forwd_file = fopen(name, "w")) == NULL)
106  |    {
107  |      fprintf(stderr, "Can't open forward file, %s", name);
108  |    }
109  | 
110  |    fprintf(forwd_file, "To: %s\nFrom: %s\nSubject:  Requested RIPE database object changes \nReply-To: %s\n\n%s\n", e_mail, humailbox, humailbox, fwtxt);
111  |    if (reading_from_mail)
112  |    {
113  |      replaced_fwmailtxt = UP_replace_globals(fwmailtxt);
114  |      fprintf(forwd_file, "\n%s\n", replaced_fwmailtxt);
115  |      free(replaced_fwmailtxt);
116  |    }
117  | 
118  |    /* close it */
119  |    fclose(forwd_file);
120  |     
121  |    return name;
122  | }
123  | 
124  | 
125  | 
126  | 
127  | /* Generates a unique file name and returns the full path of the filename 
128  |    for storing cross notification message. Creates the file at the same time.  */ 
129  | char * NT_cross_filename_generate( const char * tmpdir, const char * e_mail, int mode)
130  | {
131  |    FILE * cross_file;
132  |    char * name;
133  |       
134  |    /* allocate space for name.  32 should be enough for PID */
135  |    name = (char*)malloc(strlen(tmpdir) + strlen(e_mail) + strlen("cross") +36 ); 
136  |    
137  |    sprintf(name, "%s/%s-%s.%i", tmpdir, "cross", e_mail, (int)(getpid()) );
138  |    /* create the file */
139  |    if (( cross_file = fopen(name, "w")) == NULL)
140  |    {
141  |      fprintf(stderr, "Can't open cross notif file, %s", name);
142  |    }
143  | 
144  |    if (mode == ADDITION)
145  |    {
146  |      fprintf(cross_file, "To: %s\nFrom: %s\n%s\nReply-To: %s\n\n", e_mail, humailbox, cno_subject_add, humailbox);
147  |    }
148  |    else
149  |    {
150  |      fprintf(cross_file, "To: %s\nFrom: %s\n%s\nReply-To: %s\n\n", e_mail, humailbox, cno_subject_del, humailbox);
151  |    }
152  |    
153  |    /* close it */
154  |    fclose(cross_file);
155  |     
156  |    return name;
157  | }
158  | 
159  | 
160  | 
161  | 
162  | 
163  | /* Generates a unique file name and returns the full path of the filename for 
164  |    storing notification message. Creates the file at the same time.  */
165  | char * NT_crossntfy_filename_generate( const char * tmpdir, const char * e_mail)
166  | {
167  |    FILE * cross_file;
168  |    char * name;
169  |       
170  |    /* allocate space for name.  32 should be enough for PID */
171  |    name = (char*)malloc(strlen(tmpdir) + strlen(e_mail) + strlen("cross") +36 ); 
172  |    
173  |    sprintf(name, "%s/%s-%s.%i", tmpdir, "cross", e_mail, (int)(getpid()) );
174  | 
175  |    /* create the file */
176  |    if (( cross_file = fopen(name, "w")) == NULL)
177  |    {
178  |      fprintf(stderr, "Can't open cross file, %s", name);
179  |    }
180  | 
181  |    /* close it */
182  |    fclose(cross_file);
183  |     
184  |    return name;
185  | }
186  | 
187  | 
188  | 
189  | /* Adds the e-mail to the notify hash, generating appropriate temp files */
190  | void NT_add_to_ntfy_hash(GHashTable * ntfy_hash, char * e_mail)
191  | {
192  |   if (g_hash_table_lookup(ntfy_hash ,e_mail) == NULL)
193  |   { /* there is no such entry, so create it */
194  | 
195  |     g_hash_table_insert(ntfy_hash, strdup(e_mail), NT_ntfy_filename_generate(tmpdir, e_mail));
196  |   }
197  | }
198  | 
199  | 
200  | 
201  | /* Adds the e-mail to the forw hash, generating appropriate temp files */
202  | void NT_add_to_frwd_hash(GHashTable * frwd_hash, char * e_mail)
203  | {
204  |   if (g_hash_table_lookup(frwd_hash ,e_mail) == NULL)
205  |   { /* there is no such entry, so create it */
206  |     g_hash_table_insert(frwd_hash, strdup(e_mail), NT_forwd_filename_generate(tmpdir, e_mail));
207  |   }
208  |     
209  | }
210  | 
211  | 
212  | 
213  | /* Adds the e-mail to the cross hash, generating appropriate temp files */
214  | void NT_add_to_cross_hash(GHashTable * cross_hash, const char * e_mail, int mode)
215  | {
216  |   /*  if e-mail is NULL, immediately return */
217  |   if (e_mail == NULL)
218  |   {
219  |     return;
220  |   }
221  | 
222  |   if (g_hash_table_lookup(cross_hash ,e_mail) == NULL)
223  |   { /* there is no such entry, so create it */
224  |     g_hash_table_insert(cross_hash, strdup(e_mail), NT_cross_filename_generate(tmpdir, e_mail, mode));
225  |   }
226  | }
227  | 
228  | 
229  | 
230  | /* Adds the e-mails in a linked list to the hash */
231  | void NT_add_to_ntfy_hash_list(GHashTable * ntfy_hash, GList * e_mail_list)
232  | {
233  |    GList * temp = NULL;
234  | 
235  |    for (temp = e_mail_list; temp != NULL; temp = g_list_next(temp))
236  |    {
237  |      NT_add_to_ntfy_hash( ntfy_hash, (char *)(temp->data) );
238  |    }
239  | }
240  | 
241  | 
242  | 
243  | /* Adds the e-mails in a linked list to the hash */
244  | void NT_add_to_frwd_hash_list(GHashTable * frwd_hash, GList * e_mail_list)
245  | {
246  |    GList * temp = NULL;
247  | 
248  |    for (temp = e_mail_list; temp != NULL; temp = g_list_next(temp))
249  |    {
250  |      NT_add_to_frwd_hash(frwd_hash, (char *)temp->data);
251  |    }
252  | }
253  | 
254  | 
255  | 
256  | /* Adds the e-mails in a linked list to the hash */
257  | void NT_add_to_cross_hash_list(GHashTable * cross_hash, GList * e_mail_list, int mode)
258  | {
259  |    GList * temp = NULL;
260  | 
261  |    for (temp = e_mail_list; temp != NULL; temp = g_list_next(temp))
262  |    {
263  |      NT_add_to_cross_hash(cross_hash, (char *)temp->data, mode);
264  |    }
265  | }
266  | 
267  | 
268  | 
269  | /* Appends the argument strings to the file.  */
270  | void NT_add_to_ntfy( char * filename, char * fmt, ... )
271  | {
272  |   va_list ap;  /* points to each unnamed arg in turn */
273  |   FILE * ntfy_file;
274  |  
275  |   if (tracing)
276  |   {
277  |     printf("TRACING: NT_add_to_ntfy\n"); 
278  |   }
279  |   if (( ntfy_file = fopen(filename, "a")) == NULL)
280  |   {
281  |     fprintf(stderr, "Can't open notification file for writing, %s\n", filename);
282  |     return;
283  |   }
284  |     
285  |   va_start(ap, fmt);
286  |   vfprintf(ntfy_file, fmt, ap);
287  | 
288  |   va_end(ap); /* clean up */
289  |   fclose(ntfy_file);
290  | }
291  | 
292  | 
293  | 
294  | /* Appends the argument strings to the file.  */
295  | void NT_add_to_cross(const char * e_mail, GHashTable * hash, char * fmt, ...)
296  | {
297  |   va_list ap;  /* points to each unnamed arg in turn */
298  |   FILE * cross_file = NULL;
299  |   char * filename = NULL;
300  | 
301  |   if (tracing)
302  |   {
303  |     printf("TRACING: NT_add_to_cross\n"); 
304  |   }
305  | 
306  |   /* if e-mail is NULL, immediately return */
307  |   if(e_mail == NULL)
308  |   {
309  |     return;
310  |   }
311  |    
312  |   if ( (filename = (char *)g_hash_table_lookup(hash, find_email_address(e_mail))) == NULL )
313  |   {
314  |     fprintf(stderr, "Can't find a cross notification file for e-mail %s\n", e_mail);
315  |     return;
316  |   }
317  | 
318  |   if ( ( cross_file = fopen(filename, "a")) == NULL )
319  |   {
320  |     fprintf(stderr, "Can't open cross notification file for writing, %s\n", filename);
321  |   }
322  |     
323  |   va_start(ap, fmt);
324  |   vfprintf(cross_file, fmt, ap);
325  | 
326  |   va_end(ap); /* clean up */
327  |   fclose(cross_file);
328  | }
329  | 
330  | 
331  | 
332  | 
333  | /* Appends the argument string to the temp notif files in the list */
334  | void NT_add_to_ntfy_list(GList * list, GHashTable * hash, char * arg)
335  | {
336  |   GList * temp = NULL;
337  | 
338  |   for(temp = list; temp != NULL; temp = g_list_next(temp))
339  |   {
340  |     NT_add_to_ntfy((char *)g_hash_table_lookup(hash, ((char *)temp->data)), "%s", arg);
341  |   }
342  | }
343  | 
344  | 
345  | 
346  | /* Sends the notification message which is stored in the temporary filefilename.  */
347  | void NT_send_ntfy( const char * filename, const char * to_address, const char * mailercommand)
348  | {
349  |     char * mail_command_line = NULL;
350  |     char * supress_file = NULL;
351  |     FILE * notif_file, * supr_file_hdl;
352  |     char buf[1024];
353  | 
354  |     /* if we are not supressing acks and notifs, send the notif */
355  |     if (!supress_ack_notif)
356  | 	{
357  |       if (to_address != NULL)
358  | 	  {
359  |         mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(filename) + 128);
360  |         sprintf(mail_command_line, "%s %s < %s", mailercommand, to_address, filename);
361  |         system(mail_command_line);
362  |       }
363  |     }
364  |     /* if we are supressing acks and notifs, send notif to DEFMAIL  */
365  | 	else
366  | 	{
367  |       supress_file = (char *)malloc(strlen(filename) + strlen(".supress") + 2); 
368  |       sprintf(supress_file, "%s.supress", filename);
369  |       if (( supr_file_hdl = fopen(supress_file, "w")) == NULL)
370  | 	  {
371  |         fprintf(stderr, "Can't open supress notif file, %s", supress_file);
372  |       }
373  | 	  else
374  | 	  {
375  |         fprintf(supr_file_hdl, "From: %s\nTo: %s\nSubject: Supressed notif mail\n\n",
376  |             humailbox, defmail);
377  |         if (( notif_file = fopen(filename, "r")) == NULL)
378  | 		{
379  |           fprintf(stderr, "Can't open notif file for reading, %s", filename);
380  |         }
381  | 		else
382  | 		{
383  |           while (fgets(buf, 1023, notif_file) != NULL)
384  | 		  {
385  |             fprintf(supr_file_hdl, buf);
386  |           }
387  |           fclose(notif_file);
388  |         }
389  |       }
390  |       fclose(supr_file_hdl);
391  |       mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(defmail) 
392  |             + strlen(supress_file) + 128);
393  |       sprintf(mail_command_line, "%s %s < %s", mailercommand, defmail, supress_file);
394  |       system(mail_command_line);
395  |       unlink(supress_file);
396  |       free(supress_file);
397  |     }
398  | }
399  | 
400  | 
401  | 
402  | /* Adds the notification message which is in the filename into "logfilename.date". */
403  | void NT_log_ntfy( const char * filename, const char * logfilename)
404  | {
405  |   FILE * notif_file, * log_file;
406  |   char * buf;
407  |   time_t cur_time;
408  |   char * time_str;
409  |   char * logfile_date;
410  |   char * date;
411  | 
412  |   if (tracing)
413  |   {
414  |     printf("TRACING: NT_log_ntfy is running: filename [%s]  logfilename [%s]\n", filename, logfilename);
415  |   }
416  | 
417  |   buf = (char *)malloc(1024);
418  |   if (( notif_file = fopen(filename, "r")) == NULL)
419  |   {
420  |     fprintf(stderr, "NT_log_ntfy: Can't open notification file for reading, [%s]\n", filename);
421  |     return;
422  |   }
423  | 
424  |   /* construct the "logfilename.date" string */
425  |   logfile_date = (char *)malloc(strlen(logfilename) + 10);
426  |   date = UP_get_current_date();
427  |   snprintf(logfile_date, strlen(logfilename) + 10, "%s.%s", logfilename, date);
428  |   free(date);
429  | 
430  |   if (( log_file = fopen(logfile_date, "a")) == NULL)
431  |   {
432  |     fprintf(stderr, "NT_log_ntfy: Can't open log file, %s\n", logfilename);
433  |     return;
434  |   }
435  | 
436  |   /* get time */
437  |   cur_time = time(NULL);
438  |   time_str = strdup(ctime(&cur_time));
439  |   /* cut the '\n' at the end */
440  |   time_str[strlen(time_str) - 1] = '\0';
441  | 
442  |   fprintf(log_file, ">>> time: %s NOTIF <<<\n\n", time_str);
443  | 
444  | 
445  |   while ( (buf=fgets(buf, 1024, notif_file)) != NULL )
446  |   {
447  |     fprintf(log_file, "%s", buf);
448  |   }
449  |   free(buf);
450  | 
451  |   fclose(notif_file);
452  |   fclose(log_file);
453  | }
454  | 
455  | 
456  | /* Deletes the temporary notification file. */ 
457  | void NT_delete_ntfy( const char * filename)
458  | {
459  |    unlink(filename);
460  | }
461  | 
462  | 
463  | /* The function required for NT_send_ntfy_list */
464  | void  nt_gfunc_send(gpointer key, gpointer value, gpointer user_data)
465  | {
466  |   NT_send_ntfy((char *)value, (char *)key, (char *)user_data);
467  | }
468  | 
469  | 
470  |        
471  | /* Sends the notification messages whose temp files are stored in filehash. */              
472  | void NT_send_ntfy_list( GHashTable * filehash, char * mailercommand)
473  | {
474  |   g_hash_table_foreach( filehash, (GHFunc)nt_gfunc_send, mailercommand);
475  | }
476  | 
477  | 
478  | 
479  | 
480  | /* The function required for NT_log_ntfy_list */
481  | void  nt_gfunc_log(gpointer key, gpointer value, gpointer user_data)
482  | {
483  |   NT_log_ntfy((char *)value, (char *)user_data);
484  | }
485  | 
486  | 
487  | 
488  | 
489  | /* Logs the notification whose temp files are in filehash to log_file. */
490  | void NT_log_ntfy_list( GHashTable * filehash, char * log_file)
491  | {
492  |    g_hash_table_foreach( filehash, (GHFunc)nt_gfunc_log, log_file);
493  | }
494  | 
495  | 
496  | 
497  | /* The function required for NT_delete_ntfy_list */
498  | void  nt_gfunc_delete(gpointer key, gpointer value, gpointer user_data)
499  | {
500  |   NT_delete_ntfy((char *)value);
501  | }
502  | 
503  | 
504  | 
505  | /* Deletes the temporary notification messages in the filehash. Empties and frees 
506  |    the hash too.  */
507  | void NT_delete_ntfy_list( GHashTable * filehash)
508  | {
509  |   g_hash_table_foreach(filehash, (GHFunc)nt_gfunc_delete, NULL);
510  |   g_hash_table_destroy(filehash);
511  | }
512  | 
513  | 
514  | /* to be used with g_hash_table_foreach in NT_unify_list.
515  |    Adds the 'value' to the list (a GList) */
516  | /* void nt_add_to_list(char * key, rpsl_attr_t * value, GList ** list)
517  | {
518  |   *list = g_list_append(*list, strdup(value));
519  | }
520  | */
521  | 
522  | 
523  | /* to be used with g_hash_table_foreach in NT_unify_list.
524  |    frees the 'key' and 'value' in the list (a GList) */
525  | void nt_free_list(char * key, char * value, void *nothing)
526  | {
527  |   if ( key != NULL )
528  |     free(key);
529  |   if ( value != NULL )
530  |     free(value);
531  | }
532  | 
533  | 
534  | 
535  | /* "unifies" a list in a case insensitive manner */
536  | GList * NT_unify_list(GList * in_list)
537  | {
538  |   GHashTable * unification_hash;
539  |   GList ** out_list;
540  |   GList * temp;
541  |   GList *return_list = NULL;
542  |   char * key, * value;
543  |   int strcmp();
544  | 
545  |   /* allocate space for out_list */ 
546  |   out_list = (GList **)malloc(sizeof(GList *));
547  |   *out_list = NULL;
548  | 
549  |   /* initialize the hash to be used for unification process */
550  |   unification_hash = g_hash_table_new(g_str_hash, g_str_equal);
551  | 
552  |   /* first put the list elements into a hash, to unify them */
553  |   for (temp = in_list; temp != NULL; temp = g_list_next(temp))
554  |   {
555  |     /* convert the email address into lowercase, for comparison reasons only */
556  |     key = rpsl_attr_get_clean_value((rpsl_attr_t *)(temp->data));
557  |     value = strdup(key);
558  |     g_strdown(key);
559  |     
560  |     if (g_hash_table_lookup(unification_hash, key) == NULL)
561  | 	{ /* if it is not already in the hash table, add to the hash and append to new list */
562  |       g_hash_table_insert(unification_hash, key, value);
563  |       *out_list = g_list_insert_sorted( *out_list, strdup(value), strcmp );
564  | /*       *out_list = g_list_append( *out_list, strdup(value) ); */
565  |     }
566  | 	else
567  | 	{  /* it is a duplicate email address, don't append to new list */
568  | 	  free(key);
569  | 	  free(value);
570  | 	}
571  |   }
572  | 
573  |   /* now, delete the elements in the hash */
574  |   g_hash_table_foreach(unification_hash, (GHFunc)nt_free_list, NULL);
575  | 
576  |   g_hash_table_destroy(unification_hash);
577  |   
578  |   return_list = *out_list;
579  |   free(out_list);
580  |   return return_list;
581  | }
582  | 
583  | 
584  | 
585  | /* Gets GLists of irt atributes from old and new object. Compares these
586  |    lists and returns a list of diferences */
587  | 
588  | /* if option==1, return list contains only newly deleted irts
589  |    if option==2, return list contains only newly added irts
590  |    if option==3, return list contains both */
591  | 
592  | GList *NT_compare_lists(GList *old_irts, GList *new_irts, int option)
593  | {
594  |   typedef struct irt_details
595  |   {
596  |     gchar *irt_name;
597  | 	rpsl_attr_t *irts;
598  | 	gint   matched;
599  |   } irt_details_t;
600  |   
601  |   GList *old_irt_details = NULL;
602  |   GList *new_irt_details = NULL;
603  |   GList *old_irts_item = NULL;
604  |   GList *new_irts_item = NULL;
605  |   GList *return_list = NULL;
606  |   irt_details_t *irt_details;
607  |   char *irt_name;
608  |   
609  |   if (tracing)
610  |   { 
611  |     printf("TRACING: NT_compare_lists is running: option: [%d]\n", option);
612  |   }
613  | 
614  |   /* collect data from the old_irts */
615  |   for ( old_irts_item = old_irts; old_irts_item != NULL; old_irts_item = g_list_next(old_irts_item) )
616  |   {
617  |     irt_details = (irt_details_t *)malloc(sizeof(irt_details_t));
618  | 	/* get irt name from attr */
619  | 	irt_name = rpsl_attr_get_clean_value( (rpsl_attr_t *)(old_irts_item->data) );
620  | 	/* enter details into irt_details structure */
621  | 	irt_details->irts = (rpsl_attr_t *)(old_irts_item->data);
622  | 	irt_details->irt_name = irt_name;
623  | 	irt_details->matched = 0;
624  | 	/* append irt_details structure to old_irt_details list */
625  | 	old_irt_details = g_list_append(old_irt_details, irt_details);
626  |   }
627  |   
628  |   /* collect data from the new_irts and compare with the old in the same loop */
629  |   for ( new_irts_item = new_irts; new_irts_item != NULL; new_irts_item = g_list_next(new_irts_item) )
630  |   {
631  |     irt_details = (irt_details_t *)malloc(sizeof(irt_details_t));
632  | 	/* get irt name from attr */
633  | 	irt_name = rpsl_attr_get_clean_value( (rpsl_attr_t *)(new_irts_item->data) );
634  | 	/* enter details into irt_details structure */
635  | 	irt_details->irts = (rpsl_attr_t *)(new_irts_item->data);
636  | 	irt_details->irt_name = irt_name;
637  | 	irt_details->matched = 0;
638  | 
639  | 	/* compare the name with the names from the old list  */
640  | 	for ( old_irts_item = old_irt_details; old_irts_item != NULL; old_irts_item = g_list_next(old_irts_item) )
641  |     {
642  | 	  if ( ! strcmp(irt_name, ((irt_details_t *)(old_irts_item->data))->irt_name ) )
643  | 	  {
644  | 	    irt_details->matched = 1;
645  | 		((irt_details_t *)(old_irts_item->data))->matched = 1;
646  | 		break;
647  | 	  }
648  | 	}
649  | 
650  | 	/* append irt_details structure to new_irt_details list */
651  | 	new_irt_details = g_list_append(new_irt_details, irt_details);
652  |   }
653  |   
654  |   /* we now want a list of irts taken from the old and new irt_details lists
655  |      where the matched flag is _NOT_ set. These will only exist in one list
656  | 	 and have therefore just been added/deleted */
657  |   /* if option==1, return list contains only newly deleted irts
658  |      if option==2, return list contains only newly added irts
659  |      if option==3, return list contains both */
660  |   if ( option == 1 || option == 3 )
661  |   {   
662  |     for ( old_irts_item = old_irt_details; old_irts_item != NULL; old_irts_item = g_list_next(old_irts_item) )
663  |     {
664  |       if ( ! ((irt_details_t *)(old_irts_item->data))->matched )
665  | 	  {
666  |         if (tracing)
667  |         { 
668  |           printf("TRACING: NT_compare_lists: adding old irt to return list [%s]\n", ((irt_details_t *)(new_irts_item->data))->irt_name);
669  |         }
670  | 
671  | 	    return_list = g_list_append(return_list, ((irt_details_t *)(old_irts_item->data))->irts );
672  | 	  }
673  | 	  free ( ((irt_details_t *)(old_irts_item->data))->irt_name );
674  |     }
675  |   }
676  |   g_list_free(old_irt_details);
677  |   if ( option == 2 || option == 3 )
678  |   {   
679  |     for ( new_irts_item = new_irt_details; new_irts_item != NULL; new_irts_item = g_list_next(new_irts_item) )
680  |     {
681  |       if ( ! ((irt_details_t *)(new_irts_item->data))->matched )
682  | 	  {
683  |         if (tracing)
684  |         { 
685  |           printf("TRACING: NT_compare_lists: adding new irt to return list [%s]\n", ((irt_details_t *)(new_irts_item->data))->irt_name);
686  |         }
687  | 
688  | 	    return_list = g_list_append(return_list, ((irt_details_t *)(new_irts_item->data))->irts );
689  | 	  }
690  | 	  free ( ((irt_details_t *)(new_irts_item->data))->irt_name );
691  |     }
692  |   }
693  |   g_list_free(new_irt_details);
694  |   
695  |   return return_list;
696  | }
697  | 
698  | 
699  | /* Gets old and new objects supplied, forms lists of any irt objects referenced 
700  |    by these. Returns a GList of irt-nfy for any irt objects that heve been added
701  |    or deleted.
702  | */
703  | GList *NT_check_irtnfy(rpsl_object_t *old_obj, rpsl_object_t *new_obj)
704  | {
705  |   GList *old_irts = NULL; 
706  |   GList *new_irts = NULL; 
707  |   GList *changed_irts = NULL; 
708  | 
709  |   if (old_obj != NULL)
710  |     old_irts = get_irts(old_obj);
711  |   if (new_obj != NULL)
712  |     new_irts = get_irts(new_obj);
713  | 
714  |   if ( old_irts != NULL && new_irts!= NULL )
715  |   {
716  |     /* compare lists for additions and deletions */
717  | 	changed_irts = NT_compare_lists(old_irts, new_irts, 3);
718  | 	return get_irtnfy_vector(changed_irts);
719  |   }
720  |   else if ( old_irts != NULL )
721  |   {
722  |     /* these irts have been deleted */
723  | 	return get_irtnfy_vector(old_irts);
724  |   }
725  |   else if ( new_irts != NULL )
726  |   {
727  |     /* these irts have been added */
728  | 	return get_irtnfy_vector(new_irts);
729  |   }
730  |   else
731  |     return NULL;  /* no irt objects at all */
732  | }
733  | 
734  | 
735  | /* Gathers e-mail boxes to which we will send normal notification messages. It 
736  |    takes old and new object strings, looks up maintainers and less specific inetnums/domains/routes 
737  |    when necessary, finds the addresses (in mnt-nfy and notify attributes) and returns 
738  |    a list of email addresses as strings. 
739  |    Also now checks for irt-nfy in any irt objects that have been added or deleted */
740  | GList * NT_gather_ntfy_addresses( const char * old_object_str, const char * new_object_str)
741  | {
742  |   GList *return_list = NULL, *temp = NULL;
743  |   GList *mntners = NULL; 
744  |   const GList *error_list = NULL; 
745  |   rpsl_object_t *old_obj = NULL;
746  |   rpsl_object_t *new_obj = NULL;
747  | 
748  |   if (tracing)
749  |   { 
750  |     printf("TRACING: NT_gather_ntfy_addresses is running: old_object_str : [%s]; new_object_str: [%s]\n", old_object_str ? old_object_str : "", new_object_str ? new_object_str : "");
751  |   }
752  | 
753  |   if (old_object_str != NULL && new_object_str != NULL)
754  |   { /* it was an update */
755  | 	old_obj = rpsl_object_init(old_object_str);
756  | 	error_list = rpsl_object_errors(old_obj);
757  | 	new_obj = rpsl_object_init(new_object_str);
758  | 	error_list = rpsl_object_errors(old_obj);
759  | 
760  |     /* start with the 'notify' in the object itself */
761  |     temp = get_attr_list(old_obj, "notify");
762  |     mntners = get_mntners(old_obj);
763  | 	/* now add the 'mnt-by' from any of the mntners in the old object only */
764  |     temp = g_list_concat(temp, get_mntnfy_vector(mntners));
765  | 	/* now add the 'irt-by' from any of the irts in the old and new objects
766  | 	   if they have just been added or deleted */
767  | 	temp = g_list_concat(temp, NT_check_irtnfy(old_obj, new_obj));
768  |   }
769  |   else if (old_object_str == NULL && new_object_str != NULL)
770  |   { /* it was a creation */
771  | 	new_obj = rpsl_object_init(new_object_str);
772  | 	error_list = rpsl_object_errors(new_obj);
773  | 
774  |     if ( ! rpsl_object_has_error( new_obj, RPSL_ERRLVL_ERROR ) )
775  | 	{
776  |       /* start with the 'notify' in the object itself */
777  |       temp = get_attr_list(new_obj, "notify");
778  |       mntners = get_mntners(new_obj);
779  | 	  /* now add the 'mnt-by' from any of the mntners in the new object only */
780  |       temp = g_list_concat(temp, get_mntnfy_vector(mntners));
781  | 	  /* now add the 'irt-by' from any of the irts in the new object
782  | 		 as they have just been added */
783  | 	  temp = g_list_concat(temp, NT_check_irtnfy(old_obj, new_obj));
784  | 	}
785  |   }
786  |   else if (old_object_str != NULL && new_object_str == NULL)
787  |   { /* it was a deletion */
788  | 	old_obj = rpsl_object_init(old_object_str);
789  | 	error_list = rpsl_object_errors(old_obj);
790  | 
791  |     /* start with the 'notify' in the object itself */
792  |     temp = get_attr_list(old_obj, "notify");
793  |     mntners = get_mntners(old_obj);
794  | 	/* now add the 'mnt-by' from any of the mntners in the old object only */
795  |     temp = g_list_concat(temp, get_mntnfy_vector(mntners));
796  | 	/* now add the 'irt-by' from any of the irts in the old object
797  | 	   as they have just been deleted */
798  | 	temp = g_list_concat(temp, NT_check_irtnfy(old_obj, new_obj));
799  |   }
800  | 
801  |   /* we have to 'unify' the list here!, return_list is now a list of malloc'd email address strings */
802  |   return_list = NT_unify_list(temp);
803  |   rpsl_attr_delete_list( temp );
804  |   if ( old_obj )
805  |     rpsl_object_delete(old_obj);
806  |   if ( new_obj )
807  |     rpsl_object_delete(new_obj);
808  | 
809  |   if (tracing)
810  |   {
811  |     printf( "TRACING: notif email addresses\n" );
812  |     for ( temp=return_list; temp!=NULL; temp=g_list_next(temp) )
813  |       printf( "TRACING: [%s]\n", (char *)(temp->data) );
814  |   }
815  | 
816  |   return return_list;
817  | }
818  | 
819  | 
820  | 
821  | /* Gathers e-mail boxes to which we will forward messages (or rather, objects). It 
822  |    an object, looks up maintainers, finds the addresses (in upd-to attributes) and returns 
823  |    a list of them. */
824  | GList * NT_gather_frwd_addresses(char * object_str)
825  | {
826  |   GList *temp = NULL;
827  |   GList *attr_item = NULL;
828  |   GList *email_list = NULL;
829  |   char *email;
830  |   const GList *error_list = NULL; 
831  |   rpsl_object_t *object;
832  |   GList * mntners = NULL; 
833  | 
834  |   object = rpsl_object_init(object_str);
835  |   error_list = rpsl_object_errors(object);
836  | 
837  |   mntners = get_mntners(object);
838  |   /* get a list of upd-to attributes */
839  |   temp = get_updto_vector(mntners);
840  |   /* now extract the email text strings from the values of these attributes */
841  |   for ( attr_item = temp; attr_item != NULL ; attr_item = g_list_next(attr_item) )
842  |   {
843  |     email = rpsl_attr_get_clean_value((rpsl_attr_t *)(attr_item->data));
844  | printf("NT_gather_frwd_addresses: email [%s]\n", email );
845  |     email_list = g_list_append(email_list, email );
846  |   }
847  |   return email_list;
848  | }
849  | 
850  | 
851  | 
852  | /* Accepts a parsed route object and returns a list of overlapping routes */
853  | overlap_routes get_overlapping_routes_list(rpsl_object_t * object)
854  | {
855  |   char * route_prefix = NULL;
856  |   GList * tmp_list;
857  |   char * result;
858  |   char * query_string;  
859  |   overlap_routes result_routes;
860  |     
861  |   result_routes.less_spec = NULL;
862  |   result_routes.exact_match = NULL;
863  |   result_routes.more_spec = NULL;
864  |       
865  |   tmp_list = rpsl_object_get_attr(object, "route");  
866  | 
867  |   if (tmp_list != NULL && tmp_list->data != NULL)
868  |   {
869  |     route_prefix = rpsl_attr_get_clean_value((rpsl_attr_t *)(tmp_list->data));
870  |   }
871  |   else
872  |   {
873  |     return result_routes; /* then, this wasn't a route object */
874  |   }
875  |   
876  |   /* get the less specific route objects */
877  |   /* form the query string */
878  |   query_string = (char *)malloc(strlen("-Troute -r -l ") + strlen(route_prefix) + 2);
879  |   sprintf(query_string, "-Troute -r -l %s", route_prefix);
880  | 
881  |   /* get the results */ 
882  |   result = send_and_get(query_host, query_port, query_string);
883  |   free(query_string);
884  | 
885  |   /* and fill in the result field  */
886  |   result_routes.less_spec = take_objects(result);
887  | 
888  |   /* get the exact match route objects */
889  |   /* form the query string */
890  |   query_string = (char *)malloc(strlen("-Troute -r -x ") + strlen(route_prefix) + 2);
891  |   sprintf(query_string, "-Troute -r -x %s", route_prefix);
892  | 
893  |   /* get the results */ 
894  |   result = send_and_get(query_host, query_port, query_string);
895  |   free(query_string);
896  |   
897  | 
898  |   /* filter out the route object itself */
899  |   result = UP_filter_out_same_origins(result, object);
900  | 
901  |   /* and fill in the result field  */
902  |   if (result != NULL)
903  |   {
904  |     result_routes.exact_match = take_objects(result);
905  |   }
906  | 
907  |   /* get the more specific route objects */
908  |   /* form the query string */
909  |   query_string = (char *)malloc(strlen("-Troute -r -M ") + strlen(route_prefix) + 2);
910  |   sprintf(query_string, "-Troute -r -M %s", route_prefix);
911  | 
912  |   /* get the results */ 
913  |   result = send_and_get(query_host, query_port, query_string);
914  |   free(query_string);
915  | 
916  |   /* and fill in the result field  */
917  |   result_routes.more_spec = take_objects(result);
918  | 
919  |   /* Return the results */
920  |   return result_routes;
921  | }
922  | 
923  | 
924  | 
925  | /* Gets old and new versions of the object, and creates temporary notification
926  |    files when necessary, and then writes appropriate strings into those
927  |    temporary files. */
928  | void NT_write_all_ntfs(char * old_object, char * new_object, char * formatted_object,
929  |                        const char * tempdir,
930  |                        GHashTable * ntfy_hash,  GHashTable * forwd_hash, GHashTable * cross_hash, 
931  |                        char * from_address)
932  | { 
933  |    GList * e_mail_list = NULL;
934  |    GList * temp = NULL;
935  |    const GList *error_list = NULL; 
936  |    char * e_mail_address = NULL;
937  |    overlap_routes overlapping_routes;
938  |    rpsl_object_t *object;
939  |    char *arg2;
940  | 
941  |    if ( reading_from_mail )
942  |    {
943  |      /* from_address may contain also the name, like "Johnny Bravo <johnny@inter.net>",
944  |         so extract the e-mail address from it */
945  |      e_mail_address = find_email_address(from_address); 
946  | 
947  |      if (tracing)
948  |      {
949  |        printf("TRACING: NT_write_all_ntfs: from_address=[%s], e_mail_address=[%s]\n", from_address, e_mail_address);
950  |      }
951  |    }
952  |    if (old_object != NULL && new_object != NULL)
953  |    { 
954  |      /* it was an update */
955  | 	 object = rpsl_object_init(formatted_object ? formatted_object : new_object);
956  | 	 error_list = rpsl_object_errors(object);
957  | 
958  |      if ( UP_remove_override_attr(object) )
959  |        arg2 = rpsl_object_get_text(object, RPSL_STD_COLUMN);
960  | 	 else
961  | 	 {
962  | 	   /* there was an override attr in this object and it has not been removed */
963  | 	   arg2 = (char *)malloc(2);
964  | 	   strcpy(arg2, "");	/* Don't include object in ack/notif msgs */
965  | 	 }
966  | 
967  |      rpsl_object_delete(object);
968  |    
969  |      e_mail_list = NT_gather_ntfy_addresses(old_object, new_object);
970  |      NT_add_to_ntfy_hash_list(ntfy_hash, e_mail_list); 
971  |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "---\nPREVIOUS OBJECT:\n\n");
972  |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, old_object);
973  |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "\n\nREPLACED BY:\n\n");
974  |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, arg2);
975  |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "\n");
976  |    }
977  |    else if (old_object == NULL && new_object != NULL)
978  |    { 
979  |      /* it was a creation */
980  | 	 object = rpsl_object_init(formatted_object ? formatted_object : new_object);
981  | 	 error_list = rpsl_object_errors(object);
982  | 
983  |      if ( UP_remove_override_attr(object) )
984  |        arg2 = rpsl_object_get_text(object, RPSL_STD_COLUMN);
985  | 	 else
986  | 	 {
987  | 	   /* there was an override attr in this object and it has not been removed */
988  | 	   arg2 = (char *)malloc(2);
989  | 	   strcpy(arg2, "");	/* Don't include object in ack/notif msgs */
990  | 	 }
991  | 
992  |      rpsl_object_delete(object);
993  |    
994  |      e_mail_list = NT_gather_ntfy_addresses(old_object, new_object);
995  |      NT_add_to_ntfy_hash_list(ntfy_hash, e_mail_list); 
996  |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "---\nOBJECT BELOW CREATED:\n\n");
997  |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, arg2);
998  |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "\n");
999  | 
1000 |      /* We'll deal with cross notifications only when we create or delete route objects */
1001 | 	 object = rpsl_object_init(new_object);
1002 | 	 error_list = rpsl_object_errors(object);
1003 | 
1004 |      if (strcmp(rpsl_object_get_class(object), "route") == 0)
1005 | 	 {
1006 |        overlapping_routes = get_overlapping_routes_list(object);
1007 |        if (overlapping_routes.less_spec != NULL || overlapping_routes.exact_match != NULL ||
1008 |           overlapping_routes.more_spec != NULL )
1009 | 	   {
1010 |          NT_add_to_cross_hash(cross_hash, e_mail_address, ADDITION);
1011 |          NT_add_to_cross(e_mail_address, cross_hash, "%s\n\n%s\n\n%s\n\n", cno_explain_add, new_object, cno_overlap_add);
1012 |          if (overlapping_routes.less_spec != NULL)
1013 | 		 {
1014 |            NT_add_to_cross(from_address, cross_hash, "LESS SPECIFIC MATCHES\n\n");
1015 |            for (temp = overlapping_routes.less_spec; temp != NULL; temp = g_list_next(temp))
1016 | 		   {
1017 |              NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data);
1018 |            }
1019 |          }
1020 |          if (overlapping_routes.exact_match != NULL)
1021 | 		 {
1022 |            NT_add_to_cross(from_address, cross_hash, "EXACT MATCHES\n\n");
1023 |            for (temp = overlapping_routes.exact_match; temp != NULL; temp = g_list_next(temp))
1024 | 		   {
1025 |              NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data);
1026 |            }
1027 |          }
1028 |          if (overlapping_routes.more_spec != NULL)
1029 | 		 {
1030 |            NT_add_to_cross(from_address, cross_hash, "MORE SPECIFIC MATCHES\n\n");
1031 |            for (temp = overlapping_routes.more_spec; temp != NULL; temp = g_list_next(temp))
1032 | 		   {
1033 |              NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data);
1034 |            }
1035 |          }
1036 |        }
1037 |      }
1038 | 	 rpsl_object_delete(object);
1039 |    }
1040 |    else if (old_object != NULL && new_object == NULL)
1041 |    { /* it was a deletion */
1042 |      old_object = delete_delete_attrib(old_object);
1043 | 	 object = rpsl_object_init(old_object);
1044 | 	 error_list = rpsl_object_errors(object);
1045 | 
1046 |      if ( UP_remove_override_attr(object) )
1047 |        arg2 = rpsl_object_get_text(object, RPSL_STD_COLUMN);
1048 | 	 else
1049 | 	 {
1050 | 	   /* there was an override attr in this object and it has not been removed */
1051 | 	   arg2 = (char *)malloc(2);
1052 | 	   strcpy(arg2, "");	/* Don't include object in ack/notif msgs */
1053 | 	 }
1054 | 
1055 |      e_mail_list = NT_gather_ntfy_addresses(old_object, new_object);
1056 |      NT_add_to_ntfy_hash_list(ntfy_hash, e_mail_list); 
1057 |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "---\nOBJECT BELOW DELETED:\n\n");
1058 |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, arg2);
1059 |      NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "\n");
1060 | 
1061 |      /* We'll deal with cross notifications only when we create or delete route objects */
1062 |      if (strcmp(rpsl_object_get_class(object), "route") == 0)
1063 | 	 {
1064 |        overlapping_routes = get_overlapping_routes_list(object);
1065 |        if (overlapping_routes.less_spec != NULL || overlapping_routes.exact_match != NULL ||
1066 |           overlapping_routes.more_spec != NULL )
1067 | 	   {
1068 |          NT_add_to_cross_hash(cross_hash, e_mail_address, DELETION);
1069 |          NT_add_to_cross(e_mail_address, cross_hash, "%s\n\n%s\n\n%s\n\n", cno_explain_del, old_object, cno_overlap_del);
1070 |          if (overlapping_routes.less_spec != NULL)
1071 | 		 {
1072 |            NT_add_to_cross(from_address, cross_hash, "LESS SPECIFIC MATCHES\n\n");
1073 |            for (temp = overlapping_routes.less_spec; temp != NULL; temp = g_list_next(temp))
1074 | 		   {
1075 |              NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data);
1076 |            }
1077 |          }
1078 |          if (overlapping_routes.exact_match != NULL)
1079 | 		 {
1080 |            NT_add_to_cross(from_address, cross_hash, "EXACT MATCHES\n\n");
1081 |            for (temp = overlapping_routes.exact_match; temp != NULL; temp = g_list_next(temp))
1082 | 		   {
1083 |              NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data);
1084 |            }
1085 |          }
1086 |          if (overlapping_routes.more_spec != NULL)
1087 | 		 {
1088 |            NT_add_to_cross(from_address, cross_hash, "MORE SPECIFIC MATCHES\n\n");
1089 |            for (temp = overlapping_routes.more_spec; temp != NULL; temp = g_list_next(temp))
1090 | 		   {
1091 |              NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data);
1092 |            }
1093 |          }
1094 |        }
1095 |      }
1096 | 	 rpsl_object_delete(object);
1097 |    }
1098 |    free(arg2);
1099 | }
1100 | 
1101 | 
1102 | 
1103 | /* Gets old and new versions of the object, and creates temporary notification
1104 |    files when necessary, and then writes appropriate strings into those
1105 |    temporary files. */
1106 | void NT_write_all_frwds(char * old_object_str, char * new_object_str, const char * tempdir,
1107 |                        GHashTable * ntfy_hash,  GHashTable * forwd_hash, GHashTable * cross_hash, 
1108 |                        const char * from_address)
1109 | { 
1110 |    GList *e_mail_list = NULL;
1111 |    rpsl_object_t *object;
1112 |    char *arg2;
1113 |    const GList * error_list = NULL;
1114 | 
1115 |    if (tracing)
1116 |    {
1117 |      printf("TRACING: NT_write_all_frwds is running\n");
1118 |    }
1119 |    
1120 |    if ( new_object_str )
1121 |    {
1122 | 	 object = rpsl_object_init(new_object_str);
1123 | 	 error_list = rpsl_object_errors(object);
1124 | 
1125 |      if ( UP_remove_override_attr(object) )
1126 |        arg2 = rpsl_object_get_text(object, RPSL_STD_COLUMN);
1127 | 	 else
1128 | 	 {
1129 | 	   /* there was an override attr in this object and it has not been removed */
1130 | 	   arg2 = (char *)malloc(2);
1131 | 	   strcpy(arg2, "");	/* Don't include object in ack/notif msgs */
1132 | 	 }
1133 |    }
1134 |    
1135 |    if (old_object_str != NULL && new_object_str != NULL)
1136 |    { /* it was an update */
1137 |      e_mail_list = NT_gather_frwd_addresses(old_object_str);
1138 |      NT_add_to_frwd_hash_list(forwd_hash, e_mail_list);
1139 |      NT_add_to_ntfy_list(e_mail_list, forwd_hash, "----\nUPDATE REQUESTED FOR:\n\n");
1140 |      NT_add_to_ntfy_list(e_mail_list, forwd_hash, arg2);
1141 |    }
1142 |    else if (old_object_str == NULL && new_object_str != NULL)
1143 |    { /* it was a creation */
1144 |      e_mail_list = NT_gather_frwd_addresses(new_object_str);
1145 |      NT_add_to_frwd_hash_list(forwd_hash, e_mail_list);
1146 |      NT_add_to_ntfy_list(e_mail_list, forwd_hash, "----\nADDITION REQUESTED FOR:\n\n");
1147 |      NT_add_to_ntfy_list(e_mail_list, forwd_hash, arg2);
1148 |    }
1149 |    else if (old_object_str != NULL && new_object_str == NULL)
1150 |    { /* it was a deletion */
1151 |      e_mail_list = NT_gather_frwd_addresses(old_object_str);
1152 |      NT_add_to_frwd_hash_list(forwd_hash, e_mail_list);
1153 |      NT_add_to_ntfy_list(e_mail_list, forwd_hash, "----\nDELETION REQUESTED FOR:\n\n");
1154 |      NT_add_to_ntfy_list(e_mail_list, forwd_hash, old_object_str);
1155 |    }
1156 | }
1157 | 
1158 | 
1159 | 
1160 | /* Sends the creation forward message which is stored in the temporary file filename.  */
1161 | void NT_send_forw_creation( const char * filename, const char * to_address, const char * mailercommand)
1162 | {
1163 |     char * mail_command_line = NULL;
1164 | 
1165 |     if (to_address != NULL)
1166 | 	{
1167 |       mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(filename) + 128);
1168 |       sprintf(mail_command_line, "%s %s < %s", mailercommand, to_address, filename);
1169 |       system(mail_command_line);
1170 |       free(mail_command_line);
1171 |     }
1172 | }
1173 | 
1174 | 
1175 | /* NT_forw_create_req forwards the maintainer, as-block and irt creation requests
1176 |    to <HUMAILBOX> */
1177 | void NT_forw_create_req(const char * object_str)
1178 | {
1179 |    FILE * forw_file;
1180 |    char * filename;
1181 |    char * replaced_mtfwheader;
1182 |    char * replaced_mtfwtxt;
1183 | 
1184 |    /* allocate space for name.  32 should be enough for PID */
1185 |    filename = (char*)malloc(strlen(tmpdir) + strlen("creat-forw") +34 ); 
1186 |    
1187 |    sprintf(filename, "%s/%s.%i", tmpdir, "creat-forw", (int)(getpid()) );
1188 | 
1189 |    /* create the file */
1190 |    if (( forw_file = fopen(filename, "w")) == NULL)
1191 |    {
1192 |      fprintf(stderr, "NT_forw_create_req: Can't open creation forward file for creating, %s", filename);
1193 |    }
1194 | 
1195 |    replaced_mtfwheader = UP_replace_globals(mtfwheader);
1196 |    replaced_mtfwtxt = UP_replace_globals(mtfwtxt);
1197 |    
1198 |    fprintf(forw_file, "%s\n\n", replaced_mtfwheader);
1199 |    
1200 |    if (reading_from_mail)
1201 |    {
1202 |      fprintf(forw_file, "%s\n\n", replaced_mtfwtxt);
1203 |    }
1204 | 
1205 |    /* print the object */
1206 |    fprintf(forw_file, "%s\n\n", object_str);
1207 |     
1208 |    /* close it */
1209 |    fclose(forw_file);
1210 |     
1211 |    /* send it */ 
1212 |    NT_send_forw_creation(filename, humailbox, mailcmd);
1213 | 
1214 |    /* log it */
1215 |    NT_log_ntfy(filename, forwlog);
1216 |    
1217 |    /* delete it */
1218 |    unlink(filename);
1219 |  
1220 |    /* free the mem */ 
1221 |    free(filename);
1222 |    free(replaced_mtfwheader);
1223 |    free(replaced_mtfwtxt);
1224 | }