]> andersk Git - moira.git/blob - server/qsupport.qc
3d8e43e69bb0647f00fe8beb2b742861cf0adb03
[moira.git] / server / qsupport.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *
8  *      $Log$
9  *      Revision 1.12  1987-08-29 00:05:54  mike
10  *      Fixed bug in check_nfs.
11  *      Added code to upcasify machine names in validate_id.
12  *
13 Revision 1.11  87/08/28  14:55:45  mike
14 Modified delete_locker to require only one argument, the login name.
15 Modified get_groups_of_all_users and get_all_poboxes to disable INGRES
16 table locking.
17
18 Revision 1.10  87/08/25  15:56:54  mike
19 - Fixed bugs in get_groups_of_all_users
20 - Added tblstats updates to add_user_group
21 - Added routines: add_hostaccess (ashi), delete_hostaccess (dshi),
22   followup_ushp, and followup_usha
23
24 Revision 1.9  87/08/22  17:41:34  wesommer
25 More of Mike's changes. 
26
27 Revision 1.8  87/08/18  15:05:20  wesommer
28 Fixed definition of add_locker.
29
30 Revision 1.7  87/08/04  01:49:41  wesommer
31 Rearranged messages.
32
33 Revision 1.6  87/08/04  01:10:02  wesommer
34 Changes by mike; checked in prior to my hacking.
35
36 Revision 1.5  87/07/30  14:54:13  wesommer
37 Added debugging code in an attempt to catch a flakey problem.
38
39 Revision 1.4  87/07/30  00:30:21  wesommer
40 replaced appends = appends+1 with appends = tbs.appends+1
41
42 Revision 1.3  87/07/30  00:26:11  wesommer
43 Changes by mike prior to "appends" fix.
44
45 Revision 1.2  87/07/29  16:00:39  wesommer
46 Fixed add_locker.
47
48 Revision 1.1  87/07/29  15:13:57  wesommer
49 Initial revision
50
51  */
52
53 #ifndef lint
54 static char *rcsid_qsupport_qc = "$Header$";
55 #endif lint
56
57 #include "query.h"
58 #include "sms_server.h"
59 #include <ctype.h>
60
61 #define SMS_SUCCESS 0
62
63 extern char *whoami;
64
65 /* Specialized Access Routines */
66
67 /**
68  ** access_user - verify that client name equals specified login name
69  **
70  ** Used by: update_user_shell
71  **          update_finger_by_login
72  **
73  **  - since field validation routines are called first, a users_id is
74  **    now in argv[0] instead of the login name.  Therefore, we must 
75  **    convert the client name to a users_id.
76  **/
77
78 access_user(q, argv, cl)
79     struct query *q;
80     char *argv[];
81     client *cl;
82 ##{
83     register struct krbname *krb;
84 ##  int client_id;
85 ##  char *client_name;
86 ##  int rowcount;
87
88     client_name = cl->kname.name;
89 ##  repeat retrieve (client_id = users.users_id) 
90 ##         where users.login = @client_name
91 ##  inquire_equel (rowcount = "rowcount")
92     if (rowcount != 1) return(SMS_PERM);
93     if (client_id != *(int *)argv[0]) return(SMS_PERM);
94
95     return(SMS_SUCCESS);
96 ##}
97     
98 /**
99  ** access_pop - same as access_user plus verifies that a user has only one
100  **              mailbox of type "POP"
101  **
102  ** Inputs:
103  **   argv[0] - users_id
104  **   argv[1] - type
105  **   argv[2] - mach_id
106  **   argv[3] - box
107  **
108  ** Description:
109  **   - if q->name = "add_pobox" and type = "POP", 
110  **        verify that no POP box already exists for user
111  **   - call access_user
112  **
113  **/
114
115 access_pop(q, argv, cl)
116     struct query *q;
117     char *argv[];
118     client *cl;
119 ##{
120 ##  int users_id;
121 ##  int mach_id;
122 ##  char *box;
123 ##  int exists;
124
125     if (!bcmp(q->name, "add_pobox", 10) && !bcmp(argv[1], "POP", 4)) {
126         users_id = *(int *)argv[0];
127         mach_id = *(int *)argv[2];
128         box = argv[3];
129 ##      range of p is pobox
130 ##      repeat retrieve (exists = any(p.#box where p.#users_id = @users_id
131 ##                                    and p.type = "POP" 
132 ##                                    and p.#mach_id = @mach_id
133 ##                                    and p.#box = @box))
134         if (exists) return(SMS_EXISTS);
135     }
136
137     return(access_user(q, argv, cl));
138 ##}
139
140 /**
141  ** access_list - check access for adding or deleting list members
142  **
143  ** Inputs: argv[0] - list_id
144  **         cl->krb.name - client name
145  **
146  ** - check that client is a member of the access control list
147  ** - OR, if q->shortname == {amtl | dfml} and
148  **       if list.flags & LF_PUBLIC, allow access if client = member
149  **
150  **/ 
151
152 access_list(q, argv, cl)
153     struct query *q;
154     char *argv[];
155     client *cl;
156 ##{
157 ##  int list_id;
158 ##  int acl_id;
159 ##  int flags;
160     int member_id;
161     char *client_type;
162     int client_id;
163     int status;
164     int exists;
165
166     list_id = *(int *)argv[0];
167 ##  repeat retrieve (acl_id = list.#acl_id, flags = list.#flags) 
168 ##         where list.#list_id = @list_id
169
170     /* parse client structure */
171     status = get_client(cl, &client_type, &client_id);
172     if (status != SMS_SUCCESS) return(status);
173
174     /* if amtl or dmfl and list is public allow client to add or delete self */
175     if (!bcmp("amtl", q->shortname, 4) || !bcmp("dmfl", q->shortname, 4)) {
176         if ((flags & LF_PUBLIC) && !bcmp("USER", argv[1], 4)) {
177             member_id = *(int *)argv[2];
178             if (member_id == client_id) return(SMS_SUCCESS);
179         }
180     }
181
182     /* check for client in access control list */
183     exists = find_member(acl_id, client_type, client_id, 0);
184     if (!exists) return(SMS_PERM);
185
186     return(SMS_SUCCESS);
187 ##}
188
189 /**
190  ** access_maillist - access_list + disallow adding user-group to maillists
191  **
192  ** Inputs:
193  **   argv[0] - list_id
194  **
195  **/
196
197 access_maillist(q, argv, cl)
198     struct query *q;
199     char *argv[];
200     client *cl;
201 ##{
202 ##  int list_id;
203 ##  int exists;
204 ##  char list_name[32];
205     int status;
206
207     status = access_list(q, argv, cl);
208     if (status != SMS_SUCCESS) return(status);
209     if (bcmp(q->name, "add_maillist", 12)) return(status);
210
211     list_id = *(int *)argv[0];
212 ##  range of g is groups
213 ##  repeat retrieve (exists = any(g.#list_id where g.#list_id = @list_id))
214     if (!exists) return(SMS_SUCCESS);
215 ##  repeat retrieve (list_name = list.name) where list.#list_id = @list_id
216 ##  repeat retrieve (exists = any(users.login where users.login = @list_name))
217     return ((exists) ? SMS_USER_GROUP : SMS_SUCCESS);
218 ##}
219
220 /**
221  ** Setup routine for add_group
222  **
223  ** Inputs: none
224  **
225  ** Description: allocate next gid and store in values table
226  **
227  **/
228
229 setup_add_group(q, argv, cl, access_check)
230     struct query *q;
231     char *argv[];
232     client *cl;
233     int access_check;
234 ##{
235 ##  int ngid;
236 ##  int exists;
237     int status;
238
239     status = access_list(q, argv, cl);
240
241     if (status != SMS_SUCCESS || access_check) return(status);
242
243 ##  range of g is groups
244 ##  range of v is values
245 ##  repeat retrieve (ngid = v.value) where v.name = "gid"
246     exists = 1;
247     while (exists) {
248         ngid++;
249 ##      repeat retrieve (exists = any(g.#gid where g.#gid = @ngid))
250     }
251
252 ##  repeat replace v (value = @ngid) where v.name = "gid"
253     return(SMS_SUCCESS);
254 ##}
255 \f
256 /**
257  ** Setup routine for add_user
258  **
259  ** Inputs: argv[0] - login
260  **         argv[1] - uid
261  **
262  ** Description:
263  **
264  ** - if argv[1] == "#" then set argv[1] = next(uid)
265  ** - if argv[0] == "#" then set argv[0] = "#<uid>"
266  **
267  **/
268
269 setup_add_user(q, argv, cl, access_check)
270     struct query *q;
271     register char *argv[];
272     client *cl;
273     int access_check;
274 ##{
275 ##  int nuid;
276 ##  int exists;
277
278     if (access_check) return(SMS_SUCCESS);
279
280     if (!bcmp(argv[1], "#", 2)) {
281 ##      range of u is users
282 ##      range of v is values
283 ##      repeat retrieve (nuid = v.value) where v.name = "uid"
284         exists = 1;
285         while (exists) {
286             nuid++;
287 ##          repeat retrieve (exists = any(u.#uid where u.#uid = @nuid))
288         }
289 ##      repeat replace v (value = @nuid) where v.name = "uid"
290         sprintf(argv[1], "%d", nuid);
291     }
292
293     if (!bcmp(argv[0], "#", 2)) {
294         sprintf(argv[0], "#%s", argv[1]);
295     }
296
297     return(SMS_SUCCESS);
298 ##}
299
300 /**
301  ** followup_add_user - add finger entry, set_user_modtime
302  ** followup_delete_user - delete finger entry
303  **
304  ** Inputs:
305  **   argv[0] - login (add_user)
306  **   argv[0] - users_id (delete_user)
307  **
308  **/
309
310 followup_add_user(q, argv)
311     struct query *q;
312     char *argv[];
313 ##{
314 ##  char *login;
315 ##  int users_id;
316 ##  char first[33];
317 ##  char middle[33];
318 ##  char last[33];
319 ##  char fullname[128];
320     register char *cp1;
321     register char *cp2;
322
323     login = argv[0];
324
325     /* get user information */
326 ##  range of u is users
327 ##  repeat retrieve (users_id = u.#users_id, last = u.#last,
328 ##                   first = u.#first, middle = u.#middle) 
329 ##         where u.#login = @login
330
331     /* build fullname */
332     cp2 = fullname;
333     cp1 = first;
334     while (*cp1) *cp2++ = *cp1++;
335     *cp2++ = ' ';
336     cp1 = middle;
337     if (*cp1 == 0) cp2--;
338     while (*cp1) *cp2++ = *cp1++;
339     *cp2++ = ' ';
340     cp1 = last;
341     while (*cp2++ = *cp1++) ;
342
343     /* create a finger entry */
344 ##  repeat append finger (#users_id = @users_id, #fullname = @fullname)
345
346     /* set modtime (creation time) on user */
347 ##  repeat replace u (modtime = "now") where u.#users_id = @users_id
348
349     return(SMS_SUCCESS);
350 ##}
351
352 followup_delete_user(q, argv)
353     struct query *q;
354     char *argv[];
355 ##{
356 ##  int users_id;
357
358     users_id = *(int *)argv[0];
359 ##  repeat delete finger where finger.#users_id = @users_id
360     return(SMS_SUCCESS);
361 ##}
362 \f
363 /**
364  ** setup_add_filesys - verify existance of referenced file systems
365  ** setup_update_filesys - same, except argv[1..5] --> argv[2..6]
366  **
367  ** Inputs:     Add         Update
368  **   argv[0] - label       label
369  **   argv[1] - type        new label
370  **   argv[2] - mach_id     type
371  **   argv[3] - name        mach_id
372  **   argv[4] - mount       name
373  **   argv[5] - access      mount
374  **   argv[6] -             access
375  **
376  ** Description:
377  **   - for type = RVD:
378  **        * verify mach_id/name in rvdvirt
379  **        * verify access in {r, x, R, X}
380  **   - for type = NFS:
381  **        * extract directory prefix from name
382  **        * verify mach_id/dir in nfsphys
383  **        * verify access in {r, w, R, W}
384  **
385  ** Errors:
386  **   SMS_RVD - no such rvd
387  **   SMS_NFS - specified directory not exported
388  **   SMS_FILESYS_ACCESS - invalid filesys access
389  **
390  **/
391
392 setup_add_filesys(q, argv)
393     struct query *q;
394     char *argv[];
395 {
396     char *type;
397     int mach_id;
398     char *name;
399     char *access;  
400
401     type = argv[1];
402     mach_id = *(int *)argv[2];
403     name = argv[3];
404     access = argv[5];
405
406     if (!bcmp(type, "RVD", 3))
407         return (check_rvd(mach_id, name, access));
408     else if (!bcmp(type, "NFS", 3))
409         return (check_nfs(mach_id, name, access));
410     else
411         return(SMS_SUCCESS);
412 }
413
414 setup_update_filesys(q, argv)
415     struct query *q;
416     char *argv[];
417 {
418     char *type;
419     int mach_id;
420     char *name;
421     char *access;  
422
423     type = argv[2];
424     mach_id = *(int *)argv[3];
425     name = argv[4];
426     access = argv[6];
427
428     if (!bcmp(type, "RVD", 3))
429         return (check_rvd(mach_id, name, access));
430     else if (!bcmp(type, "NFS", 3))
431         return (check_nfs(mach_id, name, access));
432     else
433         return(SMS_SUCCESS);
434 }
435
436 ##check_rvd(mach_id, name, access)
437 ##  int mach_id;
438 ##  char *name;
439     char *access;
440 ##{
441 ##  int rowcount;
442     char caccess;
443
444 ##  range of rv is rvdvirt
445 ##  retrieve (rowcount = any(rv.#name where rv.#mach_id = mach_id and
446 ##                           rv.#name = name))
447     if (rowcount == 0) return(SMS_RVD);
448
449     caccess = (isupper(*access)) ? tolower(*access) : *access;
450     if (caccess != 'r' && caccess != 'x') return(SMS_FILESYS_ACCESS);
451
452     return(SMS_SUCCESS);
453 ##}
454
455 ##check_nfs(mach_id, name, access)
456 ##  int mach_id;
457     char *name;
458     char *access;
459 ##{
460 ##  int rowcount;
461 ##  char dir[32];
462     char caccess;
463     register int status;
464     register char *cp1;
465     register char *cp2;
466
467     caccess = (isupper(*access)) ? tolower(*access) : *access;
468     if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
469
470     status = SMS_NFS;
471 ##  range of np is nfsphys
472 ##  retrieve (dir = np.#dir) where np.#mach_id = mach_id
473 ##  {
474          cp1 = name;
475          cp2 = dir;
476          while (*cp2) {
477              if (*cp1++ != *cp2) break;
478              cp2++;
479          }
480          if (*cp2 == 0) {
481              status = SMS_SUCCESS;
482 ##           endretrieve
483          }
484 ##  }
485
486     return(status);
487 ##}
488 \f
489 /* Followup Routines */
490
491 set_user_modtime(q, argv)
492     struct query *q;
493     char *argv[];
494 ##{
495 ##  char *login;
496
497     login = argv[0];
498 ##  repeat replace u (modtime = "now") where u.#login = @login
499     return(SMS_SUCCESS);
500 ##}
501
502 set_user_modtime_by_id(q, argv)
503     struct query *q;
504     char *argv[];
505 ##{
506 ##  int users_id;
507
508     users_id = *(int *)argv[0];
509 ##  repeat replace users (modtime = "now") where users.#users_id = @users_id
510     return(SMS_SUCCESS);
511 ##}
512
513 set_list_modtime(q, argv)
514     struct query *q;
515     char *argv[];
516 ##{
517 ##  char *list_name;
518
519     list_name = argv[0];
520 ##  repeat replace list (modtime = "now") where list.name = @list_name
521     return(SMS_SUCCESS);
522 ##}
523
524 set_list_modtime_by_id(q, argv)
525     struct query *q;
526     char *argv[];
527 ##{
528 ##  int list_id;
529
530     list_id = *(int *)argv[0];
531 ##  repeat replace list (modtime = "now") where list.#list_id = @list_id
532     return(SMS_SUCCESS);
533 ##}
534
535 set_finger_modtime(q, argv)
536     struct query *q;
537     char *argv[];
538 ##{
539 ##  int users_id;
540
541     users_id = *(int *)argv[0];
542 ##  repeat replace f (modtime = "now") where f.#users_id = @users_id
543     return(SMS_SUCCESS);
544 ##}
545 \f
546 /**
547  ** followup_amtl - followup for amtl and dmfl; when adding a list 
548  **                 member to a maillist, add list to maillist table,
549  **                 unless list is a user-group.
550  **                 Then set_list_modtime_by_id.
551  **
552  ** Inputs:
553  **   argv[0] - list_id
554  **   argv[1] - member_type
555  **   argv[2] - member_id
556  **
557  **/
558
559 followup_amtl(q, argv)
560     struct query *q;
561     char *argv[];
562 ##{
563 ##  int list_id;
564 ##  int member_id;
565 ##  int exists;
566 ##  char list_name[33];
567
568     list_id = *(int *)argv[0];
569
570 ##  repeat replace list (modtime = "now") where list.#list_id = @list_id
571
572     /* if query is not amtl or if member_type is not LIST then return */
573     if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4)) 
574         return(SMS_SUCCESS);
575
576     member_id = *(int *)argv[2];
577 ##  range of l is list
578 ##  range of ml is maillists
579 ##  range of g is groups
580
581     /* is parent list a mailing list? */
582 ##  repeat retrieve (exists = any(ml.#list_id where ml.#list_id=@list_id))
583
584     /* if not then return */
585     if (!exists) return(SMS_SUCCESS);
586
587     /* is member_list a user-group? */
588     /* is it a group? */
589 ##  repeat retrieve (exists = any(g.#list_id where g.#list_id = @member_id))
590     if (exists) {
591         /* get list_name */
592 ##      repeat retrieve (list_name = l.#name) where l.#list_id = @member_id
593         /* is list_name a username? */
594 ##      repeat retrieve (exists = any(users.login 
595 ##                                    where users.login = @list_name))
596         /* yes, return error */
597         if (exists) return(SMS_USER_GROUP);
598     }
599
600     /* list is not a user-group; add list to maillist table */
601 ##  repeat append maillists (#list_id = @member_id, ltid = l.tid)
602 ##         where l.#list_id = @member_id
603
604     return(SMS_SUCCESS);
605 ##}
606 \f
607 /**
608  ** followup_add_pobox
609  ** followup_delete_pobox - followup routines for pobox queries
610  **
611  ** Description:
612  **   add_pobox: set pobox creation time
613  **              increment pop usage in serverhosts
614  **
615  **   delete_pobox: decrement pop usage in serverhosts
616  **
617  **/
618
619 followup_add_pobox(q, argv)
620     struct query *q;
621     char *argv[];
622 {
623     set_pobox_creation(q, argv);
624     set_pop_usage(q, argv, 1);
625     return(SMS_SUCCESS);
626 }
627
628 followup_delete_pobox(q, argv)
629     struct query *q;
630     char *argv[];
631 {
632     set_pop_usage(q, argv, -1);
633     return(SMS_SUCCESS);
634 }
635
636 set_pobox_creation(q, argv)
637     struct query *q;
638     char *argv[];
639 ##{
640 ##  int users_id;
641 ##  int mach_id;
642 ##  char *type;
643 ##  char *box;
644
645     users_id = *(int *)argv[0];
646     type = argv[1];
647     mach_id = *(int *)argv[2];
648     box = argv[3];
649
650 ##  range of p is pobox
651 ##  repeat replace p (created = "now") 
652 ##         where p.#users_id = @users_id and p.#type = @type and
653 ##               p.#mach_id = @mach_id and p.#box = @box
654
655     return (SMS_SUCCESS);
656 ##}
657
658 /**
659  ** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
660  **
661  ** Inputs:
662  **   q->name - "add_pobox" or "delete_pobox"
663  **   argv[1] - type
664  **   argv[2] - mach_id
665  **
666  ** Description:
667  **   - incr/decr value field in serverhosts table for pop/mach_id
668  **
669  **/
670
671 set_pop_usage(q, argv, count)
672     struct query *q;
673     char *argv[];
674 ##{
675 ##  int mach_id;
676 ##  int n;
677
678     if (bcmp(argv[1], "POP", 3)) return(SMS_SUCCESS);
679
680     mach_id = *(int *)argv[2];
681     n = count;
682
683 ##  range of sh is serverhosts
684 ##  repeat replace sh (value1 = sh.value1 + @n)
685 ##         where sh.service = "pop" and sh.#mach_id = @mach_id
686
687     return(SMS_SUCCESS);
688 ##}
689
690 /**
691  ** delete_user_poboxes - delete all poboxes for a user
692  **
693  ** Inputs:
694  **   argv[0] - users_id
695  **
696  **/
697
698 delete_user_poboxes(q, argv)
699     struct query *q;
700     char *argv[];
701 ##{
702 ##  int users_id;
703 ##  int n;
704 ##  int mach_id;
705     register int i;
706     int mach_ids[10];
707
708     users_id = *(int *)argv[0];
709
710     /* get machine ids for pop server(s) on which the user currently exists */
711 ##  range of p is pobox
712     i = 0;
713 ##  repeat retrieve (mach_id = p.#mach_id) 
714 ##         where p.#users_id = @users_id and p.type = "POP"
715 ##  {
716          mach_ids[i++] = mach_id;
717          if (i == 10) {
718 ##           endretrieve
719          }
720 ##  }
721
722     /* decrement counts on serverhost entries */
723 ##  range of sh is serverhosts
724     while (--i >= 0) {
725         mach_id = mach_ids[i];
726 ##      repeat replace sh (value1 = sh.value1 - 1)
727 ##             where sh.service = "pop" and sh.#mach_id = @mach_id
728     }
729
730     /* delete user's poboxes */
731 ##  repeat delete p where p.#users_id = @users_id
732
733     return(SMS_SUCCESS);
734 ##}
735
736 \f
737 /**
738  ** add_new_quota
739  ** delete_current_quota - adjust nfsphys values on xxx_quota queries.
740  **
741  ** Inputs:
742  **   argv[0] - mach_id
743  **   argv[1] - device
744  **   argv[2] - users_id
745  **   argv[3] - quota (add_new_quota only)
746  **
747  ** Description:
748  **   delete_current_quota:
749  **     - find nfsquota entry
750  **     - decrement nfsphys.allocated by nfsquota.quota
751  **   add_new_quota
752  **     - increment nfsphys.allocated by quota
753  **
754  **/
755
756 add_new_quota(q, argv)
757     struct query *q;
758     register char *argv[];
759 ##{
760 ##  int mach_id;
761 ##  char *device;
762 ##  int quota;
763
764     mach_id = *(int*)argv[0];
765     device = argv[1];
766     quota = *(int *)argv[3];
767
768 ##  range of np is nfsphys
769 ##  repeat replace np (allocated = np.allocated + @quota)
770 ##      where np.#mach_id = @mach_id and np.#device = @device
771
772     return(SMS_SUCCESS);
773 ##}
774
775 delete_current_quota(q, argv, cl, access_check)
776     struct query *q;
777     register char *argv[];
778     client *cl;
779     int access_check;
780 ##{
781 ##  int mach_id;
782 ##  int users_id;
783 ##  char *device;
784 ##  int quota;
785
786     if (access_check) return(SMS_SUCCESS);
787
788     mach_id = *(int *)argv[0];
789     device = argv[1];
790     users_id = *(int *)argv[2];
791
792 ##  range of np is nfsphys
793 ##  range of nq is nfsquota
794 ##  repeat retrieve (quota = nq.#quota) 
795 ##      where nq.#mach_id = @mach_id and nq.#device = @device and
796 ##            nq.#users_id = @users_id
797 ##  repeat replace np (allocated = np.allocated - @quota)
798 ##      where np.#mach_id = @mach_id and np.#device = @device
799  
800     return(SMS_SUCCESS);
801 ##}
802 \f
803 /**
804  ** add_hostaccess - create entry in hostaccess table upon adding a new
805  **                  machine to the serverhosts table where service =
806  **                  "hostaccess".
807  **
808  ** Inputs:
809  **   argv[0] - service
810  **   argv[1] - mach_id
811  **
812  **/
813
814 add_hostaccess(q, argv)
815     struct query *q;
816     char *argv[];
817 ##{
818 ##  int mach_id;
819
820     /* only work with service = "hostaccess" */
821     if (bcmp(argv[0], "hostaccess", 10)) return(SMS_SUCCESS);
822
823     mach_id = *(int *)argv[1];
824 ##  repeat append hostaccess (#mach_id = @mach_id, status = 0)
825 ##  repeat replace tblstats (modtime = "now", appends = tblstats.appends + 1)
826 ##         where tblstats.table = "hostaccess"
827     return(SMS_SUCCESS);
828 ##}
829
830 /* followup to delete_server_host_info */
831
832 delete_hostaccess(q, argv)
833     struct query *q;
834     char *argv[];
835 ##{
836 ##  int mach_id;
837
838     /* only work with service = "hostaccess" */
839     if (bcmp(argv[0], "hostaccess", 10)) return(SMS_SUCCESS);
840
841     mach_id = *(int *)argv[1];
842 ##  repeat delete hostaccess where hostaccess.#mach_id = @mach_id
843 ##  repeat replace tblstats (modtime = "now", deletes = tblstats.deletes + 1)
844 ##         where tblstats.table = "hostaccess"
845     return(SMS_SUCCESS);
846 ##}
847
848 followup_ushp(q, argv)
849     struct query *q;
850     char *argv[];
851 ##{
852 ##  int mach_id;
853 ##  int status;
854
855     mach_id = *(int *)argv[0];
856 ##  range of ha is hostaccess
857 ##  repeat retrieve (status = ha.#status) where ha.#mach_id = @mach_id
858     status |= 1;
859 ##  repeat replace ha (#status = @status) where ha.#mach_id = @mach_id
860     return(SMS_SUCCESS);
861 ##}
862
863 followup_usha(q, argv)
864     struct query *q;
865     char *argv[];
866 ##{
867 ##  int mach_id;
868 ##  int status;
869
870     mach_id = *(int *)argv[0];
871 ##  range of ha is hostaccess
872 ##  repeat retrieve (status = ha.#status) where ha.#mach_id = @mach_id
873     status |= 2;
874 ##  repeat replace ha (#status = @status) where ha.#mach_id = @mach_id
875     return(SMS_SUCCESS);
876 ##}
877 \f
878 /**
879  ** delete_list_members - called after the delete_list query to clean up
880  **                       members table.
881  **
882  ** Inputs: argv[0] - list_id
883  **
884  ** Description:
885  **   - foreach string member: decr string refc; ifzero, delete string
886  **   - delete all members entries for this list_id
887  **
888  **/
889
890 delete_list_members(q, argv)
891     struct query *q;
892     register char *argv[];
893 ##{
894 ##  int list_id;
895 ##  int string_id;
896 ##  int refc;
897 ##  int rowcount;
898     struct save_queue *sq;
899     struct save_queue *sq_create();
900
901     list_id = *(int *)argv[0];
902     sq = sq_create();
903
904 ##  range of m is members
905 ##  repeat retrieve (string_id = m.member_id)
906 ##         where m.#list_id = @list_id and m.member_type = "STRING"
907 ##  {
908          sq_save_data(sq, string_id);
909 ##  }
910
911     while (sq_get_data(sq, &string_id)) {
912 ##      range of s is strings
913 ##      repeat retrieve (refc = s.#refc) where s.#string_id = @string_id
914 ##      inquire_equel (rowcount = "rowcount")
915         if (rowcount == 0) continue;
916         if (--refc == 0) {
917 ##          repeat delete s where s.#string_id = @string_id
918         } else {
919 ##          repeat replace s (#refc = @refc) where s.#string_id = @string_id
920         }
921     }
922     sq_destroy(sq);
923
924 ##  repeat delete m where m.#list_id = @list_id
925
926     return(SMS_SUCCESS);
927 ##}
928 \f
929 /**
930  ** followup_grvd - Support routine for get_rvd_servers query
931  **
932  ** Inputs:
933  **    q     - grvd query structure
934  **    sq    - save_queue struture: contains list of {machine, oper_acl_id,
935  **            admin_acl_id, shutdown_acl_id} records.
936  **    v     - validate structure (not used)
937  **    action - action routine
938  **    actarg - action routine argument
939  **
940  ** Description:
941  **   - translate acl_ids to list names
942  **
943  **/
944
945 followup_grvd(q, sq, v, action, actarg)
946     struct query *q;
947     struct save_queue *sq;
948     struct validate *v;
949     int (*action)();
950     int actarg;
951 ##{
952     char **argv;
953     char *targv[4];
954 ##  char oper[33];
955 ##  char admin[33];
956 ##  char shutdown[33];
957 ##  int list_id;
958
959     targv[0] = oper;
960     targv[1] = admin;
961     targv[2] = shutdown;
962
963 ##  range of l is list
964
965     while (sq_get_data(sq, &argv)) {
966         sscanf(argv[0], "%d", &list_id);
967 ##      repeat retrieve (oper = l.name) where l.#list_id = @list_id
968         sscanf(argv[1], "%d", &list_id);
969 ##      repeat retrieve (admin = l.name) where l.#list_id = @list_id
970         sscanf(argv[2], "%d", &list_id);
971 ##      repeat retrieve (shutdown = l.name) where l.#list_id = @list_id
972         
973         (*action)(3, targv, actarg);
974         free(argv[0]);
975         free(argv[1]);
976         free(argv[2]);
977     }
978
979     sq_destroy(sq);
980     return(SMS_SUCCESS);
981 ##}
982
983 followup_gars(q, sq, v, action, actarg)
984     struct query *q;
985     struct save_queue *sq;
986     struct validate *v;
987     int (*action)();
988     int actarg;
989 ##{
990     char **argv;
991     char *targv[4];
992 ##  char oper[33];
993 ##  char admin[33];
994 ##  char shutdown[33];
995 ##  int list_id;
996
997     targv[1] = oper;
998     targv[2] = admin;
999     targv[3] = shutdown;
1000
1001 ##  range of l is list
1002
1003     while (sq_get_data(sq, &argv)) {
1004         sscanf(argv[1], "%d", &list_id);
1005 ##      repeat retrieve (oper = l.name) where l.#list_id = @list_id
1006         sscanf(argv[2], "%d", &list_id);
1007 ##      repeat retrieve (admin = l.name) where l.#list_id = @list_id
1008         sscanf(argv[3], "%d", &list_id);
1009 ##      repeat retrieve (shutdown = l.name) where l.#list_id = @list_id
1010         
1011         targv[0] = argv[0];
1012         (*action)(4, targv, actarg);
1013         free(argv[0]);
1014         free(argv[1]);
1015         free(argv[2]);
1016         free(argv[3]);
1017     }
1018
1019     sq_destroy(sq);
1020     return(SMS_SUCCESS);
1021 ##}
1022 \f
1023 /**
1024  ** set_next_object_id - set next object id in values table
1025  **
1026  ** Inputs: object - object name in values table
1027  **
1028  ** - called before an APPEND operation to set the next object id to
1029  **   be used for the new record
1030  **
1031  **/
1032
1033 set_next_object_id(object)
1034     char *object;
1035 ##{
1036 ##  char *name;
1037
1038     name = object;
1039 ##  range of v is values
1040 ##  repeat replace v (value = v.value + 1) where v.#name = @name
1041     return(SMS_SUCCESS);
1042 ##}
1043
1044 /**
1045  ** get_query_need - check modtime of query's associated table against given
1046  **                  time and return true if greater (false if not)
1047  **
1048  ** Inputs:
1049  **   argv[0] - query name
1050  **   argv[1] - time to compare against
1051  **
1052  **/
1053
1054 get_query_need(q, argv, action, actarg)
1055     struct query *q;
1056     register char *argv[];
1057     int (*action)();
1058 ##{
1059     struct query *q1;
1060 ##  char *last_get_time;
1061 ##  char *table;
1062 ##  int need;
1063     char *result;
1064     struct query *get_query_by_name();
1065
1066     q1 = get_query_by_name(argv[0]);
1067
1068     last_get_time = argv[1];
1069     table = q1->rtable;
1070
1071     if (q1->type != RETRIEVE) return(SMS_NO_MATCH);
1072
1073 ##  range of tbs is tblstats
1074 ##  repeat retrieve (need = any(tbs.modtime where tbs.#table = @table and
1075 ##                              tbs.modtime > @last_get_time))
1076     
1077     result = (need) ? "true" : "false";
1078     (*action)(1, &result, actarg);
1079     return(SMS_SUCCESS);
1080 ##}
1081
1082 /**
1083  ** get_list_is_group
1084  ** get_list_is_maillist
1085  **
1086  ** Inputs:
1087  **   argv[0] - list_id
1088  **
1089  ** Returns:
1090  **   {true | false}
1091  **
1092  **/
1093
1094 get_list_is_group(q, argv, action, actarg)
1095     struct query *q;
1096     char *argv[];
1097     int (*action)();
1098     int actarg;
1099 ##{
1100 ##  int exists;
1101 ##  int list_id;
1102     char *result;
1103
1104     list_id = *(int *)argv[0];
1105
1106 ##  range of g is groups
1107 ##  repeat retrieve (exists = any(g.#list_id where g.#list_id = @list_id))
1108
1109     result = (exists) ? "true" : "false";
1110     (*action)(1, &result, actarg);
1111     return(SMS_SUCCESS);
1112 ##}
1113
1114 get_list_is_maillist(q, argv, action, actarg)
1115     struct query *q;
1116     char *argv[];
1117     int (*action)();
1118     int actarg;
1119 ##{
1120 ##  int exists;
1121 ##  int list_id;
1122     char *result;
1123
1124     list_id = *(int *)argv[0];
1125
1126 ##  range of ml is maillists
1127 ##  repeat retrieve (exists = any(ml.#list_id where ml.#list_id = @list_id))
1128
1129     result = (exists) ? "true" : "false";
1130     (*action)(1, &result, actarg);
1131     return(SMS_SUCCESS);
1132 ##}
1133
1134 \f
1135 /**
1136  ** add_locker - special query routine for creating a user locker
1137  **
1138  ** Inputs:
1139  **   argv[0] - users_id
1140  **   argv[1] - machine_id
1141  **   argv[2] - device
1142  **   argv[3] - initial quota
1143  ** 
1144  ** Description:
1145  **   - get prefix directory (dir) for mount point on specified machine/device
1146  **   - create filesys entry (label=<login>, type=NFS, machine=<machine>,
1147  **     mount=<dir>/<login>, access=w, acl=dbadmin)
1148  **   - increment allocated in nfsphys by quota
1149  **   - create nfsquota entry
1150  **
1151  ** Errors:
1152  **   - SMS_NFSPHYS - machine/device does not exist in nfsphys
1153  **   - SMS_FILESYS_EXISTS - file system already exists
1154  ** 
1155  **/
1156
1157 add_locker(q, argv)
1158     register struct query *q;
1159     char *argv[];
1160 ##{
1161 ##  int users_id;
1162 ##  int mach_id;
1163 ##  char *device;
1164 ##  int quota;
1165 ##  int rowcount;
1166 ##  char login[9];
1167 ##  char dir[32];
1168 ##  int allocated;
1169 ##  char locker[64];
1170 ##  char mount[64];
1171 ##  int user_acl;
1172
1173     /* copy arguments */
1174     users_id = *(int *)argv[0];
1175     mach_id = *(int *)argv[1];
1176     device = argv[2];
1177     sscanf(argv[3], "%d", &quota);
1178
1179 ##  range of u is users
1180 ##  range of f is filesys
1181 ##  range of np is nfsphys
1182 ##  range of tbs is tblstats
1183
1184     /* get login name */
1185 ##  repeat retrieve (login = u.#login) where u.#users_id = @users_id
1186
1187     /* get user's acl id */
1188 ##  repeat retrieve (user_acl = list.list_id) where list.name = @login
1189
1190     /* get filesystem directory prefix; give error if machine/device
1191        pair not in nfsphys table */
1192     printf("np.mach_id = %d and np.device = %s\n", mach_id, device);
1193     
1194 ##  repeat retrieve (dir = np.#dir, allocated = np.#allocated) 
1195 ##         where np.#mach_id = @mach_id and np.#device = @device
1196 ##  inquire_equel (rowcount = "rowcount")
1197     if (rowcount == 0) return(SMS_NFSPHYS);
1198
1199     /* make sure a filesys with user's name does not already exist */
1200 ##  repeat retrieve (rowcount = any(f.label where f.label = @login))
1201     if (rowcount != 0) return(SMS_FILESYS_EXISTS);
1202
1203     /* create a new filesys */
1204     sprintf(locker, "%s/%s", dir, login);
1205     sprintf(mount, "/mit/%s", login);
1206 ##  repeat append filesys 
1207 ##             (#label = @login, type = "NFS", #mach_id = @mach_id,
1208 ##              name = @locker, access = "w", order = 1, #mount = @mount,
1209 ##              acl_id = @user_acl)
1210 ##  repeat replace tbs (appends = tbs.appends + 1, modtime = "now")
1211 ##             where tbs.table = "filesys"
1212
1213     /* increment usage count in nfsphys table */
1214     allocated += quota;
1215 ##  replace np (#allocated = allocated) 
1216 ##          where np.#mach_id = mach_id and np.#device = device
1217 ##  repeat replace tbs (updates = tbs.updates + 1, modtime = "now")
1218 ##             where tbs.table = "nfsphys"
1219
1220     /* create nfsquota entry */
1221 ##  append nfsquota (#users_id = users_id, #mach_id = mach_id,
1222 ##                   #device = device, #quota = quota)
1223 ##  repeat replace tbs (appends = tbs.appends + 1, modtime = "now")
1224 ##             where tbs.table = "nfsquota"
1225
1226     return(SMS_SUCCESS);
1227 ##}
1228
1229 /**
1230  ** delete_locker - special query routine for deleting a user locker
1231  **
1232  ** Inputs:
1233  **   argv[0] - users_id
1234  ** 
1235  ** Description:
1236  **   - get login name from users_id
1237  **   - get filesys entry from login
1238  **   - use filesys.mach_id and filesys.name to determine machine/device
1239  **     pair for nfsphys and nfsquota
1240  **   - delete filesys entry (label=<login>)
1241  **   - decrement allocated in nfsphys by quota
1242  **   - delete nfsquota entry
1243  **
1244  ** Errors:
1245  **   - SMS_FILESYS - no filesys exists for user
1246  ** 
1247  **/
1248
1249 delete_locker(q, argv)
1250     register struct query *q;
1251     register char *argv[];
1252 ##{
1253 ##  int users_id;
1254 ##  int mach_id;
1255 ##  int quota;
1256 ##  int rowcount;
1257 ##  char login[9];
1258 ##  char lname[64];
1259 ##  char ndev[32];
1260     register char *c;
1261
1262     /* copy arguments */
1263     users_id = *(int *)argv[0];
1264
1265 ##  range of u is users
1266 ##  range of f is filesys
1267 ##  range of np is nfsphys
1268 ##  range of nq is nfsquota
1269 ##  range of tbs is tblstats
1270
1271     /* get login name */
1272 ##  repeat retrieve (login = u.#login) where u.#users_id = @users_id
1273
1274     /* get mach_id and locker name from filesys entry; then delete it */
1275 ##  repeat retrieve (mach_id = f.#mach_id, lname = f.#name)
1276 ##         where f.#label = @login
1277 ##  inquire_equel (rowcount = "rowcount")
1278     if (rowcount == 0) return(SMS_FILESYS);
1279 ##  repeat delete f where f.#label = @login
1280
1281     /* get prefix directory */
1282     c = (char *)rindex(lname, '/');
1283     *c = 0;
1284
1285     /* get nfs device */
1286 ##  repeat retrieve (ndev = np.device) 
1287 ##         where np.#mach_id = @mach_id and np.dir = @lname
1288
1289     /* get quota from nfsquota entry; then delete entry */
1290 ##  repeat retrieve (quota = nq.#quota)
1291 ##         where nq.#mach_id = @mach_id and nq.#device = @ndev and
1292 ##               nq.#users_id = @users_id
1293 ##  repeat delete nq where nq.#mach_id = @mach_id and nq.#device = @ndev and
1294 ##                  nq.#users_id = @users_id
1295
1296     /* decrement nfsphys.allocated */
1297 ##  repeat replace np (allocated = np.allocated - @quota)
1298 ##         where np.#mach_id = @mach_id and np.#device = @ndev
1299
1300     /* adjust table statistics */
1301 ##  repeat replace tbs (deletes = tbs.deletes + 1, modtime = "now")
1302 ##             where tbs.table = "filesys"
1303 ##  repeat replace tbs (updates = tbs.updates + 1, modtime = "now")
1304 ##             where tbs.table = "nfsphys"
1305 ##  repeat replace tbs (deletes = tbs.deletes + 1, modtime = "now")
1306 ##             where tbs.table = "nfsquota"
1307
1308     return(SMS_SUCCESS);
1309 ##}
1310 \f
1311 /**
1312  ** add_user_group - create a group for a user and add user to group
1313  **
1314  ** Inputs:
1315  **   argv[0] - login
1316  **
1317  ** Description:
1318  **   - verify specified user exists
1319  **   - create a list of same name as user
1320  **   - add user as a member of the list
1321  **
1322  **/
1323
1324 add_user_group(q, argv)
1325     struct query *q;
1326     char *argv[];
1327 ##{
1328 ##  char *login;
1329 ##  int exists;
1330 ##  int users_id;
1331 ##  int list_id;
1332 ##  int gid;
1333
1334     login = argv[0];
1335
1336     /* verify user exists */
1337 ##  repeat retrieve (users_id = users.#users_id) where users.#login = @login
1338 ##  inquire_equel (exists = "rowcount")
1339     if (exists != 1) return(SMS_USER);
1340
1341     /* verify list does not exist */
1342 ##  repeat retrieve (exists = any(list.name where list.name = @login))
1343     if (exists) return(SMS_LIST);
1344
1345     /* get new list_id */
1346 ##  repeat retrieve (list_id = values.value) where values.name = "list_id"
1347     list_id++;
1348 ##  repeat replace values (value = @list_id) where values.name = "list_id"
1349
1350     /* create the list */
1351 ##  range of tbs is tblstats
1352 ##  repeat append list (name = @login, #list_id = @list_id, flags = 1,
1353 ##                      desc = "User Group", acl_id = @list_id,
1354 ##                      expdate = "today" + "5 years", modtime = "now")
1355 ##  repeat replace tbs (modtime = "now", appends = tbs.appends + 1)
1356 ##         where tbs.table = "list"
1357
1358     /* add user to list */
1359 ##  repeat append members (#list_id = @list_id, member_type = "USER",
1360 ##                         member_id = @users_id)
1361 ##  repeat replace tbs (modtime = "now", appends = tbs.appends + 1)
1362 ##         where tbs.table = "members"
1363
1364     /* get new gid */
1365 ##  range of g is groups
1366 ##  range of v is values
1367 ##  repeat retrieve (gid = v.value) where v.name = "gid"
1368     exists = 1;
1369     while (exists) {
1370         gid++;
1371 ##      repeat retrieve (exists = any(g.#gid where g.#gid = @gid))
1372     }
1373 ##  repeat replace v (value = @gid) where v.name = "gid"
1374
1375     /* add list to group table */
1376 ##  repeat append groups (#list_id = @list_id, ltid = list.tid, #gid = @gid)
1377 ##      where list.#list_id = @list_id
1378 ##  repeat replace tbs (modtime = "now", appends = tbs.appends + 1)
1379 ##         where tbs.table = "members"
1380
1381     /* and we're done */
1382     return(SMS_SUCCESS);
1383 ##}
1384
1385 \f
1386 /**
1387  ** get_members_of_list - optimized query for retrieval of list members
1388  **
1389  ** Inputs:
1390  **   argv[0] - list_id
1391  **
1392  ** Description:
1393  **   - retrieve USER members, then LIST members, then STRING members
1394  **
1395  **/
1396
1397 get_members_of_list(q, argv, action, actarg)
1398     struct query *q;
1399     char *argv[];
1400     int (*action)();
1401     int actarg;
1402 ##{
1403 ##  int list_id;
1404 ##  char member_name[129];
1405     char *targv[2];
1406
1407     list_id = *(int *)argv[0];
1408     targv[0] = "USER";
1409     targv[1] = member_name;
1410
1411 ##  range of m is members
1412 ##  repeat retrieve (member_name = users.login)
1413 ##             where m.#list_id = @list_id and m.member_type = "USER"
1414 ##                   and m.member_id = users.users_id
1415 ##             sort by #member_name
1416 ##  {
1417          (*action)(2, targv, actarg);
1418 ##  }
1419
1420     targv[0] = "LIST";
1421 ##  repeat retrieve (member_name = list.name)
1422 ##             where m.#list_id = @list_id and m.member_type = "LIST"
1423 ##                   and m.member_id = list.#list_id
1424 ##             sort by #member_name
1425 ##  {
1426          (*action)(2, targv, actarg);
1427 ##  }
1428
1429     targv[0] = "STRING";
1430 ##  repeat retrieve (member_name = strings.string)
1431 ##             where m.#list_id = @list_id and m.member_type = "STRING"
1432 ##                   and m.member_id = strings.string_id
1433 ##             sort by #member_name
1434 ##  {
1435          (*action)(2, targv, actarg);
1436 ##  }
1437
1438     return(SMS_SUCCESS);
1439 ##}
1440
1441 /**
1442  ** get_groups_of_user - optimized query for retrieval of all groups to
1443  **                      which a user belongs
1444  **
1445  **/
1446
1447 get_groups_of_user(q, argv, action, actarg)
1448     struct query *q;
1449     char *argv[];
1450     int (*action)();
1451     int actarg;
1452 ##{
1453 ##  int users_id;
1454 ##  char list_name[33];
1455 ##  char gid[11];
1456 ##  int rowcount;
1457     char *targv[2];
1458
1459     users_id = *(int *)argv[0];
1460     targv[0] = list_name;
1461     targv[1] = gid;
1462
1463 ##  range of m is members
1464
1465 ##  repeat retrieve (list_name = list.name, gid = text(groups.#gid))
1466 ##         where m.member_id = @users_id and m.member_type = "USER" and
1467 ##               m.list_id = groups.list_id and groups.ltid = list.tid
1468 ##         sort by #list_name
1469 ##  {
1470          (*action)(2, targv, actarg);
1471 ##  }
1472 ##  inquire_equel (rowcount = "rowcount")
1473
1474     return ((rowcount = 0) ? SMS_NO_MATCH : SMS_SUCCESS);
1475 ##}
1476
1477 get_groups_of_all_users(q, argv, action, actarg)
1478     struct query *q;
1479     char *argv[];
1480     int (*action)();
1481     int actarg;
1482 ##{
1483 ##  char login[9];
1484 ##  char group[33];
1485 ##  char gid[11];
1486     char *targv[3];
1487 ##  int errorno;
1488
1489     targv[0] = login;
1490     targv[1] = group;
1491     targv[2] = gid;
1492
1493 ##  range of u is users
1494 ##  range of l is list
1495 ##  range of m is members
1496 ##  range of g is groups
1497
1498 ##  set lockmode session where readlock = nolock
1499
1500 ##  repeat retrieve (login = u.#login, group = l.name, gid = text(g.#gid))
1501 ##         where m.member_type = "USER" and m.member_id = u.users_id and
1502 ##               u.status != 0 and m.list_id = g.list_id and
1503 ##               g.ltid = l.tid
1504 ##         sort by #login, #group
1505 ##  {
1506          (*action)(3, targv, actarg);
1507 ##  }
1508
1509 ##  inquire_equel (errorno = "errorno")
1510 ##  set lockmode session where readlock = system
1511
1512     return((errorno) ? SMS_INGRES_ERR : SMS_SUCCESS);
1513 ##}
1514 \f
1515 /**
1516  ** get_all_poboxes - optimized query for retrieval of all poboxes
1517  **
1518  ** Description:
1519  **   - retrieve LOCAL boxes, then POP boxes, then FOREIGN boxes
1520  **
1521  **/
1522
1523 get_all_poboxes(q, argv, action, actarg)
1524     struct query *q;
1525     char *argv[];
1526     int (*action)();
1527     int actarg;
1528 ##{
1529 ##  char login[9];
1530 ##  char machine[129];
1531 ##  char box[129];
1532     char *targv[4];
1533
1534     targv[0] = login;
1535     targv[2] = machine;
1536     targv[3] = box;
1537
1538     targv[1] = "LOCAL";
1539
1540 ##  set lockmode session where readlock = nolock
1541 ##  range of p is pobox
1542 ##  repeat retrieve (login=users.#login, machine = #machine.name, box=p.#box)
1543 ##             where p.type = "LOCAL" and p.users_id = users.users_id
1544 ##                   and p.mach_id = #machine.mach_id
1545 ##  {
1546          (*action)(4, targv, actarg);
1547 ##  }
1548
1549     targv[1] = "POP";
1550 ##  repeat retrieve (login=users.#login, machine = #machine.name, box=p.#box)
1551 ##             where p.type = "POP" and p.users_id = users.users_id
1552 ##                   and p.mach_id = #machine.mach_id
1553 ##  {
1554          (*action)(4, targv, actarg);
1555 ##  }
1556
1557     targv[1] = "FOREIGN";
1558 ##  repeat retrieve (login=users.#login, machine=strings.string, box=p.#box)
1559 ##             where p.type = "FOREIGN" and p.users_id = users.users_id
1560 ##                   and p.mach_id = strings.string_id
1561 ##  {
1562          (*action)(4, targv, actarg);
1563 ##  }
1564 ##  set lockmode session where readlock = system
1565
1566     return(SMS_SUCCESS);
1567 ##}
1568
1569 get_new_poboxes(q, argv, action, actarg)
1570     struct query *q;
1571     char *argv[];
1572     int (*action)();
1573     int actarg;
1574 ##{
1575 ##  char *created;
1576 ##  char login[9];
1577 ##  char machine[129];
1578 ##  char box[129];
1579     char *targv[4];
1580
1581     created = argv[0];
1582
1583     targv[0] = login;
1584     targv[2] = machine;
1585     targv[3] = box;
1586
1587     targv[1] = "LOCAL";
1588 ##  range of p is pobox
1589 ##  repeat retrieve (login=users.#login, machine = #machine.name, box=p.#box)
1590 ##             where p.type = "LOCAL" and p.users_id = users.users_id
1591 ##                   and p.mach_id = #machine.mach_id and
1592 ##                   p.#created > @created
1593 ##  {
1594          (*action)(4, targv, actarg);
1595 ##  }
1596
1597     targv[1] = "POP";
1598 ##  repeat retrieve (login=users.#login, machine = #machine.name, box=p.#box)
1599 ##             where p.type = "POP" and p.users_id = users.users_id
1600 ##                   and p.mach_id = #machine.mach_id and
1601 ##                   p.#created > @created
1602 ##  {
1603          (*action)(4, targv, actarg);
1604 ##  }
1605
1606     targv[1] = "FOREIGN";
1607 ##  repeat retrieve (login=users.#login, machine=strings.string, box=p.#box)
1608 ##             where p.type = "FOREIGN" and p.users_id = users.users_id
1609 ##                   and p.mach_id = strings.string_id and
1610 ##                   p.#created > @created
1611 ##  {
1612          (*action)(4, targv, actarg);
1613 ##  }
1614
1615     return(SMS_SUCCESS);
1616 ##}
1617 \f
1618 /* Validation Routines */
1619
1620 validate_row(q, argv, v)
1621     register struct query *q;
1622     char *argv[];
1623     register struct validate *v;
1624 ##{
1625 ##  char *rvar;
1626 ##  char *table;
1627 ##  char *name;
1628 ##  char qual[128];
1629 ##  int rowcount;
1630
1631     /* build where clause */
1632     build_qual(v->qual, v->argc, argv, qual);
1633
1634     /* setup ingres variables */
1635     rvar = q->rvar;
1636     table = q->rtable;
1637     name = v->field;
1638
1639     if (log_flags & LOG_RES)
1640         /* tell the logfile what we're doing */
1641         com_err(whoami, 0, "validating row: %s", qual);
1642     
1643     /* look for the record */
1644 ##  range of rvar is table
1645 ##  retrieve (rowcount = count(rvar.name where qual))
1646     if (rowcount == 0) return(SMS_NO_MATCH);
1647     if (rowcount > 1) return(SMS_NOT_UNIQUE);
1648     return(SMS_EXISTS);
1649 ##}
1650
1651 validate_fields(q, argv, vo, n)
1652     struct query *q;
1653     register char *argv[];
1654     register struct valobj *vo;
1655     register int n;
1656 {
1657     register int status;
1658
1659     while (--n >= 0) {
1660         switch (vo->type) {
1661         case V_NAME:
1662             if (log_flags & LOG_RES)
1663                 com_err(whoami, 0, "validating %s in %s: %s", 
1664                     vo->namefield, vo->table, argv[vo->index]);
1665             status = validate_name(argv, vo);
1666             break;
1667
1668         case V_ID:
1669             if (log_flags & LOG_RES)
1670                 com_err(whoami, 0, "validating %s in %s: %s", 
1671                     vo->idfield, vo->table, argv[vo->index]);
1672             status = validate_id(argv, vo);
1673             break;
1674
1675         case V_DATE:
1676             if (log_flags & LOG_RES)
1677                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
1678             status = validate_date(argv, vo);
1679             break;
1680
1681         case V_TYPE:
1682             if (log_flags & LOG_RES)
1683                 com_err(whoami, 0, "validating %s type: %s",
1684                     vo->table, argv[vo->index]);
1685             status = validate_type(argv, vo);
1686             break;
1687
1688         case V_TYPEDATA:
1689             if (log_flags & LOG_RES)
1690                 com_err(whoami, 0, "validating typed data (%s): %s",
1691                     argv[vo->index - 1], argv[vo->index]);
1692             status = validate_typedata(q, argv, vo);
1693             break;
1694
1695         case V_FOLLOWUP:
1696             status = SMS_EXISTS;
1697             break;
1698
1699         case V_SORT:
1700             status = SMS_EXISTS;
1701             break;
1702
1703         }
1704
1705         if (status != SMS_EXISTS) return(status);
1706         vo++;
1707     }
1708
1709     return(SMS_SUCCESS);
1710 }
1711
1712 validate_id(argv, vo)
1713     char *argv[];
1714     register struct valobj *vo;
1715 ##{
1716 ##  char *name;
1717 ##  char *table;
1718 ##  char *namefield;
1719 ##  char *idfield;
1720 ##  int id;
1721 ##  int rowcount;
1722     register char *c;
1723
1724     name = argv[vo->index];
1725     table = vo->table;
1726     /* minor kludge to upcasify machine names */
1727     if (!bcmp(table, "machine", 7))
1728         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
1729     namefield = vo->namefield;
1730     idfield = vo->idfield;
1731 ##  retrieve (id = table.idfield) where table.namefield = name
1732 ##  inquire_equel (rowcount = "rowcount")
1733     if (rowcount != 1) return(vo->error);
1734     *(int *)argv[vo->index] = id;
1735     return(SMS_EXISTS);
1736 ##}
1737
1738 validate_name(argv, vo)
1739     char *argv[];
1740     register struct valobj *vo;
1741 ##{
1742 ##  char *name;
1743 ##  char *table;
1744 ##  char *namefield;
1745 ##  int rowcount;
1746
1747     name = argv[vo->index];
1748     table = vo->table;
1749     namefield = vo->namefield;
1750 ##  retrieve (rowcount = countu(table.namefield 
1751 ##            where table.namefield = name))
1752     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
1753 ##}
1754
1755 validate_date(argv, vo)
1756     char *argv[];
1757     struct valobj *vo;
1758 ##{
1759 ##  char *idate;
1760 ##  double dd;
1761 ##  int errorno;
1762
1763     idate = argv[vo->index];
1764
1765 ##  retrieve (dd = interval("years", date(idate) - date("today")))
1766 ##  inquire_equel (errorno = "errorno")
1767     if (errorno != 0 || dd > 5.0) return(SMS_DATE);
1768     return(SMS_SUCCESS);
1769 ##}
1770
1771 validate_type(argv, vo)
1772     char *argv[];
1773     register struct valobj *vo;
1774 ##{
1775 ##  char *typename;
1776 ##  char *value;
1777 ##  int rowcount;
1778     register char *c;
1779
1780     typename = vo->table;
1781     value = argv[vo->index];
1782
1783     /* uppercase type fields */
1784     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
1785
1786 ##  range of a is alias
1787 ##  repeat retrieve (rowcount = count(a.trans where a.name = @typename and
1788 ##                                    a.type = "TYPE" and
1789 ##                                    a.trans = @value))
1790     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
1791 ##}
1792
1793 /* validate member or type-specific data field */
1794
1795 validate_typedata(q, argv, vo)
1796     register struct query *q;
1797     register char *argv[];
1798     register struct valobj *vo;
1799 ##{
1800 ##  char *name;
1801 ##  char *field_type;
1802 ##  char data_type[17];
1803 ##  int id;
1804 ##  int refc;
1805 ##  int rowcount;
1806     register char *c;
1807
1808     /* get named object */
1809     name = argv[vo->index];
1810
1811     /* get field type string (known to be at index-1) */
1812     field_type = argv[vo->index-1];
1813
1814     /* get corresponding data type associated with field type name */
1815 ##  repeat retrieve (data_type = alias.trans) 
1816 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
1817 ##  inquire_equel (rowcount = "rowcount")
1818     if (rowcount != 1) return(SMS_TYPE);
1819
1820     /* now retrieve the record id corresponding to the named object */
1821
1822     if (!strcmp(data_type, "user")) {
1823         /* USER */
1824 ##      repeat retrieve (id = users.users_id) where users.login = @name
1825 ##      inquire_equel (rowcount = "rowcount")
1826         if (rowcount != 1) return(SMS_USER);
1827
1828     } else if (!strcmp(data_type, "list")) {
1829         /* LIST */
1830 ##      repeat retrieve (id = list.list_id) where list.#name = @name
1831 ##      inquire_equel (rowcount = "rowcount")
1832         if (rowcount != 1) return(SMS_LIST);
1833
1834     } else if (!strcmp(data_type, "machine")) {
1835         /* MACHINE */
1836         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
1837 ##      repeat retrieve (id = machine.mach_id) where machine.#name = @name
1838 ##      inquire_equel (rowcount = "rowcount")
1839         if (rowcount != 1) return(SMS_MACHINE);
1840
1841     } else if (!strcmp(data_type, "string")) {
1842         /* STRING */
1843 ##      range of s is strings
1844 ##      repeat retrieve (id = s.string_id, refc = s.#refc) 
1845 ##             where s.string = @name
1846 ##      inquire_equel (rowcount = "rowcount")
1847         if (rowcount == 0) {
1848             if (q->type != APPEND) return(SMS_STRING);
1849 ##          range of v is values
1850 ##          retrieve (id = v.value) where v.#name = "strings_id"
1851             id++;
1852 ##          replace v (value = id) where v.#name = "strings_id"
1853 ##          append to strings (string_id = id, string = name, #refc = 1)
1854         } else if (rowcount == 1) {
1855             if (q->type == APPEND || q->type == DELETE) {
1856                 refc += (q->type == APPEND) ? 1 : -1;
1857                 if (refc > 0) {
1858 ##                  replace s (#refc = refc) where s.string_id = id
1859                 } else {
1860 ##                  delete s where s.string_id = id
1861                 }
1862             }
1863         }
1864     } else {
1865         return(SMS_TYPE);
1866     }
1867
1868     /* now set value in argv */
1869     *(int *)argv[vo->index] = id;
1870     
1871     return (SMS_EXISTS);
1872 ##}
1873
1874 \f
1875 translate_ids(q, sq, v, action, actarg)
1876     register struct query *q;
1877     register struct save_queue *sq;
1878     register struct validate *v;
1879     register int (*action)();
1880     int actarg;
1881 ##{
1882 ##  char *name;
1883 ##  char *field_type;
1884 ##  char data_type[17];
1885 ##  int id;
1886 ##  int rowcount;
1887     register int i;
1888     struct valobj *vo;
1889     char **argv;
1890
1891     for (i = 0; i < v->objcnt; i++) {
1892         vo = &v->valobj[i];
1893         if (vo->type == V_FOLLOWUP) break;
1894     }
1895
1896     /* for each row */
1897     while (sq_get_data(sq, &argv)) {
1898
1899         /* get object id */
1900         i = vo->index;
1901         sscanf(argv[i], "%d", &id);
1902         free(argv[i]);
1903         name = (char *)malloc(129);
1904         argv[i] = name;
1905
1906         /* get field type string (known to be at index-1) */
1907         field_type = argv[vo->index-1];
1908
1909         /* get corresponding data type associated with field type name */
1910 ##      repeat retrieve (data_type = alias.trans) 
1911 ##             where alias.#name = @field_type and alias.type = "TYPEDATA"
1912 ##      inquire_equel (rowcount = "rowcount")
1913         if (rowcount != 1) {
1914             sprintf(name, "%d", id);
1915             (*action)(q->vcnt, argv, actarg);
1916             continue;
1917         }
1918
1919         /* retrieve object name */
1920
1921         if (!strcmp(data_type, "user")) {
1922             /* USER */
1923 ##          repeat retrieve (name = users.login) where users.users_id = @id
1924 ##          inquire_equel (rowcount = "rowcount")
1925
1926         } else if (!strcmp(data_type, "list")) {
1927             /* LIST */
1928 ##          repeat retrieve (name = list.#name) where list.list_id = @id
1929 ##          inquire_equel (rowcount = "rowcount")
1930
1931         } else if (!strcmp(data_type, "machine")) {
1932             /* MACHINE */
1933 ##          repeat retrieve (name = machine.#name) where machine.mach_id = @id
1934 ##          inquire_equel (rowcount = "rowcount")
1935
1936         } else if (!strcmp(data_type, "string")) {
1937             /* STRING */
1938 ##          repeat retrieve (name = strings.string) 
1939 ##                 where strings.string_id = @id
1940 ##          inquire_equel (rowcount = "rowcount")
1941
1942         } else {
1943             rowcount = 0;
1944         }
1945
1946         /* if there wasn't a corresponding object name, then use the id */
1947         if (rowcount != 1) sprintf(name, "%d", id);
1948
1949         /* send the data */
1950         (*action)(q->vcnt, argv, actarg);
1951
1952         /* free saved data */
1953         for (i = 0; i < q->vcnt; i++) 
1954             free(argv[i]);
1955         free(argv);
1956     }
1957
1958     sq_destroy(sq);
1959     return (SMS_SUCCESS);
1960 ##}
1961 \f
1962 /*
1963  * Local Variables:
1964  * mode: c
1965  * c-indent-level: 4
1966  * c-continued-statement-offset: 4
1967  * c-brace-offset: -4
1968  * c-argdecl-indent: 4
1969  * c-label-offset: -4
1970  * End:
1971  */
This page took 0.18244 seconds and 3 git commands to generate.