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