]> andersk Git - moira.git/blob - regtape/employee.pc
assume 50 characters of department name in input.
[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 107
51 #define LOC_USERNAME 157
52 #define LOC_HOST 187
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 newfinger = 0, debug = 0, 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], "-n"))
119         newfinger++;
120       else if (!strcmp(argv[i], "-d"))
121         debug++;
122       else if (!strcmp(argv[i], "-h"))
123         highid++;
124       else if (file)
125         fprintf(stderr, "Usage: %s [-w] [-D] [-n] inputfile\n", whoami);
126       else
127         file = argv[i];
128     }
129
130   in = fopen(file, "r");
131   if (!in)
132     {
133       fprintf(stderr, "Unable to open %s for input\n", file);
134       exit(1);
135     }
136
137   initialize_sms_error_table();
138
139   EXEC SQL CONNECT :db IDENTIFIED BY :db;
140   if (sqlca.sqlcode)
141     {
142       dbmserr("opening database", sqlca.sqlcode);
143       exit(1);
144     }
145
146   while ((e = get_next_entry(in)))
147     {
148       process_entry(e);
149       EXEC SQL COMMIT WORK;
150       if (sqlca.sqlcode)
151         {
152           dbmserr("committing work", sqlca.sqlcode);
153           exit(1);
154         }
155       if (wait)
156         {
157           printf("Next");
158           fflush(stdout);
159           fgets(buf, sizeof(buf), stdin);
160         }
161     }
162
163   exit(0);
164 }
165
166 struct entry *get_next_entry(FILE *in)
167 {
168   static struct entry e;
169   static char buf[BUFSIZ];
170   static char name[LEN_NAME + 1], sname[LEN_NAME + 1], id[LEN_ID + 1];
171   static char office[LEN_OFFICE + 1], phone[LEN_PHONE + 1];
172   static char phone2[LEN_PHONE2 + 1], dept[LEN_DEPT + 1], title[LEN_TITLE + 1];
173   static char username[LEN_USERNAME + 1], host[LEN_HOST + 1];
174   int ends_sr, ends_jr, ends_iii, ends_iv, ends_ii, ends_v;
175   char *p;
176
177   if (!fgets(buf, sizeof(buf), in))
178     return NULL;
179
180   strncpy(id, &buf[LOC_ID], LEN_ID);
181   id[LEN_ID] = '\0';
182   strncpy(name, &buf[LOC_NAME], LEN_NAME);
183   name[LEN_NAME] = '\0';
184   strncpy(office, &buf[LOC_OFFICE], LEN_OFFICE);
185   office[LEN_OFFICE] = '\0';
186   strncpy(phone, &buf[LOC_PHONE], LEN_PHONE);
187   phone[LEN_PHONE] = '\0';
188   strncpy(phone2, &buf[LOC_PHONE2], LEN_PHONE2);
189   phone2[LEN_PHONE2] = '\0';
190   strncpy(dept, &buf[LOC_DEPT], LEN_DEPT);
191   dept[LEN_DEPT] = '\0';
192   strncpy(title, &buf[LOC_TITLE], LEN_TITLE);
193   title[LEN_TITLE] = '\0';
194   strncpy(username, &buf[LOC_USERNAME], LEN_USERNAME);
195   username[LEN_USERNAME] = '\0';
196   strncpy(host, &buf[LOC_HOST], LEN_HOST);
197   host[LEN_HOST] = '\0';
198
199   strcpy(sname, name);
200   e.name = strtrim(sname);
201   p = strchr(name, ',');
202   if (p)
203     *p = '\0';
204   e.last = strtrim(name);
205   if (p)
206     {
207       p++;
208       while (isspace(*p))
209         p++;
210       e.first = p;
211       if ((p = strchr(e.first, ' ')))
212         {
213           *p = '\0';
214           e.first = strtrim(e.first);
215           e.middle = strtrim(p + 1);
216         }
217       else
218         {
219           e.first = strtrim(e.first);
220           e.middle = "";
221         }
222     }
223   else
224     {
225       e.first = "";
226       e.middle = "";
227     }
228   ends_sr = ends_jr = ends_iii = ends_iv = ends_ii = ends_v = 0;
229   LookForSt(e.last);
230   LookForO(e.last);
231   LookForJrAndIII(e.last, &ends_jr, &ends_sr, &ends_ii, &ends_iii,
232                   &ends_iv, &ends_v);
233   LookForJrAndIII(e.first, &ends_jr, &ends_sr, &ends_ii, &ends_iii,
234                   &ends_iv, &ends_v);
235   FixCase(e.last);
236   FixCase(e.first);
237   FixCase(e.middle);
238
239   e.id = id;
240
241   e.address = strtrim(office);
242   e.phone = strtrim(phone);
243   e.phone2 = strtrim(phone2);
244   e.dept = strtrim(dept);
245   e.title = strtrim(title);
246
247   e.class = "MITS";
248   e.highid = highid;
249   if (strstr(e.title, "PROF") || strstr(e.title, "LECTURE"))
250     e.class = "FACULTY";
251   if (!strcmp(e.dept, "LINCOLN LAB"))
252     {
253       e.class = "LINCOLN";
254       e.highid = 1;
255     }
256
257   return &e;
258 }
259
260 void process_entry(struct entry *e)
261 {
262   int changed, nochange;
263   char buf[MAX_FIELD_WIDTH], *from, *to;
264   EXEC SQL BEGIN DECLARE SECTION;
265   char *first, *last, *middle, *sid, *name, *rdept;
266   char *rtitle, *raddr, *rhphone, *rophone, *prog;
267   char class[USERS_TYPE_SIZE], oaddr[USERS_OFFICE_ADDR_SIZE];
268   char ophone[USERS_OFFICE_PHONE_SIZE], dept[USERS_DEPARTMENT_SIZE];
269   char dfirst[USERS_FIRST_SIZE], dlast[USERS_LAST_SIZE];
270   char dmiddle[USERS_MIDDLE_SIZE];
271   int id, status, who;
272   EXEC SQL END DECLARE SECTION;
273
274   who = WHO;
275   prog = PROG;
276   first = e->first;
277   if (strlen(first) > USERS_FIRST_SIZE - 1)
278     first[USERS_FIRST_SIZE - 1] = '\0';
279   last = e->last;
280   if (strlen(last) > USERS_LAST_SIZE - 1)
281     last[USERS_LAST_SIZE - 1] = '\0';
282   middle = e->middle;
283   if (strlen(middle) > USERS_MIDDLE_SIZE - 1)
284     middle[USERS_MIDDLE_SIZE - 1] = '\0';
285   sid = e->id;
286   id = 0;
287
288   /* Get user info */
289   EXEC SQL SELECT users_id, first, last, middle, type, office_addr,
290     office_phone, department, status
291     INTO :id, :dfirst, :dlast, :dmiddle, :class, :oaddr,
292     :ophone, :dept, :status
293     FROM users
294     WHERE clearid = :sid;
295   if (sqlfail())
296     {
297       if (sqlca.sqlcode == SQL_DUPLICATE)
298         {
299           com_err(whoami, 0, "duplicate ID number %s on user %s %s",
300                   sid, first, last);
301           return;
302         }
303       else
304         sqlexit();
305     }
306   if (id == 0)
307     {
308       newuser(e);
309       return;
310     }
311
312   /* Update class/state if necessary.  (Exclude several spacial cases.) */
313   if (strcmp(e->class, strtrim(class)) &&
314       strcmp(class, "STAFF") && strcmp(class, "SIPBMEM") &&
315       strcmp(class, "KNIGHT"))
316     {
317       com_err(whoami, 0, "updating class for %s %s from %s to %s",
318               first, last, class, e->class);
319       if (status == US_NOT_ALLOWED)
320         status = US_NO_LOGIN_YET;
321       if (status == US_ENROLL_NOT_ALLOWED)
322         status = US_ENROLLED;
323       strcpy(class, e->class);
324       if (!debug)
325         {
326           EXEC SQL UPDATE users
327             SET type = NVL(:class, CHR(0)), status = :status,
328             modtime = SYSDATE, modby = :who, modwith = :prog
329             WHERE users_id = :id;
330           if (sqlca.sqlcode)
331             {
332               dbmserr("updating user", sqlca.sqlcode);
333               exit(1);
334             }
335         }
336     }
337
338   /* Update name if necessary */
339   if (strcmp(first, strtrim(dfirst)) ||
340       strcmp(last, strtrim(dlast)) ||
341       strcmp(middle, strtrim(dmiddle)))
342     {
343       com_err(whoami, 0, "updating real name for %s %s", first, last);
344       if (!debug)
345         {
346           EXEC SQL UPDATE users
347             SET first = NVL(:first, CHR(0)), last = NVL(:last, CHR(0)),
348             middle = NVL(:middle, CHR(0)), modby = :who, modwith = :prog,
349             modtime = SYSDATE
350             WHERE users_id = :id;
351           if (sqlca.sqlcode)
352             {
353               dbmserr("updating name", sqlca.sqlcode);
354               exit(1);
355             }
356         }
357       else
358         {
359           com_err(whoami, 0, "was %s %s %s, became %s %s %s",
360                   dfirst, dmiddle, dlast, first, middle, last);
361         }
362     }
363
364   changed = nochange = 0;
365   strcpy(buf, e->address);
366   while ((to = strchr(buf, ',')))
367     *to = ';';
368   while ((to = strchr(buf, ':')))
369     *to = ';';
370   if (newfinger)
371     {
372       if (oaddr[0] == ' ' && buf[0])
373         {
374           strncpy(oaddr, buf, USERS_OFFICE_ADDR_SIZE - 1);
375           oaddr[USERS_OFFICE_ADDR_SIZE - 1] = '\0';
376           changed++;
377         }
378       else if (strncmp(strtrim(oaddr), buf, USERS_OFFICE_ADDR_SIZE - 1))
379         nochange++;
380     }
381   else
382     {
383       if (strncmp(strtrim(oaddr), buf, USERS_OFFICE_ADDR_SIZE - 1))
384         {
385           changed++;
386           if (debug)
387             {
388               com_err(whoami, 0, "office for %s %s changed from %s to %s",
389                       first, last, oaddr, buf);
390             }
391         }
392       strncpy(oaddr, buf, USERS_OFFICE_ADDR_SIZE - 1);
393       oaddr[USERS_OFFICE_ADDR_SIZE - 1] = '\0';
394     }
395   from = e->phone;
396   to = buf;
397   while (*from)
398     {
399       if (isdigit(*from))
400         *to++ = *from;
401       from++;
402     }
403   *to = '\0';
404   if (newfinger)
405     {
406       if (ophone[0] == ' ')
407         {
408           strncpy(ophone, buf, USERS_OFFICE_PHONE_SIZE - 1);
409           ophone[USERS_OFFICE_PHONE_SIZE - 1] = '\0';
410         }
411       else if (strncmp(strtrim(ophone), buf, USERS_OFFICE_PHONE_SIZE - 1))
412         nochange++;
413     }
414   else
415     {
416       if (strncmp(strtrim(ophone), buf, USERS_OFFICE_PHONE_SIZE - 1))
417         {
418           changed++;
419           if (debug)
420             {
421               com_err(whoami, 0, "Phone for %s %s changed from %s to %s",
422                       first, last, ophone, buf);
423             }
424         }
425       strncpy(ophone, buf, USERS_OFFICE_PHONE_SIZE - 1);
426       ophone[USERS_OFFICE_PHONE_SIZE - 1] = '\0';
427     }
428   FixCase(e->dept);
429   FixCase(e->title);
430   if (newfinger)
431     {
432       if (dept[0] == ' ')
433         {
434           strncpy(dept, e->dept, USERS_DEPARTMENT_SIZE - 1);
435           dept[USERS_DEPARTMENT_SIZE - 1] = '\0';
436         }
437       else if (strncmp(strtrim(dept), e->dept, USERS_DEPARTMENT_SIZE - 1))
438         nochange++;
439     }
440   else
441     {
442       if (strncmp(strtrim(dept), e->dept, USERS_DEPARTMENT_SIZE - 1))
443         {
444           changed++;
445           if (debug)
446             {
447               com_err(whoami, 0, "Department for %s %s changed from %s to %s",
448                       first, last, dept, e->dept);
449             }
450         }
451       strncpy(dept, e->dept, USERS_DEPARTMENT_SIZE - 1);
452       dept[USERS_DEPARTMENT_SIZE - 1] = '\0';
453     }
454   sid = e->id;
455   name = e->name;
456   rdept = e->dept;
457   rtitle = e->title;
458   raddr = e->address;
459   rhphone = e->phone;
460   rophone = e->phone2;
461
462   if (debug)
463     return;
464
465   if (changed)
466     {
467       com_err(whoami, 0, "updating finger for %s %s", first, last);
468       EXEC SQL UPDATE users
469         SET office_addr = NVL(:oaddr, CHR(0)),
470         office_phone = NVL(:ophone, CHR(0)), department = NVL(:dept, CHR(0)),
471         fmodtime = SYSDATE, fmodby = :who, fmodwith = :prog,
472         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   else
484     {
485       EXEC SQL UPDATE users
486         SET xname = NVL(:name, CHR(0)), xdept = NVL(:rdept, CHR(0)),
487         xtitle = NVL(:rtitle, CHR(0)), xaddress = NVL(:raddr, CHR(0)),
488         xphone1 = NVL(:rhphone, CHR(0)), xphone2 = NVL(:rophone, CHR(0)),
489         xmodtime = SYSDATE, clearid = NVL(:sid, CHR(0))
490         WHERE users_id = :id;
491       if (sqlca.sqlcode)
492         {
493           dbmserr(NULL, sqlca.sqlcode);
494           exit(1);
495         }
496     }
497 }
498
499
500 void newuser(struct entry *e)
501 {
502   char *from, *to;
503   EXEC SQL BEGIN DECLARE SECTION;
504   int id, uid, st, who;
505   char *last, *first, *class, *middle, login[USERS_LOGIN_SIZE], *sid;
506   char fullname[USERS_FULLNAME_SIZE], *prog;
507   char oaddr[USERS_OFFICE_ADDR_SIZE], ophone[USERS_OFFICE_PHONE_SIZE];
508   char dept[USERS_DEPARTMENT_SIZE], *name, *title;
509   char *rdept, *rhphone, *rophone;
510   EXEC SQL END DECLARE SECTION;
511
512   who = WHO;
513   prog = PROG;
514   strncpy(oaddr, e->address, USERS_OFFICE_ADDR_SIZE - 1);
515   oaddr[USERS_OFFICE_ADDR_SIZE - 1] = '\0';
516   while ((to = strchr(oaddr, ',')))
517     *to = ';';
518   while ((to = strchr(oaddr, ':')))
519     *to = ';';
520   from = e->phone;
521   to = ophone;
522   while (*from)
523     {
524       if (isdigit(*from))
525         *to++ = *from;
526       from++;
527     }
528   *to = '\0';
529   FixCase(e->dept);
530   strncpy(dept, e->dept, USERS_DEPARTMENT_SIZE - 1);
531   dept[USERS_DEPARTMENT_SIZE - 1] = '\0';
532
533   id = set_next_users_id(0);
534   uid = set_next_uid(e->highid);
535   sprintf(login, "#%d", uid);
536   last = e->last;
537   first = e->first;
538   middle = e->middle;
539   class = e->class;
540   if (*middle)
541     sprintf(fullname, "%s %s %s", first, middle, last);
542   else
543     sprintf(fullname, "%s %s", first, last);
544   st = US_NO_LOGIN_YET;
545
546   sid = e->id;
547   name = e->name;
548   rdept = e->dept;
549   title = e->title;
550   rhphone = e->phone;
551   rophone = e->phone2;
552
553   com_err(whoami, 0, "adding user %s %s", e->first, e->last);
554   if (debug)
555     return;
556
557   EXEC SQL INSERT INTO users
558     (login, users_id, unix_uid, shell, last, first, middle, status,
559      clearid, type, modtime, modby, modwith, fullname, office_addr,
560      office_phone, department, fmodtime, fmodby, fmodwith,
561      potype, xname, xdept, xtitle, xaddress, xphone1, xphone2, xmodtime)
562     VALUES (:login, :id, :uid, '/bin/athena/tcsh',
563             NVL(:last, CHR(0)), NVL(:first, CHR(0)), NVL(:middle, CHR(0)),
564             :st, NVL(:sid, CHR(0)), NVL(:class, CHR(0)), SYSDATE, :who, :prog,
565             NVL(:fullname, CHR(0)), NVL(:oaddr, CHR(0)), NVL(:ophone, CHR(0)),
566             NVL(:dept, CHR(0)), SYSDATE, :who, :prog, 'NONE',
567             NVL(:name, CHR(0)), NVL(:rdept, CHR(0)), NVL(:title, CHR(0)),
568             NVL(:oaddr, CHR(0)), NVL(:rhphone, CHR(0)), NVL(:rophone, CHR(0)),
569             SYSDATE);
570   if (sqlca.sqlcode)
571     {
572       dbmserr("adding user", sqlca.sqlcode);
573       exit(1);
574     }
575 }
576
577
578 int set_next_users_id(int limit)
579 {
580   EXEC SQL BEGIN DECLARE SECTION;
581   int flag, value, retval;
582   EXEC SQL END DECLARE SECTION;
583
584   if (debug)
585     return 0;
586
587   EXEC SQL SELECT value INTO :value FROM numvalues
588     WHERE name = 'users_id';
589   if (sqlfail())
590     sqlexit();
591   if (sqlca.sqlerrd[2] != 1)
592     {
593       EXEC SQL ROLLBACK;
594       com_err(whoami, MR_INTERNAL, "values table inconsistancy");
595       exit(1);
596     }
597
598   flag = 0;
599   EXEC SQL SELECT users_id INTO :flag FROM users
600     WHERE users_id = :value;
601   if (sqlfail())
602     sqlexit();
603   if (sqlca.sqlerrd[2] == 0)
604     flag = 0;
605   while (flag)
606     {
607       value++;
608       if (limit && value > MAX_ID_VALUE)
609         value = MIN_ID_VALUE;
610       flag = 0;
611       EXEC SQL SELECT users_id INTO :flag FROM users
612         WHERE users_id = :value;
613       if (sqlfail())
614         sqlexit();
615       if (sqlca.sqlerrd[2] == 0)
616         flag = 0;
617     }
618
619   retval = value++;
620   if (limit && value > MAX_ID_VALUE)
621     value = MIN_ID_VALUE;
622   EXEC SQL UPDATE numvalues SET value = :value
623     WHERE name = 'users_id';
624   if (sqlca.sqlcode)
625     {
626       dbmserr("assigning ID", sqlca.sqlcode);
627       exit(1);
628     }
629   return retval;
630 }
631
632 int set_next_uid(int high)
633 {
634   EXEC SQL BEGIN DECLARE SECTION;
635   int flag, initial, value, retval;
636   char *name;
637   EXEC SQL END DECLARE SECTION;
638
639   if (debug)
640     return 0;
641
642   if (high)
643     name = "high_uid";
644   else
645     name = "unix_uid";
646
647   EXEC SQL SELECT value INTO :initial FROM numvalues
648     WHERE name = :name;
649   if (sqlfail())
650     sqlexit();
651   if (sqlca.sqlerrd[2] != 1)
652     {
653       EXEC SQL ROLLBACK;
654       com_err(whoami, MR_INTERNAL, "values table inconsistancy");
655       exit(1);
656     }
657
658   value = initial;
659   flag = 0;
660   EXEC SQL SELECT COUNT(unix_uid) INTO :flag
661     FROM users WHERE unix_uid = :value;
662   if (sqlfail())
663     sqlexit();
664   while (flag)
665     {
666       value++;
667       if (!high && value > MAX_ID_VALUE)
668         value = MIN_ID_VALUE;
669       if (value == initial)
670         {
671           com_err(whoami, 0, "Out of uids!");
672           EXEC SQL ROLLBACK WORK;
673           exit(1);
674         }
675       flag = 0;
676       EXEC SQL SELECT COUNT(unix_uid) INTO :flag
677         FROM users WHERE unix_uid = :value;
678       if (sqlfail())
679         sqlexit();
680     }
681
682   retval = value++;
683   if (!high && value > MAX_ID_VALUE)
684     value = MIN_ID_VALUE;
685   EXEC SQL UPDATE numvalues SET value = :value WHERE name = :name;
686   if (sqlca.sqlcode)
687     {
688       dbmserr("assigning ID", sqlca.sqlcode);
689       exit(1);
690     }
691   return retval;
692 }
693
694
695 void sqlexit(void)
696 {
697   dbmserr(NULL, sqlca.sqlcode);
698   EXEC SQL ROLLBACK WORK;
699   exit(1);
700 }
701
702 void dbmserr(char *where, int what)
703 {
704   char err_msg[256];
705   int bufsize = 256, msglength = 0;
706
707   sqlglm(err_msg, &bufsize, &msglength);
708   err_msg[msglength] = '\0';
709
710   if (where)
711     com_err(whoami, 0, "DBMS error %swhile %s", err_msg, where);
712   else
713     com_err(whoami, 0, "DBMS error %s", err_msg);
714 }
This page took 0.096201 seconds and 5 git commands to generate.