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