]> andersk Git - moira.git/blob - regtape/employee.pc
remove -d and -n options.
[moira.git] / regtape / employee.pc
1 /* $Id$
2  *
3  * Load data into Moira from Personnel Office data file
4  *
5  * Copyright (C) 1990-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include <moira.h>
12 #include <moira_site.h>
13 #include <moira_schema.h>
14
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <string.h>
18
19 EXEC SQL INCLUDE sqlca;
20 extern void sqlglm(char *, unsigned int *, unsigned int *);
21
22 RCSID("$Header$");
23
24 #define WHO 11859               /* root */
25 #define PROG "emp-tape"
26
27 #define MAX_ID_VALUE    31999
28 #define MIN_ID_VALUE    101
29
30 /* File format is:
31
32 0-8     id number
33 9-38    name
34 39-62   office address
35 63-74   phone1
36 75-86   phone2
37 87-106  dept
38 107-156 title
39 157-186 username
40 187-241 host
41
42 */
43
44 #define LOC_ID 0
45 #define LOC_NAME 9
46 #define LOC_OFFICE 39
47 #define LOC_PHONE 63
48 #define LOC_PHONE2 75
49 #define LOC_DEPT 87
50 #define LOC_TITLE 137
51 #define LOC_USERNAME 187
52 #define LOC_HOST 217
53
54 #define LEN_ID 9
55 #define LEN_NAME 30
56 #define LEN_OFFICE 24
57 #define LEN_PHONE 12
58 #define LEN_PHONE2 12
59 #define LEN_DEPT 50
60 #define LEN_TITLE 50
61 #define LEN_USERNAME 30
62 #define LEN_HOST 55
63
64
65 struct entry {
66   char *name;
67   char *last;
68   char *first;
69   char *middle;
70   char *title;
71   char *class;
72   char *id;
73   char *dept;
74   char *address;
75   char *phone;
76   char *phone2;
77   int highid;
78 };
79
80 struct entry *get_next_entry(FILE *in);
81 void process_entry(struct entry *e);
82 void newuser(struct entry *e);
83 int set_next_users_id(int limit);
84 int set_next_uid(int high);
85 void sqlexit(void);
86 void dbmserr(char *where, int what);
87
88 char *whoami;
89 int highid = 0;
90
91 #define sqlfail() (sqlca.sqlcode && sqlca.sqlcode != 1403)
92 #define SQL_DUPLICATE -2112
93
94
95 int main(int argc, char **argv)
96 {
97   FILE *in;
98   struct entry *e;
99   int i, wait = 0;
100   char buf[80], *file = NULL;
101   EXEC SQL BEGIN DECLARE SECTION;
102   char *db = "moira";
103   EXEC SQL END DECLARE SECTION;
104
105   whoami = strrchr(argv[0], '/');
106   if (whoami)
107     whoami++;
108   else
109     whoami = argv[0];
110
111   setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
112   setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
113
114   for (i = 1; i < argc; i++)
115     {
116       if (!strcmp(argv[i], "-w"))
117         wait++;
118       else if (!strcmp(argv[i], "-h"))
119         highid++;
120       else if (file)
121         fprintf(stderr, "Usage: %s [-w] [-D] [-n] inputfile\n", whoami);
122       else
123         file = argv[i];
124     }
125
126   in = fopen(file, "r");
127   if (!in)
128     {
129       fprintf(stderr, "Unable to open %s for input\n", file);
130       exit(1);
131     }
132
133   initialize_sms_error_table();
134
135   EXEC SQL CONNECT :db IDENTIFIED BY :db;
136   if (sqlca.sqlcode)
137     {
138       dbmserr("opening database", sqlca.sqlcode);
139       exit(1);
140     }
141
142   while ((e = get_next_entry(in)))
143     {
144       process_entry(e);
145       EXEC SQL COMMIT WORK;
146       if (sqlca.sqlcode)
147         {
148           dbmserr("committing work", sqlca.sqlcode);
149           exit(1);
150         }
151       if (wait)
152         {
153           printf("Next");
154           fflush(stdout);
155           fgets(buf, sizeof(buf), stdin);
156         }
157     }
158
159   exit(0);
160 }
161
162 struct entry *get_next_entry(FILE *in)
163 {
164   static struct entry e;
165   static char buf[BUFSIZ];
166   static char name[LEN_NAME + 1], sname[LEN_NAME + 1], id[LEN_ID + 1];
167   static char office[LEN_OFFICE + 1], phone[LEN_PHONE + 1];
168   static char phone2[LEN_PHONE2 + 1], dept[LEN_DEPT + 1], title[LEN_TITLE + 1];
169   static char username[LEN_USERNAME + 1], host[LEN_HOST + 1];
170   int ends_sr, ends_jr, ends_iii, ends_iv, ends_ii, ends_v;
171   char *p, *q;
172
173   if (!fgets(buf, sizeof(buf), in))
174     return NULL;
175
176   strncpy(id, &buf[LOC_ID], LEN_ID);
177   id[LEN_ID] = '\0';
178   strncpy(name, &buf[LOC_NAME], LEN_NAME);
179   name[LEN_NAME] = '\0';
180   strncpy(office, &buf[LOC_OFFICE], LEN_OFFICE);
181   office[LEN_OFFICE] = '\0';
182   strncpy(phone, &buf[LOC_PHONE], LEN_PHONE);
183   phone[LEN_PHONE] = '\0';
184   strncpy(phone2, &buf[LOC_PHONE2], LEN_PHONE2);
185   phone2[LEN_PHONE2] = '\0';
186   strncpy(dept, &buf[LOC_DEPT], LEN_DEPT);
187   dept[LEN_DEPT] = '\0';
188   strncpy(title, &buf[LOC_TITLE], LEN_TITLE);
189   title[LEN_TITLE] = '\0';
190   strncpy(username, &buf[LOC_USERNAME], LEN_USERNAME);
191   username[LEN_USERNAME] = '\0';
192   strncpy(host, &buf[LOC_HOST], LEN_HOST);
193   host[LEN_HOST] = '\0';
194
195   strcpy(sname, name);
196   e.name = strtrim(sname);
197   p = strchr(name, ',');
198   if (p)
199     *p = '\0';
200   e.last = strtrim(name);
201   if (p)
202     {
203       p++;
204       while (isspace(*p))
205         p++;
206       e.first = p;
207       if ((p = strchr(e.first, ' ')))
208         {
209           *p = '\0';
210           e.first = strtrim(e.first);
211           e.middle = strtrim(p + 1);
212         }
213       else
214         {
215           e.first = strtrim(e.first);
216           e.middle = "";
217         }
218     }
219   else
220     {
221       e.first = "";
222       e.middle = "";
223     }
224   ends_sr = ends_jr = ends_iii = ends_iv = ends_ii = ends_v = 0;
225   LookForSt(e.last);
226   LookForO(e.last);
227   LookForJrAndIII(e.last, &ends_jr, &ends_sr, &ends_ii, &ends_iii,
228                   &ends_iv, &ends_v);
229   LookForJrAndIII(e.first, &ends_jr, &ends_sr, &ends_ii, &ends_iii,
230                   &ends_iv, &ends_v);
231   FixCase(e.last);
232   FixCase(e.first);
233   FixCase(e.middle);
234
235   e.id = id;
236
237   /* The following is really gross, but it happens to successfully convert
238    * new-style Warehouse office descriptions into (more-readable) old-style
239    * Personnel Office office descriptions.
240    */
241   e.address = p = strtrim(office);
242   while (*p && !isspace(*p))
243     p++;
244   q = p;
245   while (isspace(*q))
246     q++;
247   if (*q && q < e.address + LEN_OFFICE / 2)
248     {
249       *p++ = '-';
250       while (*q && q < e.address + LEN_OFFICE / 2)
251         {
252           if (*q != ' ' && *q != '-')
253             *p++ = *q;
254           if (q > p)
255             *q = ' ';
256           q++;
257         }
258       memset(p, ' ', q - p);
259     }
260
261   p = e.address + LEN_OFFICE / 2;
262   while (*p && !isspace(*p))
263     p++;
264   q = p;
265   while (isspace(*q))
266     q++;
267   if (*q)
268     {
269       *p++ = '-';
270       while (*q)
271         {
272           if (*q != ' ' && *q != '-')
273             *p++ = *q;
274           if (q > p)
275             *q = ' ';
276           q++;
277         }
278       memset(p, ' ', q - p);
279     }
280   strtrim(e.address);
281
282   e.phone = strtrim(phone);
283   e.phone2 = strtrim(phone2);
284   e.dept = strtrim(dept);
285   e.title = strtrim(title);
286
287   e.class = "MITS";
288   e.highid = highid;
289   if (strstr(e.title, "PROF") || strstr(e.title, "LECTURE"))
290     e.class = "FACULTY";
291   if (!strcmp(e.dept, "LINCOLN LAB"))
292     {
293       e.class = "LINCOLN";
294       e.highid = 1;
295     }
296
297   return &e;
298 }
299
300 void process_entry(struct entry *e)
301 {
302   int changed;
303   char buf[MAX_FIELD_WIDTH], *from, *to;
304   EXEC SQL BEGIN DECLARE SECTION;
305   char *first, *last, *middle, *sid, *name, *rdept;
306   char *rtitle, *raddr, *rhphone, *rophone, *prog;
307   char class[USERS_TYPE_SIZE], oaddr[USERS_OFFICE_ADDR_SIZE];
308   char ophone[USERS_OFFICE_PHONE_SIZE], dept[USERS_DEPARTMENT_SIZE];
309   char dfirst[USERS_FIRST_SIZE], dlast[USERS_LAST_SIZE];
310   char dmiddle[USERS_MIDDLE_SIZE];
311   int id, status, who;
312   EXEC SQL END DECLARE SECTION;
313
314   who = WHO;
315   prog = PROG;
316   first = e->first;
317   if (strlen(first) > USERS_FIRST_SIZE - 1)
318     first[USERS_FIRST_SIZE - 1] = '\0';
319   last = e->last;
320   if (strlen(last) > USERS_LAST_SIZE - 1)
321     last[USERS_LAST_SIZE - 1] = '\0';
322   middle = e->middle;
323   if (strlen(middle) > USERS_MIDDLE_SIZE - 1)
324     middle[USERS_MIDDLE_SIZE - 1] = '\0';
325   sid = e->id;
326   id = 0;
327
328   /* Get user info */
329   EXEC SQL SELECT users_id, first, last, middle, type, office_addr,
330     office_phone, department, status
331     INTO :id, :dfirst, :dlast, :dmiddle, :class, :oaddr,
332     :ophone, :dept, :status
333     FROM users
334     WHERE clearid = :sid AND status != 3;
335   if (sqlfail())
336     {
337       if (sqlca.sqlcode == SQL_DUPLICATE)
338         {
339           com_err(whoami, 0, "duplicate ID number %s on user %s %s",
340                   sid, first, last);
341           return;
342         }
343       else
344         sqlexit();
345     }
346   if (id == 0)
347     {
348       newuser(e);
349       return;
350     }
351   strtrim(dfirst);
352   strtrim(dlast);
353   strtrim(dmiddle);
354   strtrim(class);
355
356   /* Update class/state if necessary.  (Exclude several spacial cases.) */
357   if (strcmp(e->class, class) &&
358       strcmp(class, "STAFF") && strcmp(class, "SIPBMEM") &&
359       strcmp(class, "KNIGHT"))
360     {
361       com_err(whoami, 0, "updating class for %s %s from \"%s\" to \"%s\"",
362               first, last, class, e->class);
363       if (status == US_NOT_ALLOWED)
364         status = US_NO_LOGIN_YET;
365       if (status == US_ENROLL_NOT_ALLOWED)
366         status = US_ENROLLED;
367       strcpy(class, e->class);
368       EXEC SQL UPDATE users
369         SET type = NVL(:class, CHR(0)), status = :status,
370         modtime = SYSDATE, modby = :who, modwith = :prog
371         WHERE users_id = :id;
372       if (sqlca.sqlcode)
373         {
374           dbmserr("updating user", sqlca.sqlcode);
375           exit(1);
376         }
377     }
378
379   /* Update name if necessary */
380   if (strcmp(first, strtrim(dfirst)) ||
381       strcmp(last, strtrim(dlast)) ||
382       strcmp(middle, strtrim(dmiddle)))
383     {
384       com_err(whoami, 0, "updating real name for %s%s%s %s (was %s%s%s %s)",
385               first, *middle ? " " : "", middle, last,
386               dfirst, *dmiddle ? " " : "", dmiddle, dlast);
387       EXEC SQL UPDATE users
388         SET first = NVL(:first, CHR(0)), last = NVL(:last, CHR(0)),
389         middle = NVL(:middle, CHR(0)), modby = :who, modwith = :prog,
390         modtime = SYSDATE
391         WHERE users_id = :id;
392       if (sqlca.sqlcode)
393         {
394           dbmserr("updating name", sqlca.sqlcode);
395           exit(1);
396         }
397     }
398
399   changed = 0;
400   strcpy(buf, e->address);
401   while ((to = strchr(buf, ',')))
402     *to = ';';
403   while ((to = strchr(buf, ':')))
404     *to = ';';
405   if (strncmp(strtrim(oaddr), buf, USERS_OFFICE_ADDR_SIZE - 1))
406     {
407       changed++;
408       com_err(whoami, 0, "office for %s %s changed from \"%s\" to \"%s\"",
409               first, last, oaddr, buf);
410     }
411   strncpy(oaddr, buf, USERS_OFFICE_ADDR_SIZE - 1);
412   oaddr[USERS_OFFICE_ADDR_SIZE - 1] = '\0';
413
414   from = e->phone;
415   to = buf;
416   while (*from)
417     {
418       if (isdigit(*from))
419         *to++ = *from;
420       from++;
421     }
422   *to = '\0';
423   if (strncmp(strtrim(ophone), buf, USERS_OFFICE_PHONE_SIZE - 1))
424     {
425       changed++;
426       com_err(whoami, 0, "Phone for %s %s changed from \"%s\" to \"%s\"",
427               first, last, ophone, buf);
428     }
429   strncpy(ophone, buf, USERS_OFFICE_PHONE_SIZE - 1);
430   ophone[USERS_OFFICE_PHONE_SIZE - 1] = '\0';
431
432   FixCase(e->dept);
433   FixCase(e->title);
434   if (strncmp(strtrim(dept), e->dept, USERS_DEPARTMENT_SIZE - 1))
435     {
436       changed++;
437       com_err(whoami, 0, "Department for %s %s changed from \"%s\" to \"%s\"",
438               first, last, dept, e->dept);
439     }
440   strncpy(dept, e->dept, USERS_DEPARTMENT_SIZE - 1);
441   dept[USERS_DEPARTMENT_SIZE - 1] = '\0';
442
443   sid = e->id;
444   name = e->name;
445   rdept = e->dept;
446   rtitle = e->title;
447   raddr = e->address;
448   rhphone = e->phone;
449   rophone = e->phone2;
450
451   if (changed)
452     {
453       com_err(whoami, 0, "updating finger for %s %s", first, last);
454       EXEC SQL UPDATE users
455         SET office_addr = NVL(:oaddr, CHR(0)),
456         office_phone = NVL(:ophone, CHR(0)), department = NVL(:dept, CHR(0)),
457         fmodtime = SYSDATE, fmodby = :who, fmodwith = :prog,
458         xname = NVL(:name, CHR(0)), xdept = NVL(:rdept, CHR(0)),
459         xtitle = NVL(:rtitle, CHR(0)), xaddress = NVL(:raddr, CHR(0)),
460         xphone1 = NVL(:rhphone, CHR(0)), xphone2 = NVL(:rophone, CHR(0)),
461         xmodtime = SYSDATE, clearid = NVL(:sid, CHR(0))
462         WHERE users_id = :id;
463       if (sqlca.sqlcode)
464         {
465           dbmserr(NULL, sqlca.sqlcode);
466           exit(1);
467         }
468     }
469   else
470     {
471       EXEC SQL UPDATE users
472         SET xname = NVL(:name, CHR(0)), xdept = NVL(:rdept, CHR(0)),
473         xtitle = NVL(:rtitle, CHR(0)), xaddress = NVL(:raddr, CHR(0)),
474         xphone1 = NVL(:rhphone, CHR(0)), xphone2 = NVL(:rophone, CHR(0)),
475         xmodtime = SYSDATE, clearid = NVL(:sid, CHR(0))
476         WHERE users_id = :id;
477       if (sqlca.sqlcode)
478         {
479           dbmserr(NULL, sqlca.sqlcode);
480           exit(1);
481         }
482     }
483 }
484
485
486 void newuser(struct entry *e)
487 {
488   char *from, *to;
489   EXEC SQL BEGIN DECLARE SECTION;
490   int id, uid, st, who;
491   char *last, *first, *class, *middle, login[USERS_LOGIN_SIZE], *sid;
492   char fullname[USERS_FULLNAME_SIZE], *prog;
493   char oaddr[USERS_OFFICE_ADDR_SIZE], ophone[USERS_OFFICE_PHONE_SIZE];
494   char dept[USERS_DEPARTMENT_SIZE], *name, *title;
495   char *rdept, *rhphone, *rophone;
496   EXEC SQL END DECLARE SECTION;
497
498   who = WHO;
499   prog = PROG;
500   strncpy(oaddr, e->address, USERS_OFFICE_ADDR_SIZE - 1);
501   oaddr[USERS_OFFICE_ADDR_SIZE - 1] = '\0';
502   while ((to = strchr(oaddr, ',')))
503     *to = ';';
504   while ((to = strchr(oaddr, ':')))
505     *to = ';';
506   from = e->phone;
507   to = ophone;
508   while (*from)
509     {
510       if (isdigit(*from))
511         *to++ = *from;
512       from++;
513     }
514   *to = '\0';
515   FixCase(e->dept);
516   strncpy(dept, e->dept, USERS_DEPARTMENT_SIZE - 1);
517   dept[USERS_DEPARTMENT_SIZE - 1] = '\0';
518
519   id = set_next_users_id(0);
520   uid = set_next_uid(e->highid);
521   sprintf(login, "#%d", uid);
522   last = e->last;
523   first = e->first;
524   middle = e->middle;
525   class = e->class;
526   if (*middle)
527     sprintf(fullname, "%s %s %s", first, middle, last);
528   else
529     sprintf(fullname, "%s %s", first, last);
530   st = US_NO_LOGIN_YET;
531
532   sid = e->id;
533   name = e->name;
534   rdept = e->dept;
535   title = e->title;
536   rhphone = e->phone;
537   rophone = e->phone2;
538
539   com_err(whoami, 0, "adding user %s %s", e->first, e->last);
540
541   EXEC SQL INSERT INTO users
542     (login, users_id, unix_uid, shell, last, first, middle, status,
543      clearid, type, modtime, modby, modwith, fullname, office_addr,
544      office_phone, department, fmodtime, fmodby, fmodwith,
545      potype, xname, xdept, xtitle, xaddress, xphone1, xphone2, xmodtime)
546     VALUES (:login, :id, :uid, '/bin/athena/tcsh',
547             NVL(:last, CHR(0)), NVL(:first, CHR(0)), NVL(:middle, CHR(0)),
548             :st, NVL(:sid, CHR(0)), NVL(:class, CHR(0)), SYSDATE, :who, :prog,
549             NVL(:fullname, CHR(0)), NVL(:oaddr, CHR(0)), NVL(:ophone, CHR(0)),
550             NVL(:dept, CHR(0)), SYSDATE, :who, :prog, 'NONE',
551             NVL(:name, CHR(0)), NVL(:rdept, CHR(0)), NVL(:title, CHR(0)),
552             NVL(:oaddr, CHR(0)), NVL(:rhphone, CHR(0)), NVL(:rophone, CHR(0)),
553             SYSDATE);
554   if (sqlca.sqlcode)
555     {
556       dbmserr("adding user", sqlca.sqlcode);
557       exit(1);
558     }
559 }
560
561
562 int set_next_users_id(int limit)
563 {
564   EXEC SQL BEGIN DECLARE SECTION;
565   int flag, value, retval;
566   EXEC SQL END DECLARE SECTION;
567
568   EXEC SQL SELECT value INTO :value FROM numvalues
569     WHERE name = 'users_id';
570   if (sqlfail())
571     sqlexit();
572   if (sqlca.sqlerrd[2] != 1)
573     {
574       EXEC SQL ROLLBACK;
575       com_err(whoami, MR_INTERNAL, "values table inconsistancy");
576       exit(1);
577     }
578
579   flag = 0;
580   EXEC SQL SELECT users_id INTO :flag FROM users
581     WHERE users_id = :value;
582   if (sqlfail())
583     sqlexit();
584   if (sqlca.sqlerrd[2] == 0)
585     flag = 0;
586   while (flag)
587     {
588       value++;
589       if (limit && value > MAX_ID_VALUE)
590         value = MIN_ID_VALUE;
591       flag = 0;
592       EXEC SQL SELECT users_id INTO :flag FROM users
593         WHERE users_id = :value;
594       if (sqlfail())
595         sqlexit();
596       if (sqlca.sqlerrd[2] == 0)
597         flag = 0;
598     }
599
600   retval = value++;
601   if (limit && value > MAX_ID_VALUE)
602     value = MIN_ID_VALUE;
603   EXEC SQL UPDATE numvalues SET value = :value
604     WHERE name = 'users_id';
605   if (sqlca.sqlcode)
606     {
607       dbmserr("assigning ID", sqlca.sqlcode);
608       exit(1);
609     }
610   return retval;
611 }
612
613 int set_next_uid(int high)
614 {
615   EXEC SQL BEGIN DECLARE SECTION;
616   int flag, initial, value, retval;
617   char *name;
618   EXEC SQL END DECLARE SECTION;
619
620   if (high)
621     name = "high_uid";
622   else
623     name = "unix_uid";
624
625   EXEC SQL SELECT value INTO :initial FROM numvalues
626     WHERE name = :name;
627   if (sqlfail())
628     sqlexit();
629   if (sqlca.sqlerrd[2] != 1)
630     {
631       EXEC SQL ROLLBACK;
632       com_err(whoami, MR_INTERNAL, "values table inconsistancy");
633       exit(1);
634     }
635
636   value = initial;
637   flag = 0;
638   EXEC SQL SELECT COUNT(unix_uid) INTO :flag
639     FROM users WHERE unix_uid = :value;
640   if (sqlfail())
641     sqlexit();
642   while (flag)
643     {
644       value++;
645       if (!high && value > MAX_ID_VALUE)
646         value = MIN_ID_VALUE;
647       if (value == initial)
648         {
649           com_err(whoami, 0, "Out of uids!");
650           EXEC SQL ROLLBACK WORK;
651           exit(1);
652         }
653       flag = 0;
654       EXEC SQL SELECT COUNT(unix_uid) INTO :flag
655         FROM users WHERE unix_uid = :value;
656       if (sqlfail())
657         sqlexit();
658     }
659
660   retval = value++;
661   if (!high && value > MAX_ID_VALUE)
662     value = MIN_ID_VALUE;
663   EXEC SQL UPDATE numvalues SET value = :value WHERE name = :name;
664   if (sqlca.sqlcode)
665     {
666       dbmserr("assigning ID", sqlca.sqlcode);
667       exit(1);
668     }
669   return retval;
670 }
671
672
673 void sqlexit(void)
674 {
675   dbmserr(NULL, sqlca.sqlcode);
676   EXEC SQL ROLLBACK WORK;
677   exit(1);
678 }
679
680 void dbmserr(char *where, int what)
681 {
682   char err_msg[256];
683   int bufsize = 256, msglength = 0;
684
685   sqlglm(err_msg, &bufsize, &msglength);
686   err_msg[msglength] = '\0';
687
688   if (where)
689     com_err(whoami, 0, "DBMS error %swhile %s", err_msg, where);
690   else
691     com_err(whoami, 0, "DBMS error %s", err_msg);
692 }
This page took 0.105417 seconds and 5 git commands to generate.