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