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

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