source: trunk/athena/bin/discuss/server/expunge.c @ 17452

Revision 17452, 13.9 KB checked in by zacheiss, 23 years ago (diff)
Include unistd.h for lseek prototype and SEEK_* macros
Line 
1/*
2 *
3 *      Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology
4 *      Developed by the MIT Student Information Processing Board (SIPB).
5 *      For copying information, see the file mit-copyright.h in this release.
6 *
7 */
8/*
9 *
10 * expunge -- program to expunge a meeting; i.e. really delete those
11 *            deleted transaction.  This program is linked to a server
12 *            so it can use the privileged procedure of create_mtg, and
13 *            the like.
14 *
15 */
16
17#include <stdio.h>
18#include <string.h>
19#if HAVE_FCNTL_H
20#include <fcntl.h>
21#endif
22#include <ctype.h>
23#include <sys/types.h>
24#include <sys/file.h>
25#include <sys/stat.h>
26#include <unistd.h>
27
28#include <discuss/types.h>
29#include <discuss/dsc_et.h>
30#include <discuss/tfile.h>
31#include <discuss/interface.h>
32#include <discuss/acl.h>
33#include "mtg.h"
34
35#define min(a, b) (a < b ? a : b)
36
37static int tempf;
38static char *mtg_name = NULL, *location = NULL, *chairman = NULL, *trn_file = NULL;
39static char *backup_location = NULL;
40static char *future_location = NULL;
41static int found_eof = 0;
42static int error_occurred = 0;
43static char *temp_dir = "/tmp";
44static int daemon_flag = FALSE;
45
46tfile unix_tfile ();
47char *malloc();
48
49static lower(), strip_addr(), extract_full_name();
50static char *get_header();
51
52extern char rpc_caller[];
53extern int has_privs;
54extern int errno;
55extern int no_nuke, use_zephyr;
56
57main (argc, argv)
58int argc;
59char **argv;
60{
61     int i,n,low,high;
62     mtg_info old_mtg_info,new_mtg_info;
63     trn_info3 old_trn_info;
64     int result;
65     dsc_acl *acl_list,*new_acl_list;
66     dsc_acl_entry *ae;
67     char *new_modes, *signature;
68     char new_signature[50],dtest[10];
69     tfile tf;
70     char control_name[256];
71     int control_fd;
72     static struct flock lock;
73
74
75     init_dsc_err_tbl();
76
77     for (i = 1; i < argc; i++) {
78          if (*argv[i] == '-') switch (argv[i][1]) {
79          case 'c':
80               if (++i < argc)
81                    chairman = argv[i];
82               continue;
83
84          case 'n':
85               if (++i < argc)
86                    mtg_name = argv[i];
87               continue;
88
89           case 't':
90               if (++i < argc)
91                   temp_dir = argv[i];
92               continue;
93
94          case 'd':
95               daemon_flag = TRUE;
96               continue;
97
98          default:
99               goto lusage;
100          }
101          if (location == NULL)
102               location = argv[i];
103          else goto lusage;
104     }
105
106     if (location == NULL)
107          goto lusage;                                  /* required */
108
109     has_privs = TRUE;          /* Tell discuss we're special */
110     use_zephyr = 0;            /* Don't notify of every trn copied */
111     strcpy (rpc_caller, "expunger");
112
113     /* First, we get the mtg info to make sure it exists */
114     get_mtg_info (location, &old_mtg_info, &result);
115     if (result != 0) {
116          fprintf(stderr, "%s: %s while getting mtg info\n", location, error_message(result));
117          exit (1);
118     }
119
120     get_acl (location, &result, &acl_list);
121     if (result != 0) {
122          fprintf(stderr, "%s: %s while getting acl\n", location, error_message(result));
123          exit (1);
124     }
125
126     /* Create the new meeting */
127     backup_location = malloc (strlen(location)+5);     /* be generous */
128     strcpy (backup_location, location);
129     strcat (backup_location, "~");
130
131     future_location = malloc (strlen(location)+5);     /* be generous */
132     strcpy (future_location, location);
133     strcat (future_location, "#");
134
135     printf("Creating new meeting\n");
136     fflush(stdout);
137
138     if (mtg_name == NULL) {
139          mtg_name = old_mtg_info.long_name;
140     }
141     if (chairman == NULL) {
142          chairman = old_mtg_info.chairman;
143     }
144
145     /* get acl's on old meeting, so we can make it new one */
146     get_acl (location, &result, &new_acl_list);
147     if (result != 0) {
148          fprintf(stderr, "%s: %s while getting acl\n", backup_location, error_message(result));
149          exit (1);
150     }
151
152     create_mtg_priv (backup_location, mtg_name, old_mtg_info.public_flag,
153                      old_mtg_info.date_created, chairman,
154                      new_acl_list, &result);
155     if (result != 0) {
156          fprintf (stderr, "%s: %s while creating new meeting\n",
157                   location, error_message(result));
158          exit (1);
159     }
160     
161     /* now, do the actual expunging */
162     low = old_mtg_info.lowest;
163     high = old_mtg_info.highest;
164     create_temp ();
165
166expunge_range:
167     for (i = low; i <= high; i++) {
168          get_trn_info3 (location, i, &old_trn_info, &result);
169          if (result != 0 && result != DELETED_TRN && result != EXPUNGED_TRN) {
170               fprintf(stderr,
171                       "Error getting info for transaction [%04d]: %s\n",
172                       i, error_message(result));
173               error_occurred = TRUE;
174          } else if (result != 0) {             /* expunge it */
175               no_nuke = TRUE;
176               printf("Expunging transaction [%04d]\n", i);
177               expunge_trn (backup_location, i, &result);
178               no_nuke = FALSE;
179               if (result != 0) {
180                    fprintf(stderr,
181                            "Error expunging transaction [%04d]: %s\n",
182                            i, error_message(result));
183                    error_occurred = TRUE;
184               }
185          } else if (result == 0) {
186               ftruncate(tempf,0);
187               lseek(tempf,0,SEEK_SET);
188               tf = unix_tfile (tempf);
189
190               get_trn (location, i, tf, &result);
191               if (result != 0) {
192                    fprintf(stderr, "Error getting transaction [%04d]: %s\n",
193                            i, error_message(result));
194                    error_occurred = TRUE;
195                    free(old_trn_info. author);
196                    free(old_trn_info.subject);
197                    continue;
198               }
199
200               tdestroy (tf);
201
202               signature = old_trn_info.signature;
203               if (daemon_flag && old_trn_info.signature != NULL) {
204                    memmove(dtest, old_trn_info.signature,  7);
205                    dtest[7] = '\0';
206                    if (!strcmp(dtest,"daemon@")) {
207                         if (get_from_signature(tempf, new_signature, sizeof(new_signature)))
208                              signature = new_signature;
209                    }
210               }
211               lseek(tempf,0,SEEK_SET);
212               tf = unix_tfile (tempf);
213               no_nuke = TRUE;
214               add_trn_priv (backup_location, tf, old_trn_info.subject,
215                             signature, old_trn_info.pref,
216                             old_trn_info.current, old_trn_info.author,
217                             old_trn_info.date_entered, old_trn_info.flags,
218                             &n, &result);
219               no_nuke = FALSE;
220               if (result != 0) {
221                    fprintf(stderr,
222                            "Error getting info for transaction %d: %s\n", i,
223                            error_message(result));
224                    error_occurred = TRUE;
225               }
226               tdestroy(tf);
227               free(old_trn_info.author);
228               free(old_trn_info.subject);
229               free(old_trn_info.signature);
230          }
231     }
232
233     /* Check if any new transactions have been added */
234     free(old_mtg_info.long_name);
235     free(old_mtg_info.chairman);
236     free(old_mtg_info.location);
237     get_mtg_info(location, &old_mtg_info, &result);
238     if (result != 0) {
239          fprintf(stderr, "%s: %s while getting mtg info\n", location, error_message(result));
240          error_occurred = TRUE;
241     } else if (old_mtg_info.highest > high) {          /* New transactions added */
242          low = high+1;
243          high = old_mtg_info.highest;
244          goto expunge_range;
245     }
246
247     strcpy(control_name, location);
248     strcat(control_name, "/control");
249     if ((control_fd = open (control_name, O_RDWR, 0700)) < 0) {
250          error_occurred = TRUE;
251     } else {
252          lock.l_type = F_WRLCK;
253          lock.l_start = 0;
254          lock.l_whence = 0;
255          lock.l_len = 0;
256          fcntl(control_fd, F_SETLKW, &lock);
257
258          free(old_mtg_info.long_name);
259          free(old_mtg_info.chairman);
260          free(old_mtg_info.location);
261
262          no_nuke = TRUE;
263          get_mtg_info(location, &old_mtg_info, &result);
264          if (result != 0) {           
265               fprintf(stderr, "%s: %s while getting mtg info\n", location, error_message(result));
266               error_occurred = TRUE;
267
268               lock.l_type = F_UNLCK;
269               lock.l_start = 0;
270               lock.l_whence = 0;
271               lock.l_len = 0;
272               fcntl(control_fd, F_SETLK, &lock);
273
274               close(control_fd);
275          } else if (old_mtg_info.highest > high) {             /* New transactions added */
276               low = high + 1;
277               high = old_mtg_info.highest;
278               lock.l_type = F_UNLCK;
279               lock.l_start = 0;
280               lock.l_whence = 0;
281               lock.l_len = 0;
282               fcntl(control_fd, F_SETLK, &lock);
283               close(control_fd);
284               goto expunge_range;
285          }
286     }
287
288     /* When we get here, we have the old meeting locked.  Now we do the move
289        as atomically as we can */
290     if (!error_occurred) {
291          if (rename(location, future_location) < 0) {
292               perror("rename of old meeting failed");
293               exit (1);
294          }
295          if (rename(backup_location, location) < 0) {
296               perror("rename of new meeting");
297               exit (1);
298          }
299          remove_mtg (future_location, &result);
300          if (result != 0) {
301               fprintf(stderr, "%s: %s while removing new meeting.\n",
302                       location, error_message(result));
303               exit (1);
304          }
305     } else exit (1);                           /* error occurred */
306
307     exit (0);
308
309lusage:
310     fprintf(stderr, "usage: expunge mtg_location {-c chairman} {-n name}\n");
311     exit (1);
312}
313
314/*
315 *
316 * create_temp () -- Create temp file, and let it be tempf.
317 *
318 */
319create_temp()
320{
321     char *filename;
322
323     filename = malloc (strlen (temp_dir) + 20);
324     strcpy (filename, temp_dir);
325     strcat (filename, "/rcXXXXXX");
326     mktemp (filename);
327
328     tempf = open (filename, O_RDWR | O_CREAT, 0700);
329     if (tempf < 0) {
330          fprintf (stderr, "Cannot open temp file\n");
331          exit (1);
332     }
333}
334
335/*
336 *
337 *   get_from_signature () -- Look in the file file_no, looking for a
338 *      From: line.  Construct a signature from this from line, returning
339 *      it in sign, with a maximum length of sign_len.
340 *
341 */
342
343int
344get_from_signature(file_no, sign, sign_len)
345int file_no;
346char *sign;
347int sign_len;
348{
349     char buf[2048];
350     int len;
351     char *cp, *hp;
352
353     lseek(file_no, 0, SEEK_SET);
354     len = read(file_no, buf, sizeof(buf)-1);
355     buf[len] = '\0';
356
357     hp = get_header(buf, "from");
358     if (hp == NULL)
359          return(0);
360
361     cp = strchr(hp, ':');
362     if (cp == NULL)
363          return(0);
364
365     cp++;
366
367     extract_full_name(cp, sign, sign_len);
368     return(1);
369}
370
371/* Stolen from TechMail */
372
373static
374lower(s)
375char *s;
376{
377     while (*s) {
378          if (isupper(*s))
379               *s = tolower(*s);
380          s++;
381     }
382     return;
383}
384
385static
386strip_addr(addr, dest, dest_size)
387char *addr,*dest;
388int dest_size;
389{
390     char *dest_end,*dp,*sp,*quote_start;
391     int paren_level,found_angle;
392
393     dest_end = &dest[dest_size-1];
394     dp = dest;
395     sp = addr;
396     paren_level = 0;
397
398eat_white:
399     while (isspace(*sp) && *sp != '\n')
400          sp++;
401
402     if (*sp == '(')
403          goto eat_comment;
404
405     if (*sp == '"')
406          goto eat_string;
407
408     if (*sp == '<') {
409          dp = dest;
410          sp++;
411          found_angle = TRUE;
412          goto eat_white;
413     }
414
415     if (*sp == '>' && found_angle) {
416          *sp++;
417          goto eat_white;
418     }
419
420     if (*sp == '\0' || *sp == '\n') {
421          *dp++ = '\0';
422          goto post_proc;
423     }
424
425     *dp++ = *sp++;
426     if (dp == dest_end) {
427          *dp++ = '\0';
428          goto post_proc;
429     }
430
431     goto eat_white;
432
433eat_comment:
434     paren_level++;
435     sp++;
436
437cont_comment:
438     while (*sp != ')' && *sp != '(' && *sp) {
439          sp++;
440     }
441
442     if (*sp == '\0') {
443          *dp = '\0';
444          goto post_proc;
445     }
446
447     if (*sp == '(')
448          goto eat_comment;
449
450     sp++;              /* ) */
451     paren_level--;
452     if (paren_level <= 0)
453          goto eat_white;
454
455     goto cont_comment;
456
457eat_string:
458     quote_start = sp;
459     sp++;
460
461     while(*sp != '"' && *sp)
462          sp++;
463
464     if (!*sp) {
465          *dp = '\0';
466          goto post_proc;
467     }
468
469     if (*++sp == '@') {                /* "foo"@bar */
470          sp = quote_start;
471          *dp++ = *sp++;
472          while (dp < dest_end && *sp != '"')
473               *dp++ = *sp++;
474
475          if (dp == dest_end) {
476               *dp = '\0';
477               goto post_proc;
478          }
479          *dp++ = *sp++;
480          if (dp == dest_end) {
481               *dp++ = '\0';
482               goto post_proc;
483          }
484     }
485     goto eat_white;
486
487     /* No post processing */
488post_proc:
489     return;
490}
491
492/*
493 *
494 *   Routine to extract a full name from an address.  If no full name
495 *   can be found, then we simply return the stripped address.
496 *
497 */
498
499static
500extract_full_name(addr, dest, dest_size)
501char *addr,*dest;
502int dest_size;
503{
504     char *dest_end,*dp,*sp,*bracket,*close_paren;
505     int paren_level,non_white;
506
507     dest_end = &dest[dest_size-1];
508     dp = dest;
509     sp = addr;
510
511     /* Find angle bracket (if possible) */
512     while (*sp && *sp != '<' && *sp != '\n')
513          sp++;
514
515     bracket = NULL;
516     if (*sp == '<')
517          bracket = sp;
518
519     non_white = 0;
520     if (bracket != NULL) {
521          for (sp = addr; sp < bracket; sp++) {
522               if (!isspace(*sp) && *sp != '"')
523                    non_white++;
524          }
525     }
526
527     if (non_white > 1) {               /* We have a name */
528          sp = addr;
529          while (isspace(*sp) || *sp == '"')    /* Skip leading spaces */
530               sp++;
531
532          while (isspace(*(bracket-1)) || *(bracket-1) == '"')  /* Skip trailing spaces */
533               bracket--;
534
535          /* Copy it over */
536          while (sp < bracket && dp < dest_end)
537               *dp++ = *sp++;
538
539          *dp++ = '\0';
540          return;
541     }
542
543     /* Now, let's see if we have name in a comment (look back from the
544        end for a parenthesis. */
545     for (sp = addr; *sp && *sp != '\n'; sp++)
546          ;
547
548     sp--;
549     while (sp > addr && isspace(*sp))
550          sp--;
551
552     if (*sp == ')') {                  /* Name in comment */
553          close_paren = sp;
554          paren_level = 1;
555          sp--;
556
557          for (;sp > addr; sp--) {
558               if (*sp == ')')
559                    paren_level++;
560               else if (*sp == '(') {
561                    paren_level--;
562                    if (paren_level == 0)
563                         break;
564               }
565          }
566
567          if (*sp == '(') {             /* Copy it over */
568               sp++;
569
570               while(isspace(*sp))
571                    sp++;
572
573               while (sp < close_paren && dp < dest_end)
574                    *dp++ = *sp++;
575
576               *dp = '\0';
577               return;
578          }
579     }
580
581     strip_addr(addr, dest, dest_size);
582     return;
583}         
584
585static char *
586get_header(hstring, hname)
587char *hstring, *hname;
588{
589     char *eolp, *colonp, *cp;
590     int name_len;
591     char field[33];
592
593     cp = hstring;
594     name_len = strlen(hname);
595
596     while (*cp != '\0') {
597          eolp = strchr(cp, '\n');
598          colonp = strchr(cp, ':');
599
600          if (eolp == NULL || colonp == NULL || eolp == cp)
601               return(0);
602
603          if (colonp > eolp || colonp - cp != name_len) {
604               cp = eolp+1;
605               continue;
606          }
607
608          /* Chance of a match, copy header over to name, and lower it */
609          memmove(field,cp,  colonp - cp);
610          field[colonp - cp] = '\0';
611          lower(field);
612          if (!strcmp(field,hname))
613               return(cp);
614          cp = eolp + 1;
615     }
616
617     return(NULL);
618}
Note: See TracBrowser for help on using the repository browser.