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