]> andersk Git - moira.git/blob - server/qsupport.qc
characters -> letters & numbers
[moira.git] / server / qsupport.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  *
10  */
11
12 #ifndef lint
13 static char *rcsid_qsupport_qc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include "query.h"
18 #include "sms_server.h"
19 #include <ctype.h>
20
21
22 extern char *whoami, *strsave();
23 extern int ingres_errno, sms_errcode;
24
25
26 /* Specialized Access Routines */
27
28 /* access_user - verify that client name equals specified login name
29  *
30  *  - since field validation routines are called first, a users_id is
31  *    now in argv[0] instead of the login name.
32  */
33
34 access_user(q, argv, cl)
35     struct query *q;
36     char *argv[];
37     client *cl;
38 {
39     if (cl->users_id != *(int *)argv[0])
40         return(SMS_PERM);
41     else
42         return(SMS_SUCCESS);
43 }
44
45     
46
47 /* access_login - verify that client name equals specified login name
48  *
49  *   argv[0...n] contain search info.  q->
50  */
51
52 access_login(q, argv, cl)
53     struct query *q;
54     char *argv[];
55     client *cl;
56 ##{
57 ##  int rowcount, id;
58 ##  char qual[256];
59
60     build_qual(q->qual, q->argc, argv, qual);
61 ##  range of u is users
62 ##  retrieve (id = u.users_id) where qual
63 ##  inquire_equel(rowcount = "rowcount")
64     if (rowcount != 1 || id != cl->users_id)
65         return(SMS_PERM);
66     else
67         return(SMS_SUCCESS);
68 ##}
69
70     
71
72 /* access_list - check access for most list operations
73  *
74  * Inputs: argv[0] - list_id
75  *          q - query name
76  *          argv[2] - member ID (only for queries "amtl" and  "dmfl")
77  *          argv[7] - group IID (only for query "ulis")
78  *          cl - client name
79  *
80  * - check that client is a member of the access control list
81  * - OR, if the query is add_member_to_list or delete_member_from_list
82  *      and the list is public, allow access if client = member
83  */ 
84
85 access_list(q, argv, cl)
86     struct query *q;
87     char *argv[];
88     client *cl;
89 ##{
90 ##  int list_id, acl_id, flags, rowcount, gid;
91 ##  char acl_type[9];
92     char *client_type;
93     int client_id, status;
94
95     list_id = *(int *)argv[0];
96 ##  repeat retrieve (acl_id = list.#acl_id, acl_type = list.#acl_type,
97 ##                   gid = list.#gid, flags = list.#public) 
98 ##         where list.#list_id = @list_id
99 ##  inquire_equel(rowcount = "rowcount")
100     if (rowcount != 1)
101       return(SMS_INTERNAL);
102
103     /* parse client structure */
104     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
105         return(status);
106
107     /* if amtl or dmfl and list is public allow client to add or delete self */
108     if (((!strcmp("amtl", q->shortname) && flags) ||
109          (!strcmp("dmfl", q->shortname))) &&
110         (!strcmp("USER", argv[1]))) {
111         if (*(int *)argv[2] == client_id) return(SMS_SUCCESS);
112     /* if update_list, don't allow them to change the GID */
113     } else if (!strcmp("ulis", q->shortname)) {
114         if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
115             (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
116           return(SMS_PERM);
117     }
118
119     if (!strcmp(strtrim(acl_type), "LIST")) {
120         if (!client_is_member(cl, acl_id))
121           return(SMS_PERM);
122         else
123           return(SMS_SUCCESS);
124     }
125
126     /* check for client in access control list */
127     status = find_member(acl_type, acl_id, client_type, client_id, 0);
128     if (!status) return(SMS_PERM);
129
130     return(SMS_SUCCESS);
131 ##}
132
133
134 /* access_visible_list - allow access to list only if it is not hidden,
135  *      or if the client is on the ACL
136  *
137  * Inputs: argv[0] - list_id
138  *         cl - client identifier
139  */ 
140
141 access_visible_list(q, argv, cl)
142     struct query *q;
143     char *argv[];
144     client *cl;
145 ##{
146 ##  int list_id, acl_id, flags, rowcount;
147 ##  char acl_type[9];
148     char *client_type;
149     int client_id, status;
150
151     list_id = *(int *)argv[0];
152 ##  repeat retrieve (flags = list.hidden, acl_id = list.#acl_id, 
153 ##      acl_type = list.#acl_type) where list.#list_id = @list_id
154 ##  inquire_equel(rowcount = "rowcount")
155     if (rowcount != 1)
156       return(SMS_INTERNAL);
157     if (!flags)
158         return(SMS_SUCCESS);
159
160
161     if (!strcmp(strtrim(acl_type), "LIST")) {
162         if (!client_is_member(cl, acl_id))
163           return(SMS_PERM);
164         else
165           return(SMS_SUCCESS);
166     }
167
168     /* parse client structure */
169     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
170         return(status);
171
172     /* check for client in access control list */
173     status = find_member(acl_type, acl_id, client_type, client_id, 0);
174     if (!status)
175         return(SMS_PERM);
176
177     return(SMS_SUCCESS);
178 ##}
179
180
181 /* access_vis_list_by_name - allow access to list only if it is not hidden,
182  *      or if the client is on the ACL
183  *
184  * Inputs: argv[0] - list name
185  *         cl - client identifier
186  */ 
187
188 access_vis_list_by_name(q, argv, cl)
189     struct query *q;
190     char *argv[];
191     client *cl;
192 ##{
193 ##  int acl_id, flags, rowcount;
194 ##  char acl_type[9], *listname;
195     char *client_type;
196     int client_id, status;
197
198     listname = argv[0];
199 ##  repeat retrieve (flags = list.hidden, acl_id = list.#acl_id, 
200 ##      acl_type = list.#acl_type) where list.#name = @listname
201 ##  inquire_equel(rowcount = "rowcount");
202     if (rowcount > 1)
203       return(SMS_WILDCARD);
204     if (rowcount == 0)
205       return(SMS_NO_MATCH);
206     if (!flags)
207         return(SMS_SUCCESS);
208
209     if (!strcmp(strtrim(acl_type), "LIST")) {
210         if (!client_is_member(cl, acl_id))
211           return(SMS_PERM);
212         else
213           return(SMS_SUCCESS);
214     }
215
216     /* parse client structure */
217     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
218         return(status);
219
220     /* check for client in access control list */
221     status = find_member(acl_type, acl_id, client_type, client_id, 0);
222     if (!status)
223         return(SMS_PERM);
224
225     return(SMS_SUCCESS);
226 ##}
227
228
229 /* access_member - allow user to access member of type "USER" and name matches
230  * username, or to access member of type "LIST" and list is one that user is
231  * on the acl of, or the list is visible.
232  */
233
234 access_member(q, argv, cl)
235     struct query *q;
236     char *argv[];
237     client *cl;
238 {
239     if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
240       return(access_visible_list(q, &argv[1], cl));
241
242     if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
243         if (cl->users_id == *(int *)argv[1])
244           return(SMS_SUCCESS);
245     }
246
247     return(SMS_PERM);
248 }
249
250
251 /* access_qgli - special access routine for Qualified_get_lists.  Allows
252  * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
253  */
254
255 access_qgli(q, argv, cl)
256     struct query *q;
257     char *argv[];
258     client *cl;
259 {
260     if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
261       return(SMS_SUCCESS);
262     return(SMS_PERM);
263 }
264
265
266 /* access_service - allow access if user is on ACL of service.  Don't
267  * allow access if a wildcard is used.
268  */
269
270 access_service(q, argv, cl)
271     struct query *q;
272     char *argv[];
273     client *cl;
274 ##{
275 ##  int acl_id, rowcount;
276 ##  char *name, acl_type[9];
277     int client_id, status;
278     char *client_type;
279
280     name = argv[0];
281 ##  repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
282 ##      where servers.#name = uppercase(@name)
283 ##  inquire_equel(rowcount = "rowcount")
284     if (rowcount > 1)
285       return(SMS_PERM);
286
287     if (!strcmp(strtrim(acl_type), "LIST")) {
288         if (!client_is_member(cl, acl_id))
289           return(SMS_PERM);
290         else
291           return(SMS_SUCCESS);
292     }
293
294     /* parse client structure */
295     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
296         return(status);
297
298     /* check for client in access control list */
299     status = find_member(acl_type, acl_id, client_type, client_id, 0);
300     if (!status) return(SMS_PERM);
301
302     return(SMS_SUCCESS);
303 ##}
304
305
306
307 /* access_filesys - verify that client is owner or on owners list of filesystem
308  *      named by argv[0]
309  */
310
311 access_filesys(q, argv, cl)
312     struct query *q;
313     char *argv[];
314     client *cl;
315 ##{
316 ##  int rowcount, users_id, list_id;
317 ##  char *name;
318     int status, client_id;
319     char *client_type;
320
321     name = argv[0];
322 ##  repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
323 ##      where filesys.label = @name
324 ##  inquire_equel(rowcount = "rowcount")
325
326     if (rowcount != 1)
327       return(SMS_PERM);
328     if (users_id == cl->users_id)
329       return(SMS_SUCCESS);
330     if (!client_is_member(cl, list_id))
331       return(SMS_PERM);
332     else
333       return(SMS_SUCCESS);
334 ##}
335
336     
337 \f
338 /* Setup Routines */
339
340 /* Setup routine for add_user
341  *
342  * Inputs: argv[0] - login
343  *         argv[1] - uid
344  *
345  * Description:
346  *
347  * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
348  * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
349  */
350
351 setup_ausr(q, argv, cl)
352     struct query *q;
353     register char *argv[];
354     client *cl;
355 ##{
356 ##  int nuid, rowcount;
357
358     if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
359         if (set_next_object_id("uid", "users"))
360           return(SMS_INGRES_ERR);
361 ##      repeat retrieve (nuid = values.value) where values.name = "uid"
362 ##      inquire_equel(rowcount = "rowcount")
363         if (rowcount != 1)
364           return(SMS_INTERNAL);
365         sprintf(argv[1], "%d", nuid);
366     }
367
368     if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
369         sprintf(argv[0], "#%s", argv[1]);
370     }
371
372     return(SMS_SUCCESS);
373 ##}
374
375
376 /* setup_dusr - verify that the user is no longer being referenced 
377  * and may safely be deleted.
378  */
379
380 int setup_dusr(q, argv)
381     struct query *q;
382     char **argv;
383 ##{
384 ##  int flag, id;
385
386     id = *(int *)argv[0];
387
388     /* For now, only allow users to be deleted if their status is 0 */
389 ##  repeat retrieve (flag = u.status) where u.users_id = @id
390     if (flag != 0 && flag != 4)
391       return(SMS_IN_USE);
392
393 ##  repeat delete nfsquota where nfsquota.users_id = @id
394 ##  repeat delete krbmap where krbmap.users_id = @id
395 ##  repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
396 ##                       and imembers.member_type = "USER"))
397     if (flag)
398         return(SMS_IN_USE);
399 ##  repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
400     if (flag)
401         return(SMS_IN_USE);
402 ##  repeat retrieve (flag = any(list.name where list.acl_id=@id and
403 ##                      list.acl_type = "USER"))
404     if (flag)
405         return(SMS_IN_USE);
406 ##  repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
407 ##                      servers.acl_type = "USER"))
408     if (flag)
409         return(SMS_IN_USE);
410 ##  repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
411 ##                      hostaccess.acl_type = "USER"))
412     if (flag)
413         return(SMS_IN_USE);
414     else
415         return(SMS_SUCCESS);
416 ##}
417
418
419 /* setup_spop: verify that there is already a valid POP machine_id in the
420  * pop_id field.  Also take care of keeping track of the post office usage.
421  */
422 int setup_spop(q, argv)
423 struct query *q;
424 char **argv;
425 ##{
426 ##  int id, mid, flag;
427 ##  char type[9];
428
429     id = *(int *)argv[0];
430 ##  repeat retrieve (type = u.potype, mid = u.pop_id,
431 ##                   flag = any(machine.name where machine.mach_id = u.pop_id 
432 ##                                   and u.pop_id != 0 and u.users_id = @id))
433 ##      where u.users_id = @id
434     if (!flag)
435       return(SMS_MACHINE);
436     if (strcmp(strtrim(type), "POP"))
437       set_pop_usage(mid, 1);
438     return(SMS_SUCCESS);
439 ##}
440
441
442 /* setup_dpob:  Take care of keeping track of the post office usage.
443  */
444 int setup_dpob(q, argv)
445 struct query *q;
446 char **argv;
447 ##{
448 ##  int id, user;
449 ##  char type[9];
450
451     user = *(int *)argv[0];
452 ##  repeat retrieve (type = u.potype, id = u.pop_id)
453 ##              where u.users_id = @user
454
455     if (!strcmp(strtrim(type), "POP"))
456       set_pop_usage(id, -1);
457     return(SMS_SUCCESS);
458 ##}
459
460
461 /* setup_dmac - verify that the machine is no longer being referenced 
462  * and may safely be deleted.
463  */
464
465 int setup_dmac(q, argv)
466     struct query *q;
467     char **argv;
468 ##{
469 ##  int flag, id;
470
471     id = *(int *)argv[0];
472 ##  repeat retrieve (flag = any(users.login where users.potype = "POP" 
473 ##                                                and users.pop_id=@id))
474     if (flag)
475         return(SMS_IN_USE);
476 ##  repeat retrieve (flag = any(serverhosts.mach_id
477 ##                               where serverhosts.mach_id=@id))
478     if (flag)
479         return(SMS_IN_USE);
480 ##  repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
481     if (flag)
482         return(SMS_IN_USE);
483 ##  repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
484     if (flag)
485         return(SMS_IN_USE);
486 ##  repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
487     if (flag)
488         return(SMS_IN_USE);
489 ##  repeat retrieve (flag = any(palladium.mach_id where palladium.mach_id=@id))
490     if (flag)
491         return(SMS_IN_USE);
492
493 ##  repeat delete mcmap where mcmap.mach_id = @id
494     return(SMS_SUCCESS);
495 ##}
496
497
498 /* setup_dclu - verify that the cluster is no longer being referenced 
499  * and may safely be deleted.
500  */
501
502 int setup_dclu(q, argv)
503     struct query *q;
504     char **argv;
505 ##{
506 ##  int flag, id;
507
508     id = *(int *)argv[0];
509 ##  repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
510     if (flag)
511         return(SMS_IN_USE);
512 ##  repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
513     if (flag)
514         return(SMS_IN_USE);
515     else
516         return(SMS_SUCCESS);
517 ##}
518
519
520 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
521  * a new gid and put it in argv[6].  Otherwise if argv[6] is UNIQUE_ID but
522  * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
523  * a -1 there.  Remember that this is also used for ulis, with the indexes
524  * at 6 & 7.
525  */
526
527 int setup_alis(q, argv)
528 struct query *q;
529 char **argv;
530 ##{
531 ##  int ngid;
532     char *malloc();
533     int idx;
534
535     if (!strcmp(q->shortname, "alis"))
536       idx = 6;
537     else if (!strcmp(q->shortname, "ulis"))
538       idx = 7;
539
540     if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
541         if (atoi(argv[idx - 1])) {
542             if (set_next_object_id("gid", "list"))
543               return(SMS_INGRES_ERR);
544 ##          repeat retrieve (ngid = values.value) where values.name = "gid"
545             sprintf(argv[idx], "%d", ngid);
546         } else {
547             strcpy(argv[idx], "-1");
548         }
549     }
550
551     return(SMS_SUCCESS);
552 ##}
553
554
555 /* setup_dlist - verify that the list is no longer being referenced 
556  * and may safely be deleted.
557  */
558
559 int setup_dlis(q, argv)
560     struct query *q;
561     char **argv;
562 ##{
563 ##  int flag, id;
564
565     id = *(int *)argv[0];
566 ##  repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
567 ##                       and imembers.member_type = "LIST"))
568     if (flag)
569         return(SMS_IN_USE);
570 ##  repeat retrieve (flag = any(imembers.member_id where imembers.list_id=@id))
571     if (flag)
572         return(SMS_IN_USE);
573 ##  repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
574     if (flag)
575         return(SMS_IN_USE);
576 ##  repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
577     if (flag)
578         return(SMS_IN_USE);
579 ##  repeat retrieve (flag = any(list.name where list.acl_id=@id and
580 ##                      list.acl_type = "LIST" and list.list_id != @id))
581     if (flag)
582         return(SMS_IN_USE);
583 ##  repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
584 ##                      servers.acl_type = "LIST"))
585     if (flag)
586         return(SMS_IN_USE);
587 ##  repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
588 ##                      hostaccess.acl_type = "LIST"))
589     if (flag)
590         return(SMS_IN_USE);
591 ##  repeat retrieve (flag = any(zephyr.class
592 ##              where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
593 ##                    zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
594 ##                    zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
595 ##                    zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
596     if (flag)
597         return(SMS_IN_USE);
598     else
599         return(SMS_SUCCESS);
600 ##}
601
602
603 /* setup_dsin - verify that the service is no longer being referenced 
604  * and may safely be deleted.
605  */
606
607 int setup_dsin(q, argv)
608     struct query *q;
609     char **argv;
610 ##{
611 ##  int flag;
612 ##  char *name;
613
614     name = argv[0];
615 ##  repeat retrieve (flag = any(serverhosts.service 
616 ##                              where serverhosts.service=uppercase(@name)))
617     if (flag)
618         return(SMS_IN_USE);
619 ##  repeat retrieve (flag = servers.inprogress) where servers.#name = @name
620     if (flag)
621         return(SMS_IN_USE);
622     else
623         return(SMS_SUCCESS);
624 ##}
625
626
627 /* setup_dshi - verify that the service-host is no longer being referenced 
628  * and may safely be deleted.
629  */
630
631 int setup_dshi(q, argv)
632     struct query *q;
633     char **argv;
634 ##{
635 ##  int flag, id;
636 ##  char *name;
637
638     name = argv[0];
639     id = *(int *)argv[1];
640 ##  repeat retrieve (flag=serverhosts.inprogress) 
641 ##      where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
642     if (flag)
643         return(SMS_IN_USE);
644     else
645         return(SMS_SUCCESS);
646 ##}
647
648
649 /**
650  ** setup_add_filesys - verify existance of referenced file systems
651  **
652  ** Inputs:     Add
653  **   argv[1] - type
654  **   argv[2] - mach_id
655  **   argv[3] - name
656  **   argv[5] - access
657  **
658  ** Description:
659  **   - for type = RVD:
660  **        * allow anything
661  **   - for type = NFS:
662  **        * extract directory prefix from name
663  **        * verify mach_id/dir in nfsphys
664  **        * verify access in {r, w, R, W}
665  **
666  **  Side effect: sets variable var_phys_id to the ID of the physical
667  **     filesystem (nfsphys_id for NFS, 0 for RVD)
668  **
669  ** Errors:
670  **   SMS_NFS - specified directory not exported
671  **   SMS_FILESYS_ACCESS - invalid filesys access
672  **
673  **/
674
675 ##static int var_phys_id;
676
677 setup_afil(q, argv)
678     struct query *q;
679     char *argv[];
680 {
681     char *type;
682     int mach_id;
683     char *name;
684     char *access;  
685
686     type = argv[1];
687     mach_id = *(int *)argv[2];
688     name = argv[3];
689     access = argv[5];
690     var_phys_id = 0;
691
692     if (!strcmp(type, "NFS"))
693         return (check_nfs(mach_id, name, access));
694     else
695         return(SMS_SUCCESS);
696 }
697
698
699 /* Verify the arguments, depending on the FStype.  Also, if this is an
700  * NFS filesystem, then update any quotas for that filesystem to reflect
701  * the new phys_id.
702  */
703
704 setup_ufil(q, argv)
705     struct query *q;
706     char *argv[];
707 ##{
708     int mach_id, status;
709     char *type, *name, *access;  
710 ##  int fid;
711
712     type = argv[2];
713     mach_id = *(int *)argv[3];
714     name = argv[4];
715     access = argv[6];
716     var_phys_id = 0;
717
718     if (!strcmp(type, "NFS")) {
719         status = check_nfs(mach_id, name, access);
720         fid = *(int *)argv[0];
721 ##      replace nfsquota (phys_id = var_phys_id) where nfsquota.filsys_id = fid
722         return(status);
723     } else
724       return(SMS_SUCCESS);
725 ##}
726
727
728 /* Find the NFS physical partition that the named directory is on.
729  * This is done by comparing the dir against the mount point of the
730  * partition.  To make sure we get the correct match when there is 
731  * more than one, we sort the query in reverse order by dir name.
732  */
733
734 ##check_nfs(mach_id, name, access)
735 ##  int mach_id;
736     char *name;
737     char *access;
738 ##{
739 ##  char dir[81];
740     char caccess;
741     register int status;
742     register char *cp1;
743     register char *cp2;
744
745     caccess = (isupper(*access)) ? tolower(*access) : *access;
746     if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
747
748     status = SMS_NFS;
749 ##  range of np is nfsphys
750 ##  repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
751 ##      where np.#mach_id = @mach_id sort by #dir:d {
752          cp1 = name;
753          cp2 = dir;
754          while (*cp2) {
755              if (*cp1++ != *cp2) break;
756              cp2++;
757          }
758          if (*cp2 == 0) {
759              status = SMS_SUCCESS;
760 ##           endretrieve
761          }
762 ##  }
763
764     return(status);
765 ##}
766
767
768 /* setup_dfil: free any quota records and fsgroup info associated with
769  * a filesystem when it is deleted.  Also adjust the allocation numbers.
770  */
771
772 setup_dfil(q, argv, cl)
773     struct query  *q;
774     char **argv;
775     client *cl;
776 ##{
777 ##  int id;
778
779     id = *(int *)argv[0];
780 ##  range of q is nfsquota
781 ##  range of fs is filesys
782 ##  range of n is nfsphys
783 ##  repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
784 ##      where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
785
786 ##  repeat delete q where q.filsys_id = @id
787 ##  repeat delete fsgroup where fsgroup.filsys_id = @id
788 ##  repeat delete fsgroup where fsgroup.group_id = @id
789     return(SMS_SUCCESS);
790 ##}
791
792
793 /* setup_dnfp: check to see that the nfs physical partition does not have
794  * any filesystems assigned to it before allowing it to be deleted.
795  */
796
797 setup_dnfp(q, argv, cl)
798     struct query  *q;
799     char **argv;
800     client *cl;
801 ##{
802 ##  int id, exists;
803
804     id = *(int *)argv[0];
805 ##  repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
806     if (exists)
807       return(SMS_IN_USE);
808     return(SMS_SUCCESS);
809 ##}
810
811
812 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
813  *   argv[0] = filsys_id
814  *   argv[1] = users_id
815  */
816
817 setup_dnfq(q, argv, cl)
818     struct query  *q;
819     char **argv;
820     client *cl;
821 ##{
822 ##  int quota, fs, user;
823
824     fs = *(int *)argv[0];
825     user = *(int *)argv[1];
826
827 ##  range of q is nfsquota
828 ##  repeat retrieve (quota = q.#quota) where q.users_id = @user and
829 ##      q.filsys_id = @fs
830 ##  repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
831 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
832     return(SMS_SUCCESS);
833 ##}
834
835
836 /* setup_sshi: don't exclusive lock the machine table during
837  * set_server_host_internal.
838  */
839
840 setup_sshi(q, argv, cl)
841     struct query  *q;
842     char **argv;
843     client *cl;
844 ##{
845 ##  set lockmode session where readlock = system
846 ##}
847
848
849 /* setup add_kerberos_user_mapping: add the string to the string 
850  * table if necessary.
851  */
852
853 setup_akum(q, argv, cl)
854 struct query *q;
855 char **argv;
856 client *cl;
857 ##{
858 ##  int id, rowcount;
859 ##  char *name;
860
861     name = argv[1];
862 ##  range of s is strings
863 ##  repeat retrieve (id = s.string_id) where s.string = @name
864 ##  inquire_equel (rowcount = "rowcount")
865     if (rowcount == 0) {
866         if (q->type != APPEND) return(SMS_STRING);
867 ##      range of v is values
868 ##      retrieve (id = v.value) where v.#name = "strings_id"
869         id++;
870 ##      replace v (value = id) where v.#name = "strings_id"
871 ##      append to strings (string_id = id, string = name)
872     }
873     *(int *)argv[1] = id;
874     return(0);
875 ##}
876
877
878 \f
879 /* FOLLOWUP ROUTINES */
880
881 /* generic set_modtime routine.  This takes the table name from the query,
882  * and will update the modtime, modby, and modwho fields in the entry in
883  * the table whose name field matches argv[0].
884  */
885
886 set_modtime(q, argv, cl)
887     struct query *q;
888     char *argv[];
889     client *cl;
890 ##{
891 ##  char *name, *entity, *table;
892 ##  int who;
893
894     entity = cl->entity;
895     who = cl->client_id;
896     table = q->rtable;
897     name = argv[0];
898
899 ##  replace table (modtime = "now", modby = who, modwith = entity)
900 ##       where table.#name = name
901     return(SMS_SUCCESS);
902 ##}
903
904 /* generic set_modtime_by_id routine.  This takes the table name from
905  * the query, and the id name from the validate record,
906  * and will update the modtime, modby, and modwho fields in the entry in
907  * the table whose id matches argv[0].
908  */
909
910 set_modtime_by_id(q, argv, cl)
911     struct query *q;
912     char **argv;
913     client *cl;
914 ##{
915 ##  char *entity, *table, *id_name;
916 ##  int who, id;
917
918     entity = cl->entity;
919     who = cl->client_id;
920     table = q->rtable;
921     id_name = q->validate->object_id;
922
923     id = *(int *)argv[0];
924 ##  replace table (modtime = "now", modby = who, modwith = entity)
925 ##       where table.id_name = id
926     return(SMS_SUCCESS);
927 ##}
928
929
930 /* Sets the finger modtime on a user record.  The users_id will be in argv[0].
931  */
932
933 set_finger_modtime(q, argv, cl)
934     struct query *q;
935     char *argv[];
936     client *cl;
937 ##{
938 ##  int users_id, who;
939 ##  char *entity;
940
941     entity = cl->entity;
942     who = cl->client_id;
943     users_id = *(int *)argv[0];
944
945 ##  repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
946 ##       where u.#users_id = @users_id
947     return(SMS_SUCCESS);
948 ##}
949
950
951 /* Sets the pobox modtime on a user record.  The users_id will be in argv[0].
952  */
953
954 set_pobox_modtime(q, argv, cl)
955     struct query *q;
956     char **argv;
957     client *cl;
958 ##{
959 ##  int users_id, who;
960 ##  char *entity;
961
962     entity = cl->entity;
963     who = cl->client_id;
964     users_id = *(int *)argv[0];
965
966 ##  repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
967 ##       where users.#users_id = @users_id
968     return(SMS_SUCCESS);
969 ##}
970
971
972 /* Like set_modtime, but uppercases the name first.
973  */
974
975 set_uppercase_modtime(q, argv, cl)
976     struct query *q;
977     char **argv;
978     client *cl;
979 ##{
980 ##  char *name, *entity, *table;
981 ##  int who;
982
983     entity = cl->entity;
984     who = cl->client_id;
985     table = q->rtable;
986     name = argv[0];
987
988 ##  replace table (modtime = "now", modby = who, modwith = entity)
989 ##       where table.#name = uppercase(name)
990     return(SMS_SUCCESS);
991 ##}
992
993
994 /* Sets the modtime on the machine whose mach_id is in argv[0].  This routine
995  * is necessary for add_machine_to_cluster becuase the table that query
996  * operates on is "mcm", not "machine".
997  */
998
999 set_mach_modtime_by_id(q, argv, cl)
1000     struct query *q;
1001     char **argv;
1002     client *cl;
1003 ##{
1004 ##  char *entity;
1005 ##  int who, id;
1006
1007     entity = cl->entity;
1008     who = cl->client_id;
1009
1010     id = *(int *)argv[0];
1011 ##  range of m is machine
1012 ##  repeat replace m (modtime = "now", modby = @who, modwith = @entity)
1013 ##       where m.mach_id = @id
1014     return(SMS_SUCCESS);
1015 ##}
1016
1017
1018 /* Sets the modtime on the cluster whose mach_id is in argv[0].  This routine
1019  * is necessary for add_cluster_data and delete_cluster_data becuase the
1020  * table that query operates on is "svc", not "cluster".
1021  */
1022
1023 set_cluster_modtime_by_id(q, argv, cl)
1024     struct query *q;
1025     char **argv;
1026     client *cl;
1027 ##{
1028 ##  char *entity;
1029 ##  int who, id;
1030
1031     entity = cl->entity;
1032     who = cl->client_id;
1033
1034     id = *(int *)argv[0];
1035 ##  range of c is cluster
1036 ##  repeat replace c (modtime = "now", modby = @who, modwith = @entity)
1037 ##       where c.clu_id = @id
1038     return(SMS_SUCCESS);
1039 ##}
1040
1041
1042 /* sets the modtime on the serverhost where the service name is in argv[0]
1043  * and the mach_id is in argv[1].
1044  */
1045
1046 set_serverhost_modtime(q, argv, cl)
1047     struct query *q;
1048     char **argv;
1049     client *cl;
1050 ##{
1051 ##  char *entity, *serv;
1052 ##  int who, id;
1053
1054     entity = cl->entity;
1055     who = cl->client_id;
1056
1057     serv = argv[0];
1058     id = *(int *)argv[1];
1059 ##  repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
1060 ##       where sh.service = uppercase(@serv) and sh.mach_id = @id
1061     return(SMS_SUCCESS);
1062 ##}
1063
1064
1065 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1066  * directory name is in argv[1].
1067  */
1068
1069 set_nfsphys_modtime(q, argv, cl)
1070     struct query *q;
1071     char **argv;
1072     client *cl;
1073 ##{
1074 ##  char *entity, *dir;
1075 ##  int who, id;
1076
1077     entity = cl->entity;
1078     who = cl->client_id;
1079
1080     id = *(int *)argv[0];
1081     dir = argv[1];
1082 ##  repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1083 ##       where np.#dir = @dir and np.mach_id = @id
1084     return(SMS_SUCCESS);
1085 ##}
1086
1087
1088 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1089  * label.
1090  */
1091
1092 set_filesys_modtime(q, argv, cl)
1093     struct query *q;
1094     char *argv[];
1095     client *cl;
1096 ##{
1097 ##  char *label, *entity;
1098 ##  int who;
1099
1100     entity = cl->entity;
1101     who = cl->client_id;
1102
1103     label = argv[0];
1104     if (!strcmp(q->shortname, "ufil"))
1105       label = argv[1];
1106
1107 ##  repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1108 ##                     #phys_id = @var_phys_id)  where fs.#label = @label
1109     return(SMS_SUCCESS);
1110 ##}
1111
1112
1113 /* sets the modtime on a zephyr class, where argv[0] contains the class
1114  * name.
1115  */
1116
1117 set_zephyr_modtime(q, argv, cl)
1118     struct query *q;
1119     char *argv[];
1120     client *cl;
1121 ##{
1122 ##  char *class, *entity;
1123 ##  int who;
1124
1125     entity = cl->entity;
1126     who = cl->client_id;
1127
1128     class = argv[0];
1129
1130 ##  repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1131 ##                     where z.#class = @class
1132     return(SMS_SUCCESS);
1133 ##}
1134
1135
1136 /* fixes the modby field.  This will be the second to last thing in the
1137  * argv, the argv length is determined from the query structure.  It is
1138  * passed as a pointer to an integer.  This will either turn it into a
1139  * username, or # + the users_id.
1140  */
1141 followup_fix_modby(q, sq, v, action, actarg, cl)
1142     struct query *q;
1143     register struct save_queue *sq;
1144     struct validate *v;
1145     register int (*action)();
1146     register int actarg;
1147     client *cl;
1148 ##{
1149     register int i, j;
1150     char **argv, *malloc();
1151 ##  int id, rowcount;
1152 ##  char *name;
1153
1154     i = q->vcnt - 2;
1155     while (sq_get_data(sq, &argv)) {
1156         id = atoi(argv[i]);
1157         free(argv[i]);
1158         argv[i] = malloc(256);
1159         name = argv[i];
1160         if (id > 0)
1161 ##        repeat retrieve (name = users.login) where users.users_id = @id
1162         else {
1163             id = -id;
1164 ##          repeat retrieve (name = strings.string) where strings.string_id = @id
1165             id = -id;
1166         }
1167 ##      inquire_equel(rowcount = "rowcount")
1168         if (rowcount != 1) {
1169             sprintf(argv[i], "#%d", id);
1170         }
1171         (*action)(q->vcnt, argv, actarg);
1172         for (j = 0; j < q->vcnt; j++)
1173           free(argv[j]);
1174         free(argv);
1175     }
1176     sq_destroy(sq);
1177     return(SMS_SUCCESS);
1178 ##}
1179
1180
1181 /**
1182  ** followup_ausr - add finger and pobox entries, set_user_modtime
1183  **
1184  ** Inputs:
1185  **     argv[0] - login (add_user)
1186  **     argv[3] - last name
1187  **     argv[4] - first name
1188  **     argv[5] - middle name
1189  **
1190  **/
1191
1192 followup_ausr(q, argv, cl)
1193     struct query *q;
1194     char *argv[];
1195     client *cl;
1196 ##{
1197 ##  int who;
1198 ##  char *login, *entity;
1199 ##  char fullname[129];
1200
1201     login = argv[0];
1202     who = cl->client_id;
1203     entity = cl->entity;
1204
1205     /* build fullname */
1206     if (strlen(argv[4]) && strlen(argv[5]))
1207         sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1208     else if (strlen(argv[4]))
1209         sprintf(fullname, "%s %s", argv[4], argv[3]);
1210     else
1211         sprintf(fullname, "%s", argv[3]);
1212
1213     /* create finger entry, pobox & set modtime on user */
1214 ##  repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1215 ##           #fullname=@fullname, mit_affil = u.mit_year,
1216 ##           fmodtime="now", fmodby=@who, fmodwith=@entity,
1217 ##           potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1218 ##      where u.#login = @login
1219
1220     return(SMS_SUCCESS);
1221 ##}
1222
1223
1224 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1225  * type in argv[1].  Then completes the upcall to the user.
1226  *
1227  * argv[2] is of the form "123:234" where the first integer is the machine
1228  * ID if it is a pop box, and the second is the string ID if it is an SMTP
1229  * box.  argv[1] should be "POP", "SMTP", or "NONE".  Boxes of type NONE
1230  * are skipped.
1231  */
1232
1233 followup_gpob(q, sq, v, action, actarg, cl)
1234     register struct query *q;
1235     register struct save_queue *sq;
1236     register struct validate *v;
1237     register int (*action)();
1238     int actarg;
1239     client *cl;
1240 ##{
1241     char **argv, *index();
1242     char *ptype, *p;
1243 ##  char box[129], *name;
1244 ##  int mid, sid, rowcount;
1245
1246     /* for each row */
1247     while (sq_get_data(sq, &argv)) {
1248         sms_trim_args(2, argv);
1249         ptype = argv[1];
1250         p = index(argv[2], ':');
1251         *p++ = 0;
1252         mid = atoi(argv[2]);
1253         sid = atoi(p);
1254         free(argv[2]);
1255
1256         if (!strcmp(ptype, "POP")) {
1257 ##          repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1258 ##          inquire_equel(rowcount = "rowcount")
1259             if (rowcount != 1)
1260               return(SMS_MACHINE);
1261         } else if (!strcmp(ptype, "SMTP")) {
1262 ##          repeat retrieve (box=strings.string) where strings.string_id=@sid
1263 ##          inquire_equel(rowcount = "rowcount")
1264             if (rowcount != 1)
1265               return(SMS_STRING);
1266         } else /* ptype == "NONE" */ {
1267             goto skip;
1268         }
1269
1270         if (!strcmp(q->shortname, "gpob")) {
1271             sid = atoi(argv[4]);
1272             free(argv[4]);
1273             argv[4] = malloc(256);
1274             name = argv[4];
1275             if (sid > 0)
1276 ##            repeat retrieve (name = users.login) where users.users_id = @sid
1277             else {
1278               sid = -sid;
1279 ##            repeat retrieve (name = strings.string) 
1280 ##                where strings.string_id = @sid
1281               sid = -sid;
1282             }
1283 ##          inquire_equel(rowcount = "rowcount")
1284             if (rowcount != 1)
1285               sprintf(name, "#%d", sid);
1286         }
1287
1288         argv[2] = box;
1289         (*action)(q->vcnt, argv, actarg);
1290     skip:
1291         /* free saved data */
1292         free(argv[0]);
1293         free(argv[1]);
1294         free(argv[4]);
1295         free(argv);
1296     }
1297
1298     sq_destroy(sq);
1299     return (SMS_SUCCESS);
1300 ##}
1301
1302
1303 /* followup_glin: fix the ace_name in argv[8].  argv[7] will contain the
1304  * ace_type: "LIST", "USER", or "NONE".  Decode the id in argv[8] into the
1305  * proper name based on the type, and repace that string in the argv.
1306  * Also fixes the modby field by called followup_fix_modby.
1307  */
1308
1309 followup_glin(q, sq, v, action, actarg, cl)
1310     register struct query *q;
1311     register struct save_queue *sq;
1312     register struct validate *v;
1313     register int (*action)();
1314     int actarg;
1315     client *cl;
1316 ##{
1317     char **argv, *malloc(), *realloc(), *type;
1318 ##  char *name;
1319 ##  int id, rowcount;
1320     int i, idx;
1321
1322     idx = 8;
1323     if (!strcmp(q->shortname, "gsin"))
1324       idx = 12;
1325
1326     while (sq_get_data(sq, &argv)) {
1327         sms_trim_args(q->vcnt, argv);
1328
1329         id = atoi(argv[i = q->vcnt - 2]);
1330         free(argv[i]);
1331         name = argv[i] = malloc(256);
1332         if (id > 0)
1333 ##        repeat retrieve (name = users.login) where users.users_id = @id
1334         else {
1335           id = -id;
1336 ##        repeat retrieve (name = strings.string) where strings.string_id = @id
1337           id = -id;
1338         }
1339 ##      inquire_equel(rowcount = "rowcount")
1340         if (rowcount != 1)
1341           sprintf(argv[i], "#%d", id);
1342
1343         id = atoi(argv[idx]);
1344         type = argv[idx - 1];
1345         if ((name = malloc(33)) == NULL)
1346             return(SMS_NO_MEM);
1347
1348         if (!strcmp(type, "LIST")) {
1349 ##          repeat retrieve (name = list.#name) where list.list_id = @id
1350 ##          inquire_equel(rowcount = "rowcount")
1351             if (rowcount != 1)
1352                 strcpy(name, "???");
1353         } else if (!strcmp(type, "USER")) {
1354 ##          repeat retrieve (name = users.login) where users.users_id = @id
1355 ##          inquire_equel(rowcount = "rowcount")
1356             if (rowcount != 1)
1357                 strcpy(name, "???");
1358         } else if (!strcmp(type, "KERBEROS")) {
1359 ##          repeat retrieve (name = strings.string) where strings.string_id = @id
1360 ##          inquire_equel(rowcount = "rowcount")
1361             if (rowcount != 1)
1362                 strcpy(name, "???");
1363         } else if (!strcmp(type, "NONE")) {
1364             strcpy(name, "NONE");
1365         } else
1366           strcpy(name, "???");
1367         free(argv[idx]);
1368         argv[idx] = name;
1369
1370         if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1371             argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1372             strcpy(argv[6], UNIQUE_GID);
1373         }
1374
1375         /* send the data */
1376         (*action)(q->vcnt, argv, actarg);
1377
1378         /* free saved data */
1379         for (i = 0; i < q->vcnt; i++) 
1380             free(argv[i]);
1381         free(argv);
1382     }
1383
1384     sq_destroy(sq);
1385     return (SMS_SUCCESS);
1386 ##}
1387
1388
1389 /** followup_amtl - followup for amtl and dmfl; when adding a list 
1390  **                 member to a maillist, make member list a maillist also
1391  **                 unless list is a user-group.
1392  **                 Then set_list_modtime_by_id.
1393  **
1394  ** Inputs:
1395  **   argv[0] - list_id
1396  **   argv[1] - member_type
1397  **   argv[2] - member_id
1398  **
1399  **/
1400
1401 followup_amtl(q, argv, cl)
1402     struct query *q;
1403     char *argv[];
1404     client *cl;
1405 ##{
1406 ##  int list_id;
1407 ##  int member_id;
1408 ##  int exists, who;
1409 ##  char *entity;
1410
1411     list_id = *(int *)argv[0];
1412     entity = cl->entity;
1413     who = cl->client_id;
1414
1415 ##  range of l is list
1416 ##  repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1417 ##       where l.#list_id = @list_id
1418
1419     /* if query is not amtl or if member_type is not LIST then return */
1420     if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4)) 
1421         return(SMS_SUCCESS);
1422
1423     member_id = *(int *)argv[2];
1424
1425     /* is parent list a mailing list? */
1426 ##  repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1427     if (!exists)
1428         return(SMS_SUCCESS);
1429
1430     /* list is not a user-group; add list to maillist table */
1431 ##  repeat replace l (maillist = 1) where l.#list_id = @member_id
1432     return(SMS_SUCCESS);
1433 ##}
1434
1435
1436 /* followup_gnfq: Fix the directory name & modby fields
1437  *   argv[0] = filsys_id
1438  *   argv[2] = ascii(quota)
1439  */
1440
1441 followup_gnfq(q, sq, v, action, actarg, cl)
1442     struct query *q;
1443     register struct save_queue *sq;
1444     struct validate *v;
1445     register int (*action)();
1446     register int actarg;
1447     client *cl;
1448 ##{
1449     register int j;
1450     char **argv, *malloc();
1451 ##  int id, rowcount;
1452 ##  char *name, *label;
1453
1454     while (sq_get_data(sq, &argv)) {
1455         id = atoi(argv[3]);
1456         free(argv[3]);
1457         argv[3] = malloc(256);
1458         name = argv[3];
1459         if (id == 0) {
1460             label = argv[0];
1461 ##          repeat retrieve (name = filesys.#name) where filesys.#label = @label
1462         } else {
1463 ##          repeat retrieve (name = nfsphys.dir) where nfsphys.nfsphys_id = @id
1464         }
1465 ##      inquire_equel(rowcount = "rowcount")
1466         if (rowcount != 1) {
1467             sprintf(argv[3], "#%d", id);
1468         }
1469
1470         id = atoi(argv[6]);
1471         free(argv[6]);
1472         argv[6] = malloc(256);
1473         name = argv[6];
1474         if (id > 0)
1475 ##        repeat retrieve (name = users.login) where users.users_id = @id
1476         else {
1477             id = -id;
1478 ##          repeat retrieve (name = strings.string) where strings.string_id = @id
1479             id = -id;
1480         }
1481 ##      inquire_equel(rowcount = "rowcount")
1482         if (rowcount != 1) {
1483             sprintf(argv[6], "#%d", id);
1484         }
1485         (*action)(q->vcnt, argv, actarg);
1486         for (j = 0; j < q->vcnt; j++)
1487           free(argv[j]);
1488         free(argv);
1489     }
1490     sq_destroy(sq);
1491     return(SMS_SUCCESS);
1492 ##}
1493
1494
1495 /* followup_anfq: Add allocation to nfsphys after creating quota.
1496  *   argv[0] = filsys_id
1497  *   argv[2] = ascii(quota)
1498  */
1499
1500 followup_anfq(q, argv, cl)
1501     struct query  *q;
1502     char **argv;
1503     client *cl;
1504 ##{
1505 ##  int quota, user, fs, who;
1506 ##  char *entity;
1507
1508     fs = *(int *)argv[0];
1509     user = *(int *)argv[1];
1510     quota = atoi(argv[2]);
1511     who = cl->client_id;
1512     entity = cl->entity;
1513
1514 ##  repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1515 ##      where nq.filsys_id = @fs and nq.users_id = @user
1516 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1517 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1518     return(SMS_SUCCESS);
1519 ##}
1520
1521
1522 /* followup_gzcl:
1523  */
1524
1525 followup_gzcl(q, sq, v, action, actarg, cl)
1526     register struct query *q;
1527     register struct save_queue *sq;
1528     register struct validate *v;
1529     register int (*action)();
1530     int actarg;
1531     client *cl;
1532 ##{
1533 ##  char *name;
1534 ##  int rowcount, id;
1535     char **argv;
1536     int i;
1537
1538     while (sq_get_data(sq, &argv)) {
1539         sms_trim_args(q->vcnt, argv);
1540
1541         id = atoi(argv[i = q->vcnt - 2]);
1542         free(argv[i]);
1543         name = argv[i] = malloc(256);
1544         if (id > 0)
1545 ##        repeat retrieve (name = users.login) where users.users_id = @id
1546         else {
1547           id = -id;
1548 ##        repeat retrieve (name = strings.string) where strings.string_id = @id
1549           id = -id;
1550         }
1551 ##      inquire_equel(rowcount = "rowcount")
1552         if (rowcount != 1)
1553           sprintf(argv[i], "#%d", id);
1554
1555         for (i = 1; i < 8; i+=2) {
1556             id = atoi(argv[i+1]);
1557             free(argv[i+1]);
1558             if ((name = argv[i+1] = malloc(33)) == NULL)
1559               return(SMS_NO_MEM);
1560             if (!strcmp(argv[i], "LIST")) {
1561 ##              repeat retrieve (name = list.#name) where list.list_id = @id
1562 ##              inquire_equel(rowcount = "rowcount")
1563                 if (rowcount != 1)
1564                   strcpy(name, "???");
1565             } else if (!strcmp(argv[i], "USER")) {
1566 ##              repeat retrieve (name = users.login) where users.users_id = @id
1567 ##              inquire_equel(rowcount = "rowcount")
1568                 if (rowcount != 1)
1569                   strcpy(name, "???");
1570             } else if (!strcmp(argv[i], "KERBEROS")) {
1571 ##              repeat retrieve (name = strings.string) where strings.string_id = @id
1572 ##              inquire_equel(rowcount = "rowcount")
1573                 if (rowcount != 1)
1574                   strcpy(name, "???");
1575             } else if (!strcmp(argv[i], "NONE")) {
1576                 strcpy(name, "NONE");
1577             } else {
1578                 strcpy(name, "???");
1579             }
1580         }
1581
1582         /* send the data */
1583         (*action)(q->vcnt, argv, actarg);
1584
1585         /* free saved data */
1586         for (i = 0; i < q->vcnt; i++) 
1587             free(argv[i]);
1588         free(argv);
1589     }
1590     sq_destroy(sq);
1591     return(SMS_SUCCESS);
1592 ##}
1593
1594
1595 /* followup_gsha:
1596  */
1597
1598 followup_gsha(q, sq, v, action, actarg, cl)
1599     register struct query *q;
1600     register struct save_queue *sq;
1601     register struct validate *v;
1602     register int (*action)();
1603     int actarg;
1604     client *cl;
1605 ##{
1606 ##  char *name;
1607 ##  int rowcount, id;
1608     char **argv;
1609     int i;
1610
1611     while (sq_get_data(sq, &argv)) {
1612         sms_trim_args(q->vcnt, argv);
1613
1614         id = atoi(argv[4]);
1615         free(argv[4]);
1616         name = argv[4] = malloc(256);
1617         if (id > 0)
1618 ##        repeat retrieve (name = users.login) where users.users_id = @id
1619         else {
1620           id = -id;
1621 ##        repeat retrieve (name = strings.string) where strings.string_id = @id
1622           id = -id;
1623         }
1624 ##      inquire_equel(rowcount = "rowcount")
1625         if (rowcount != 1)
1626           sprintf(argv[4], "#%d", id);
1627
1628         id = atoi(argv[2]);
1629         free(argv[2]);
1630         if ((name = argv[2] = malloc(33)) == NULL)
1631           return(SMS_NO_MEM);
1632         if (!strcmp(argv[1], "LIST")) {
1633 ##          repeat retrieve (name = list.#name) where list.list_id = @id
1634 ##          inquire_equel(rowcount = "rowcount")
1635             if (rowcount != 1)
1636               strcpy(name, "???");
1637         } else if (!strcmp(argv[1], "USER")) {
1638 ##          repeat retrieve (name = users.login) where users.users_id = @id
1639 ##          inquire_equel(rowcount = "rowcount")
1640             if (rowcount != 1)
1641               strcpy(name, "???");
1642         } else if (!strcmp(argv[1], "KERBEROS")) {
1643 ##          repeat retrieve (name = strings.string) where strings.string_id = @id
1644 ##          inquire_equel(rowcount = "rowcount")
1645             if (rowcount != 1)
1646               strcpy(name, "???");
1647         } else if (!strcmp(argv[1], "NONE")) {
1648             strcpy(name, "NONE");
1649         } else {
1650             strcpy(name, "???");
1651         }
1652
1653         /* send the data */
1654         (*action)(q->vcnt, argv, actarg);
1655
1656         /* free saved data */
1657         for (i = 0; i < q->vcnt; i++) 
1658             free(argv[i]);
1659         free(argv);
1660     }
1661     sq_destroy(sq);
1662     return(SMS_SUCCESS);
1663 ##}
1664
1665
1666 \f
1667 /* Special query routines */
1668
1669 /* set_pobox - this does all of the real work.
1670  *       argv = user_id, type, box
1671  * if type is POP, then box should be a machine, and its ID should be put in
1672  * pop_id.  If type is SMTP, then box should be a string and its ID should
1673  * be put in box_id.  If type is NONE, then box doesn't matter.
1674  */
1675
1676 int set_pobox(q, argv, cl)
1677     struct query *q;
1678     char **argv;
1679     client *cl;
1680 ##{
1681 ##  int user, id, rowcount;
1682 ##  char *box, potype[9];
1683
1684     box = argv[2];
1685     user = *(int *)argv[0];
1686
1687 ##  repeat retrieve (id = users.pop_id, potype = users.#potype)
1688 ##              where users.users_id = @user
1689     if (!strcmp(strtrim(potype), "POP"))
1690       set_pop_usage(id, -1);
1691
1692     if (!strcmp(argv[1], "POP")) {
1693 ##      repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1694 ##      inquire_equel(rowcount = "rowcount")
1695         if (rowcount != 1)
1696             return(SMS_MACHINE);
1697 ##      repeat replace users (#potype = "POP", pop_id = @id)
1698 ##              where users.users_id = @user
1699         set_pop_usage(id, 1);
1700     } else if (!strcmp(argv[1], "SMTP")) {
1701 ##      range of s is strings
1702 ##      repeat retrieve (id = s.string_id) where s.string = @box
1703 ##      inquire_equel (rowcount = "rowcount")
1704         if (rowcount == 0) {
1705 ##          range of v is values
1706 ##          repeat retrieve (id = v.value) where v.name = "strings_id"
1707             id++;
1708 ##          repeat replace v (value = @id) where v.name = "strings_id"
1709 ##          append to strings (string_id = id, string = box)
1710         }
1711 ##      repeat replace users (#potype = "SMTP", box_id = @id) 
1712 ##             where users.users_id = @user
1713     } else /* argv[1] == "NONE" */ {
1714 ##      repeat replace users (#potype = "NONE") where users.users_id = @user
1715     }
1716
1717     set_pobox_modtime(q, argv, cl);
1718 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1719 ##      where tblstats.#table = "users"
1720     return(SMS_SUCCESS);
1721 ##}
1722
1723
1724 /* get_list_info:  passed a wildcard list name, returns lots of stuff about
1725  * each list.  This is tricky:  first build a queue of all requested
1726  * data.  Rest of processing consists of fixing gid, ace_name, and modby.
1727  */
1728
1729 get_list_info(q, aargv, cl, action, actarg)
1730     register struct query *q;
1731     char **aargv;
1732     client *cl;
1733     register int (*action)();
1734     int actarg;
1735 ##{
1736     char *argv[13], *malloc(), *realloc();
1737 ##  char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1738 ##  char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1739 ##  char modby[256], modwith[9];
1740 ##  int id, rowcount, acl_id, hid, modby_id;
1741     int returned;
1742     struct save_queue *sq, *sq_create();
1743
1744     returned = rowcount = 0;
1745     name = aargv[0];
1746
1747     sq = sq_create();
1748 ##  range of l is list
1749 ##  repeat retrieve (id = l.list_id) where l.#name = @name {
1750         sq_save_data(sq, id);
1751         rowcount++;
1752 ##  }
1753     if (ingres_errno) return(sms_errcode);
1754     if (rowcount == 0)
1755       return(SMS_NO_MATCH);
1756
1757     argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1758     argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1759     argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1760     argv[12] = modwith;
1761
1762     while (sq_get_data(sq, &id)) {
1763         if (id == 0)
1764           continue;
1765         argv[6] = gid;
1766 ##      repeat retrieve (listname = l.#name, active = text(l.#active), 
1767 ##              public = text(l.#public), hidden = text(l.#hidden),
1768 ##              hid = l.#hidden, maillist = text(l.#maillist),
1769 ##              group = text(l.#group), gid = text(l.#gid),
1770 ##              acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1771 ##              desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1772 ##              modwith =l.#modwith)
1773 ##          where l.list_id = @id
1774         if (ingres_errno) return(sms_errcode);
1775
1776         if (atoi(gid) == -1)
1777             argv[6] = UNIQUE_GID;
1778
1779         if (!strcmp(acl_type, "LIST")) {
1780 ##          repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1781 ##          inquire_equel(rowcount = "rowcount")
1782             if (rowcount != 1)
1783                 strcpy(acl_name, "???");
1784         } else if (!strcmp(acl_type, "USER")) {
1785 ##          repeat retrieve (acl_name = users.#login)
1786 ##              where users.users_id = @acl_id
1787 ##          inquire_equel(rowcount = "rowcount")
1788             if (rowcount != 1)
1789                 strcpy(acl_name, "???");
1790         } else if (!strcmp(acl_type, "KERBEROS")) {
1791 ##          repeat retrieve (acl_name = strings.string)
1792 ##              where strings.string_id = @acl_id
1793 ##          inquire_equel(rowcount = "rowcount")
1794             if (rowcount != 1)
1795                 strcpy(acl_name, "???");
1796         } else if (!strcmp(acl_type, "NONE")) {
1797             strcpy(acl_name, "NONE");
1798         } else
1799           strcpy(acl_name, "???");
1800
1801         if (modby_id > 0)
1802 ##        repeat retrieve (modby = users.login) where users.users_id = @modby_id
1803         else {
1804             modby_id = -modby_id;
1805 ##           repeat retrieve (modby = strings.string) 
1806 ##              where strings.string_id = @modby_id
1807             modby_id = -modby_id;
1808         }
1809 ##      inquire_equel(rowcount = "rowcount")
1810         if (rowcount != 1)
1811           sprintf(modby, "#%d", modby_id);
1812         if (ingres_errno) return(sms_errcode);
1813
1814         sms_trim_args(q->vcnt, argv);
1815         returned++;
1816         (*action)(q->vcnt, argv, actarg);
1817     }
1818
1819     sq_destroy(sq);
1820 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1821 ##      where tblstats.#table = "list"
1822
1823     return (SMS_SUCCESS);
1824 ##}
1825
1826
1827 /* Add_member_to_list: do list flattening as we go!  MAXLISTDEPTH is
1828  * how many different ancestors a member is allowed to have.
1829  */
1830
1831 #define MAXLISTDEPTH    100
1832
1833 int add_member_to_list(q, argv, cl)
1834     struct query *q;
1835     char **argv;
1836     client *cl;
1837 ##{
1838 ##  int id, lid, mid, exists, error;
1839 ##  char *mtype, dtype[9];
1840     int ancestors[MAXLISTDEPTH], acount, a;
1841     int descendants[MAXLISTDEPTH], dcount, d;
1842     char *dtypes[MAXLISTDEPTH];
1843     char *iargv[3];
1844
1845 ##  range of m is imembers
1846     lid = *(int *)argv[0];
1847     mtype = argv[1];
1848     mid = *(int *)argv[2];
1849 ##  repeat retrieve (exists = any(m.list_id where m.list_id=@lid and 
1850 ##                         m.member_id = @mid and m.member_type = @mtype
1851 ##                         and m.direct = 1))
1852     if (exists)
1853       return(SMS_EXISTS);
1854     ancestors[0] = lid;
1855     acount = 1;
1856 ##  repeat retrieve (id = m.list_id)
1857 ##      where m.member_id = @lid and m.member_type = "LIST" {
1858         ancestors[acount++] = id;
1859         if (acount >= MAXLISTDEPTH) {
1860 ##          endretrieve
1861         }
1862 ##  }
1863     if (ingres_errno) return(sms_errcode);
1864     if (acount >= MAXLISTDEPTH) {
1865         return(SMS_INTERNAL);
1866     }
1867     descendants[0] = mid;
1868     dtypes[0] = mtype;
1869     dcount = 1;
1870     error = 0;
1871     if (!strcmp(mtype, "LIST")) {
1872 ##      repeat retrieve (id = m.member_id, dtype = m.member_type)
1873 ##        where m.list_id = @mid {
1874             switch (dtype[0]) {
1875             case 'L':
1876                 dtypes[dcount] = "LIST";
1877                 break;
1878             case 'U':
1879                 dtypes[dcount] = "USER";
1880                 break;
1881             case 'S':
1882                 dtypes[dcount] = "STRING";
1883                 break;
1884             case 'K':
1885                 dtypes[dcount] = "KERBEROS";
1886                 break;
1887             default:
1888                 error++;
1889 ##              endretrieve
1890             }
1891             descendants[dcount++] = id;
1892             if (dcount >= MAXLISTDEPTH) {
1893                 error++;
1894 ##              endretrieve
1895             }
1896 ##      }
1897         if (ingres_errno) return(sms_errcode);
1898         if (error)
1899           return(SMS_INTERNAL);
1900     }
1901     for (a = 0; a < acount; a++) {
1902         lid = ancestors[a];
1903         for (d = 0; d < dcount; d++) {
1904             mid = descendants[d];
1905             mtype = dtypes[d];
1906             if (mid == lid && !strcmp(mtype, "LIST")) {
1907                 return(SMS_LISTLOOP);
1908             }
1909 ##          repeat retrieve (exists = any(m.ref_count where m.list_id = @lid
1910 ##                                       and m.member_id = @mid
1911 ##                                       and m.member_type = @mtype))
1912             if (exists) {
1913                 if (a == 0 && d == 0)
1914 ##                replace m (ref_count = m.ref_count+1, direct = 1)
1915 ##                           where m.list_id = lid and m.member_id = mid and
1916 ##                           m.member_type = mtype
1917                 else
1918 ##                replace m (ref_count = m.ref_count+1)
1919 ##                           where m.list_id = lid and m.member_id = mid and
1920 ##                           m.member_type = mtype
1921             } else {
1922                 incremental_clear_before();
1923                 if (a == 0 && d == 0)
1924 ##                append imembers (list_id=lid, member_id = mid, direct = 1,
1925 ##                                 member_type=mtype, ref_count = 1)
1926                 else
1927 ##                append imembers (list_id=lid, member_id = mid,
1928 ##                                 member_type=mtype, ref_count = 1)
1929                 iargv[0] = (char *)lid;
1930                 iargv[1] = mtype;
1931                 iargv[2] = (char *)mid;
1932                 incremental_after("members", 0, iargv);
1933             }
1934         }
1935     }
1936     if (ingres_errno) return(sms_errcode);
1937     return(SMS_SUCCESS);
1938 ##}
1939
1940
1941 /* Delete_member_from_list: do list flattening as we go!
1942  */
1943
1944 int delete_member_from_list(q, argv, cl)
1945     struct query *q;
1946     char **argv;
1947     client *cl;
1948 ##{
1949 ##  int id, lid, mid, cnt, exists, error;
1950 ##  char *mtype, dtype[9];
1951     int ancestors[MAXLISTDEPTH], acount, a;
1952     int descendants[MAXLISTDEPTH], dcount, d;
1953     char *dtypes[MAXLISTDEPTH];
1954     char *iargv[3];
1955
1956 ##  range of m is imembers
1957     lid = *(int *)argv[0];
1958     mtype = argv[1];
1959     mid = *(int *)argv[2];
1960 ##  repeat retrieve (exists = any(m.list_id where m.list_id=@lid and 
1961 ##                         m.member_id = @mid and m.member_type = @mtype
1962 ##                         and m.direct = 1))
1963     if (ingres_errno) return(sms_errcode);
1964     if (!exists)
1965       return(SMS_NO_MATCH);
1966     ancestors[0] = lid;
1967     acount = 1;
1968 ##  repeat retrieve (id = m.list_id)
1969 ##      where m.member_id = @lid and m.member_type = "LIST" {
1970         ancestors[acount++] = id;
1971         if (acount >= MAXLISTDEPTH)
1972 ##        endretrieve
1973 ##  }
1974           if (ingres_errno) return(sms_errcode);
1975     if (acount >= MAXLISTDEPTH)
1976       return(SMS_INTERNAL);
1977     descendants[0] = mid;
1978     dtypes[0] = mtype;
1979     dcount = 1;
1980     error = 0;
1981     if (!strcmp(mtype, "LIST")) {
1982 ##      repeat retrieve (id = m.member_id, dtype = m.member_type)
1983 ##        where m.list_id = @mid {
1984             switch (dtype[0]) {
1985             case 'L':
1986                 dtypes[dcount] = "LIST";
1987                 break;
1988             case 'U':
1989                 dtypes[dcount] = "USER";
1990                 break;
1991             case 'S':
1992                 dtypes[dcount] = "STRING";
1993                 break;
1994             case 'K':
1995                 dtypes[dcount] = "KERBEROS";
1996                 break;
1997             default:
1998                 error++;
1999 ##              endretrieve
2000             }
2001             descendants[dcount++] = id;
2002             if (dcount >= MAXLISTDEPTH)
2003 ##            endretrieve
2004 ##      }
2005               if (ingres_errno) return(sms_errcode);
2006         if (error)
2007           return(SMS_INTERNAL);
2008     }
2009     for (a = 0; a < acount; a++) {
2010         lid = ancestors[a];
2011         for (d = 0; d < dcount; d++) {
2012             mid = descendants[d];
2013             mtype = dtypes[d];
2014             if (mid == lid && !strcmp(mtype, "LIST")) {
2015                 return(SMS_LISTLOOP);
2016             }
2017 ##          repeat retrieve (cnt = m.ref_count)
2018 ##              where m.list_id = @lid and m.member_id = @mid
2019 ##                and m.member_type = @mtype
2020             if (cnt <= 1) {
2021                 iargv[0] = (char *)lid;
2022                 iargv[1] = mtype;
2023                 iargv[2] = (char *)mid;
2024                 incremental_before("members", 0, iargv);
2025 ##              delete m where m.list_id = lid and m.member_id = mid and
2026 ##                  m.member_type = mtype
2027                 incremental_clear_after();
2028             } else if (a == 0 && d == 0) {
2029 ##              replace m (ref_count = m.ref_count-1, direct = 0)
2030 ##                  where m.list_id = lid and m.member_id = mid and
2031 ##                  m.member_type = mtype
2032             } else {
2033 ##              replace m (ref_count = m.ref_count-1)
2034 ##                  where m.list_id = lid and m.member_idn = mid and
2035 ##                  m.member_type = mtype
2036             }
2037         }
2038     }
2039     if (ingres_errno) return(sms_errcode);
2040     return(SMS_SUCCESS);
2041 ##}
2042
2043
2044 /* get_ace_use - given a type and a name, return a type and a name.
2045  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2046  * and argv[1] will contain the ID of the entity in question.  The R*
2047  * types mean to recursively look at every containing list, not just
2048  * when the object in question is a direct member.  On return, the
2049  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2050  */
2051
2052 int get_ace_use(q, argv, cl, action, actarg)
2053     struct query *q;
2054     char *argv[];
2055     client *cl;
2056     int (*action)();
2057     int actarg;
2058 ##{
2059     int found = 0;
2060 ##  char *atype;
2061 ##  int aid, listid, id;
2062     struct save_queue *sq, *sq_create();
2063
2064 ##  range of m is imembers
2065     atype = argv[0];
2066     aid = *(int *)argv[1];
2067     if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2068         !strcmp(atype, "KERBEROS")) {
2069         return(get_ace_internal(atype, aid, action, actarg));
2070     }
2071
2072     sq = sq_create();
2073     if (!strcmp(atype, "RLIST")) {
2074         sq_save_data(sq, aid);
2075         /* get all the list_id's of containing lists */
2076 ##      range of m is imembers
2077 ##      repeat retrieve (listid = m.list_id)
2078 ##              where m.member_type = "LIST" and m.member_id = @id {
2079             sq_save_unique_data(sq, listid);
2080 ##      }
2081         /* now process each one */
2082         while (sq_get_data(sq, &id)) {
2083             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
2084               found++;
2085         }
2086     }
2087
2088     if (!strcmp(atype, "RUSER")) {
2089 ##      repeat retrieve (listid = m.list_id)
2090 ##              where m.member_type = "USER" and m.member_id = @aid {
2091             sq_save_data(sq, listid);
2092 ##      }
2093         /* now process each one */
2094         while (sq_get_data(sq, &id)) {
2095             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
2096               found++;
2097         }
2098         if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
2099           found++;
2100     }
2101
2102     if (!strcmp(atype, "RKERBERO")) {
2103 ##      repeat retrieve (listid = m.list_id)
2104 ##              where m.member_type = "KERBEROS" and m.member_id = @aid {
2105             sq_save_data(sq, listid);
2106 ##      }
2107         /* now process each one */
2108         while (sq_get_data(sq, &id)) {
2109             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
2110               found++;
2111         }
2112         if (get_ace_internal("KERBEROS", aid, action, actarg) == SMS_SUCCESS)
2113           found++;
2114     }
2115
2116     sq_destroy(sq);     
2117     if (!found) return(SMS_NO_MATCH);
2118     return(SMS_SUCCESS);
2119 ##}
2120
2121
2122 /* This looks up a single list or user for ace use.  atype must be "USER"
2123  * or "LIST", and aid is the ID of the corresponding object.  This is used
2124  * by get_ace_use above.
2125  */
2126
2127 ##get_ace_internal(atype, aid, action, actarg)
2128 ##  char *atype;
2129 ##  int aid;
2130     int (*action)();
2131     int actarg;
2132 ##{
2133     char *rargv[2];
2134     int found = 0;
2135 ##  char name[33];
2136
2137     rargv[1] = name;
2138     if (!strcmp(atype, "LIST")) {
2139         rargv[0] = "FILESYS";
2140 ##      repeat retrieve (name = filesys.label) 
2141 ##              where filesys.owners = @aid {
2142             (*action)(2, rargv, actarg);
2143             found++;
2144 ##      }
2145
2146         rargv[0] = "QUERY";
2147 ##      repeat retrieve (name = capacls.capability)
2148 ##              where capacls.list_id = @aid {
2149             (*action)(2, rargv, actarg);
2150             found++;
2151 ##      }
2152     } else if (!strcmp(atype, "USER")) {
2153         rargv[0] = "FILESYS";
2154 ##      repeat retrieve (name = filesys.label) 
2155 ##              where filesys.owner = @aid {
2156             (*action)(2, rargv, actarg);
2157             found++;
2158 ##      }
2159     }
2160
2161     rargv[0] = "LIST";
2162 ##  repeat retrieve (name = list.#name) 
2163 ##              where list.acl_type = @atype and list.acl_id = @aid {
2164          (*action)(2, rargv, actarg);
2165          found++;
2166 ##  }
2167
2168     rargv[0] = "SERVICE";
2169 ##  repeat retrieve (name = servers.#name) 
2170 ##              where servers.acl_type = @atype and servers.acl_id = @aid {
2171          (*action)(2, rargv, actarg);
2172          found++;
2173 ##  }
2174
2175     rargv[0] = "HOSTACCESS";
2176 ##  repeat retrieve (name = machine.#name)
2177 ##              where machine.mach_id = hostaccess.mach_id and 
2178 ##                   hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
2179         (*action)(2, rargv, actarg);
2180         found++;
2181 ##  }
2182     rargv[0] = "ZEPHYR";
2183 ##  repeat retrieve (name = zephyr.class) 
2184 ##              where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
2185 ##                    zephyr.sub_type = @atype and zephyr.sub_id = @aid or
2186 ##                    zephyr.iws_type = @atype and zephyr.iws_id = @aid or
2187 ##                    zephyr.iui_type = @atype and zephyr.iui_id = @aid {
2188          (*action)(2, rargv, actarg);
2189          found++;
2190 ##  }
2191
2192     if (!found) return(SMS_NO_MATCH);
2193     return(SMS_SUCCESS);
2194 ##}
2195
2196
2197 /* get_lists_of_member - given a type and a name, return the name and flags
2198  * of all of the lists of the given member.  The member_type is one of
2199  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2200  * and argv[1] will contain the ID of the entity in question.  The R*
2201  * types mean to recursively look at every containing list, not just
2202  * when the object in question is a direct member.
2203  */
2204
2205 int get_lists_of_member(q, argv, cl, action, actarg)
2206     struct query *q;
2207     char *argv[];
2208     client *cl;
2209     int (*action)();
2210     int actarg;
2211 ##{
2212     int found = 0, direct = 1;
2213     char *rargv[6];
2214 ##  char *atype;
2215 ##  int aid, listid, id;
2216 ##  char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
2217
2218     atype = argv[0];
2219     aid = *(int *)argv[1];
2220     if (!strcmp(atype, "RLIST")) {
2221         atype = "LIST";
2222         direct = 0;
2223     }
2224     if (!strcmp(atype, "RUSER")) {
2225         atype = "USER";
2226         direct = 0;
2227     }
2228     if (!strcmp(atype, "RSTRING")) {
2229         atype = "STRING";
2230         direct = 0;
2231     }
2232     if (!strcmp(atype, "RKERBEROS")) {
2233         atype = "KERBEROS";
2234         direct = 0;
2235     }
2236
2237     rargv[0] = name;
2238     rargv[1] = active;
2239     rargv[2] = public;
2240     rargv[3] = hidden;
2241     rargv[4] = maillist;
2242     rargv[5] = group;
2243     if (direct) {
2244 ##    repeat retrieve (name = list.#name, active = text(list.#active), 
2245 ##                   public = text(list.#public), hidden = text(list.#hidden),
2246 ##                   maillist = text(list.#maillist), group = text(list.#group))
2247 ##              where list.list_id = m.list_id and m.direct = 1 and
2248 ##                    m.member_type = @atype and m.member_id = @aid {
2249          (*action)(6, rargv, actarg);
2250          found++;
2251 ##    }
2252     } else {
2253 ##    repeat retrieve (name = list.#name, active = text(list.#active), 
2254 ##                   public = text(list.#public), hidden = text(list.#hidden),
2255 ##                   maillist = text(list.#maillist), group = text(list.#group))
2256 ##              where list.list_id = m.list_id and
2257 ##                    m.member_type = @atype and m.member_id = @aid {
2258          (*action)(6, rargv, actarg);
2259          found++;
2260 ##    }
2261     }
2262
2263     if (!found) return(SMS_NO_MATCH);
2264     return(SMS_SUCCESS);
2265 ##}
2266
2267
2268 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2269  * the five flags associated with each list.  It will return the name of
2270  * each list that meets the quailifications.  It does this by building a
2271  * where clause based on the arguments, then doing a retrieve.
2272  */
2273
2274 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
2275
2276 int qualified_get_lists(q, argv, cl, action, actarg)
2277     struct query *q;
2278     char *argv[];
2279     client *cl;
2280     int (*action)();
2281     int actarg;
2282 {
2283     return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2284                          "l", "name", lflags));
2285 }
2286
2287
2288 /** get_members_of_list - optimized query for retrieval of list members
2289  **
2290  ** Inputs:
2291  **   argv[0] - list_id
2292  **
2293  ** Description:
2294  **   - retrieve USER members, then LIST members, then STRING members
2295  **/
2296
2297 get_members_of_list(q, argv, cl, action, actarg)
2298     struct query *q;
2299     char *argv[];
2300     client *cl;
2301     int (*action)();
2302     int actarg;
2303 ##{
2304 ##  int list_id;
2305 ##  char member_name[129];
2306     char *targv[2];
2307
2308     list_id = *(int *)argv[0];
2309     targv[0] = "USER";
2310     targv[1] = member_name;
2311
2312 ##  range of m is imembers
2313 ##  repeat retrieve (member_name = users.login)
2314 ##             where m.#list_id = @list_id and m.member_type = "USER"
2315 ##                   and m.member_id = users.users_id and m.direct = 1
2316 ##             sort by #member_name
2317 ##  {
2318          (*action)(2, targv, actarg);
2319 ##  }
2320
2321     targv[0] = "LIST";
2322 ##  repeat retrieve (member_name = list.name)
2323 ##             where m.#list_id = @list_id and m.member_type = "LIST"
2324 ##                   and m.member_id = list.#list_id and m.direct = 1
2325 ##             sort by #member_name
2326 ##  {
2327          (*action)(2, targv, actarg);
2328 ##  }
2329
2330     targv[0] = "STRING";
2331 ##  repeat retrieve (member_name = strings.string)
2332 ##             where m.#list_id = @list_id and m.member_type = "STRING"
2333 ##                   and m.member_id = strings.string_id and m.direct = 1
2334 ##             sort by #member_name
2335 ##  {
2336          (*action)(2, targv, actarg);
2337 ##  }
2338
2339     targv[0] = "KERBEROS";
2340 ##  repeat retrieve (member_name = strings.string)
2341 ##             where m.#list_id = @list_id and m.member_type = "KERBEROS"
2342 ##                   and m.member_id = strings.string_id and m.direct = 1
2343 ##             sort by #member_name
2344 ##  {
2345          (*action)(2, targv, actarg);
2346 ##  }
2347
2348     return(SMS_SUCCESS);
2349 ##}
2350
2351
2352 /* count_members_of_list: this is a simple query, but it cannot be done
2353  * through the dispatch table.
2354  */
2355
2356 int count_members_of_list(q, argv, cl, action, actarg)
2357     struct query *q;
2358     char *argv[];
2359     client *cl;
2360     int (*action)();
2361     int actarg;
2362 ##{
2363 ##  int  list, ct = 0;
2364     char *rargv[1], countbuf[5];
2365
2366     list = *(int *)argv[0];
2367     rargv[0] = countbuf;
2368 ##  repeat retrieve (ct = count(imembers.list_id
2369 ##                              where imembers.list_id = @list and
2370 ##                                    imembers.direct = 1))
2371     sprintf(countbuf, "%d", ct);
2372     (*action)(1, rargv, actarg);
2373     return(SMS_SUCCESS);
2374 ##}
2375
2376
2377 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2378  * the three flags associated with each service.  It will return the name of
2379  * each service that meets the quailifications.  It does this by building a
2380  * where clause based on the arguments, then doing a retrieve.
2381  */
2382
2383 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2384
2385 int qualified_get_server(q, argv, cl, action, actarg)
2386     struct query *q;
2387     char *argv[];
2388     client *cl;
2389     int (*action)();
2390     int actarg;
2391 {
2392     return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2393                          "s", "name", sflags));
2394 }
2395
2396
2397 /* generic qualified get routine, used by qualified_get_lists,
2398  * qualified_get_server, and qualified_get_serverhost.
2399  *   Args:
2400  *      start - a simple where clause, must not be empty
2401  *      range - the name of the range variable
2402  *      field - the field to return
2403  *      flags - an array of strings, names of the flag variables
2404  */
2405
2406 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2407     struct query *q;
2408     char *argv[];
2409     int (*action)();
2410     int actarg;
2411     char *start;
2412     char *range;
2413     char *field;
2414     char *flags[];
2415 ##{
2416 ##  char name[33], qual[256], *rvar, *rtbl, *rfield;
2417     char *rargv[1], buf[32];
2418 ##  int rowcount, i;
2419
2420     strcpy(qual, start);
2421     for (i = 0; i < q->argc; i++) {
2422         if (!strcmp(argv[i], "TRUE")) {
2423             sprintf(buf, " and %s.%s != 0", range, flags[i]);
2424             (void) strcat(qual, buf);
2425         } else if (!strcmp(argv[i], "FALSE")) {
2426             sprintf(buf, " and %s.%s = 0", range, flags[i]);
2427             (void) strcat(qual, buf);
2428         }
2429     }
2430       
2431     rargv[0] = name;
2432     rvar = range;
2433     rtbl = q->rtable;
2434     rfield = field;
2435 ##  range of rvar is rtbl
2436 ##  retrieve (name = rvar.rfield) where qual {
2437         (*action)(1, rargv, actarg);
2438 ##  }
2439 ##  inquire_equel(rowcount = "rowcount")
2440 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2441 ##      where tblstats.#table = @rtbl
2442     if (rowcount == 0)
2443       return(SMS_NO_MATCH);
2444     return(SMS_SUCCESS);
2445 ##}
2446
2447
2448 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2449  * the five flags associated with each serverhost.  It will return the name of
2450  * each service and host that meets the quailifications.  It does this by 
2451  * building a where clause based on the arguments, then doing a retrieve.
2452  */
2453
2454 static char *shflags[6] = { "service", "enable", "override", "success",
2455                             "inprogress", "hosterror" };
2456
2457 int qualified_get_serverhost(q, argv, cl, action, actarg)
2458     struct query *q;
2459     char *argv[];
2460     client *cl;
2461     int (*action)();
2462     int actarg;
2463 ##{
2464 ##  char sname[33], mname[33], qual[256];
2465     char *rargv[2], buf[32];
2466 ##  int rowcount, i;
2467
2468     sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2469             argv[0]);
2470     for (i = 1; i < q->argc; i++) {
2471         if (!strcmp(argv[i], "TRUE")) {
2472             sprintf(buf, " and sh.%s != 0", shflags[i]);
2473             strcat(qual, buf);
2474         } else if (!strcmp(argv[i], "FALSE")) {
2475             sprintf(buf, " and sh.%s = 0", shflags[i]);
2476             strcat(qual, buf);
2477         }
2478     }
2479       
2480     rargv[0] = sname;
2481     rargv[1] = mname;
2482 ##  range of sh is serverhosts
2483 ##  retrieve (sname = sh.service, mname = machine.name) where qual {
2484         (*action)(2, rargv, actarg);
2485 ##  }
2486 ##  inquire_equel(rowcount = "rowcount")
2487 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2488 ##      where tblstats.#table = "serverhosts"
2489     if (rowcount == 0)
2490       return(SMS_NO_MATCH);
2491     return(SMS_SUCCESS);
2492 ##}
2493
2494
2495 /* register_user - change user's login name and allocate a pobox, group,
2496  * filesystem, and quota for them.  The user's status must start out as 0,
2497  * and is left as 2.  Arguments are: user's UID, new login name, and user's
2498  * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY, 
2499  * SMS_FS_STAFF, SMS_FS_MISC).
2500  */
2501
2502 register_user(q, argv, cl)
2503     struct query *q;
2504     char **argv;
2505     client *cl;
2506 ##{
2507 ##  char *login, dir[65], *entity, *directory, machname[33];
2508 ##  int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2509 ##  int size, alloc, pid, m_id;
2510     char buffer[256], *aargv[3];
2511     int maxsize;
2512
2513     entity = cl->entity;
2514     who = cl->client_id;
2515
2516     uid = atoi(argv[0]);
2517     login = argv[1];
2518     utype = atoi(argv[2]);
2519
2520 ##  range of u is users
2521 ##  range of l is list
2522 ##  range of sh is serverhosts
2523 ##  range of n is nfsphys
2524 ##  range of m is machine
2525
2526     /* find user */
2527 ##  repeat retrieve (users_id = u.#users_id)
2528 ##      where u.#uid = @uid and (u.status = 0 or u.status = 5)
2529 ##  inquire_equel(rowcount = "rowcount");
2530     if (rowcount == 0)
2531       return(SMS_NO_MATCH);
2532     if (rowcount > 1)
2533       return(SMS_NOT_UNIQUE);
2534
2535     /* check new login name */
2536 ##  repeat retrieve (flag = any(u.#login where u.#login = @login and
2537 ##                              u.#users_id != users_id))
2538     if (ingres_errno) return(sms_errcode);
2539     if (flag) return(SMS_IN_USE);
2540 ##  repeat retrieve (flag = any(l.#name where l.#name = @login))
2541     if (ingres_errno) return(sms_errcode);
2542     if (flag) return(SMS_IN_USE);
2543 ##  repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2544     if (ingres_errno) return(sms_errcode);
2545     if (flag) return(SMS_IN_USE);
2546     com_err(whoami, 0, "new login name OK");
2547
2548     /* choose place for pobox, put in mid */
2549 ##  repeat retrieve (mid = sh.mach_id, machname = m.name)
2550 ##    where sh.service = "POP" and m.mach_id = sh.mach_id and
2551 ##      sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2552 ##  inquire_equel(rowcount = "rowcount");
2553     if (rowcount == 0)
2554       return(SMS_NO_POBOX);
2555
2556     /* change login name, set pobox */
2557     sprintf(buffer, "u.users_id = %d", users_id);
2558     incremental_before("users", buffer, 0);
2559 ##  repeat replace u (#login = @login, status = 2, modtime = "now",
2560 ##                    modby = @who, modwith = @entity, potype="POP",
2561 ##                    pop_id = @mid, pmodtime="now", pmodby=@who,
2562 ##                    pmodwith=@entity)
2563 ##      where u.#users_id = @users_id
2564 ##  inquire_equel(rowcount = "rowcount");
2565     if (rowcount != 1)
2566       return(SMS_INTERNAL);
2567     set_pop_usage(mid, 1);
2568     com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2569             strtrim(machname));
2570     incremental_after("users", buffer, 0);
2571
2572     /* create group list */
2573     if (set_next_object_id("gid", "list"))
2574       return(SMS_NO_ID);
2575     if (set_next_object_id("list_id", "list"))
2576       return(SMS_NO_ID);
2577 ##  repeat retrieve (list_id = values.value) where values.name = "list_id"
2578 ##  inquire_equel(rowcount = "rowcount");
2579     if (rowcount != 1)
2580       return(SMS_INTERNAL);
2581     incremental_clear_before();
2582 ##  repeat append list (name = @login, #list_id = @list_id, active = 1,
2583 ##                      public = 0, hidden = 0, maillist = 0, group = 1,
2584 ##                      #gid = values.value, desc = "User Group",
2585 ##                      acl_type = "USER", acl_id = @users_id, modtime = "now",
2586 ##                      modby = @who, modwith = @entity)
2587 ##      where values.name = "gid"
2588 ##  inquire_equel(rowcount = "rowcount");
2589     if (rowcount != 1)
2590       return(SMS_INTERNAL);
2591     sprintf(buffer, "l.list_id = %d", list_id);
2592     incremental_after("list", buffer, 0);
2593     aargv[0] = (char *) list_id;
2594     aargv[1] = "USER";
2595     aargv[2] = (char *) users_id;
2596     incremental_clear_before();
2597 ##  repeat append imembers (#list_id = @list_id, member_type = "USER",
2598 ##                         member_id = @users_id, ref_count = 1, direct = 1)
2599 ##  inquire_equel(rowcount = "rowcount");
2600     if (rowcount != 1)
2601       return(SMS_INTERNAL);
2602     incremental_after("members", 0, argv);
2603     com_err(whoami, 0, "group list created");
2604
2605     /* decide where to put filesystem */
2606     maxsize = 0;
2607     directory = NULL;
2608 ##  repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2609 ##                   flag = n.status, size = n.#size, alloc = n.allocated) {
2610         if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2611             maxsize = size - alloc;
2612             if (directory)
2613               free(directory);
2614             directory = strsave(dir);
2615             pid = nid;
2616             m_id = mid;
2617         }
2618 ##  }
2619     if (maxsize == 0)
2620       return(SMS_NO_FILESYS);
2621
2622     /* create filesystem */
2623     if (set_next_object_id("filsys_id", "filesys"))
2624       return(SMS_NO_ID);
2625     incremental_clear_before(); 
2626 ##  repeat append filesys (filsys_id = values.value, phys_id = @pid,
2627 ##                         label = @login, type = "NFS", mach_id = @m_id,
2628 ##                         name = @directory + "/" + @login,
2629 ##                         mount = "/mit/" + @login,
2630 ##                         access = "w", comments = "User Locker",
2631 ##                         owner = @users_id, owners = @list_id, createflg = 1,
2632 ##                         lockertype = "HOMEDIR", modtime = "now",
2633 ##                         modby = @who, modwith = @entity)
2634 ##      where values.name = "filsys_id"
2635 ##  inquire_equel(rowcount = "rowcount");
2636     if (rowcount != 1)
2637       return(SMS_INTERNAL);
2638     incremental_after("filesys", 
2639           "fs.filsys_id = values.value and values.name = \"filsys_id\"",
2640                       0);
2641     com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2642             directory, login);
2643
2644     /* set quota */
2645 ##  repeat retrieve (quota = values.value) where values.name = "def_quota"
2646 ##  inquire_equel(rowcount = "rowcount");
2647     if (rowcount != 1)
2648       return(SMS_NO_QUOTA);
2649     incremental_clear_before();
2650 ##  repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2651 ##                          #quota = @quota, phys_id = @pid, modtime = "now",
2652 ##                          modby = @who, modwith = @entity)
2653 ##      where values.name = "filsys_id"
2654 ##  inquire_equel(rowcount = "rowcount");
2655     if (rowcount != 1)
2656       return(SMS_INTERNAL);
2657 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2658 ##      where nfsphys.nfsphys_id = filesys.#phys_id and
2659 ##            filesys.filsys_id = values.value and values.name = "filsys_id"
2660 ##  inquire_equel(rowcount = "rowcount");
2661     if (rowcount != 1)
2662       return(SMS_INTERNAL);
2663     aargv[0] = login;
2664     aargv[1] = login;
2665     sprintf(buffer, "nq.users_id = %d and nq.filsys_id = values.value and values.name = \"filsys_id\"", users_id);
2666     incremental_after("nfsquota", buffer, argv);
2667     com_err(whoami, 0, "quota of %d assigned", quota);
2668
2669 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2670 ##      where tblstats.table = "users"
2671 ##  repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2672 ##      where tblstats.table = "list" or tblstats.table = "filesys" or
2673 ##            tblstats.table = "nfsquota"
2674     return(SMS_SUCCESS);
2675 ##}
2676
2677
2678
2679 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2680  **
2681  ** Inputs:
2682  **   id of machine
2683  **   delta (will be +/- 1)
2684  **
2685  ** Description:
2686  **   - incr/decr value field in serverhosts table for pop/mach_id
2687  **
2688  **/
2689
2690 static int set_pop_usage(id, count)
2691 int id;
2692 int count;
2693 ##{
2694 ##  int mach_id = id;
2695 ##  int n = count;
2696
2697 ##  range of sh is serverhosts
2698 ##  repeat replace sh (value1 = sh.value1 + @n)
2699 ##         where sh.service = "POP" and sh.#mach_id = @mach_id
2700
2701     return(SMS_SUCCESS);
2702 ##}
2703
2704
2705 \f
2706 /* Validation Routines */
2707
2708 validate_row(q, argv, v)
2709     register struct query *q;
2710     char *argv[];
2711     register struct validate *v;
2712 ##{
2713 ##  char *rvar;
2714 ##  char *table;
2715 ##  char *name;
2716 ##  char qual[128];
2717 ##  int rowcount;
2718
2719     /* build where clause */
2720     build_qual(v->qual, v->argc, argv, qual);
2721
2722     /* setup ingres variables */
2723     rvar = q->rvar;
2724     table = q->rtable;
2725     name = v->field;
2726
2727     if (log_flags & LOG_VALID)
2728         /* tell the logfile what we're doing */
2729         com_err(whoami, 0, "validating row: %s", qual);
2730     
2731     /* look for the record */
2732 ##  range of rvar is table
2733 ##  retrieve (rowcount = count(rvar.name where qual))
2734     if (ingres_errno) return(sms_errcode);
2735     if (rowcount == 0) return(SMS_NO_MATCH);
2736     if (rowcount > 1) return(SMS_NOT_UNIQUE);
2737     return(SMS_EXISTS);
2738 ##}
2739
2740 validate_fields(q, argv, vo, n)
2741     struct query *q;
2742     register char *argv[];
2743     register struct valobj *vo;
2744     register int n;
2745 {
2746     register int status;
2747
2748     while (--n >= 0) {
2749         switch (vo->type) {
2750         case V_NAME:
2751             if (log_flags & LOG_VALID)
2752                 com_err(whoami, 0, "validating %s in %s: %s", 
2753                     vo->namefield, vo->table, argv[vo->index]);
2754             status = validate_name(argv, vo);
2755             break;
2756
2757         case V_ID:
2758             if (log_flags & LOG_VALID)
2759                 com_err(whoami, 0, "validating %s in %s: %s", 
2760                     vo->idfield, vo->table, argv[vo->index]);
2761             status = validate_id(argv, vo);
2762             break;
2763
2764         case V_DATE:
2765             if (log_flags & LOG_VALID)
2766                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2767             status = validate_date(argv, vo);
2768             break;
2769
2770         case V_TYPE:
2771             if (log_flags & LOG_VALID)
2772                 com_err(whoami, 0, "validating %s type: %s",
2773                     vo->table, argv[vo->index]);
2774             status = validate_type(argv, vo);
2775             break;
2776
2777         case V_TYPEDATA:
2778             if (log_flags & LOG_VALID)
2779                 com_err(whoami, 0, "validating typed data (%s): %s",
2780                     argv[vo->index - 1], argv[vo->index]);
2781             status = validate_typedata(q, argv, vo);
2782             break;
2783
2784         case V_RENAME:
2785             if (log_flags & LOG_VALID)
2786                 com_err(whoami, 0, "validating rename %s in %s",
2787                         argv[vo->index], vo->table);
2788             status = validate_rename(argv, vo);
2789             break;
2790
2791         case V_CHAR:
2792             if (log_flags & LOG_VALID)
2793               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2794             status = validate_chars(argv[vo->index]);
2795             break;
2796
2797         case V_SORT:
2798             status = SMS_EXISTS;
2799             break;
2800
2801         case V_LOCK:
2802             status = lock_table(vo);
2803             break;
2804         }
2805
2806         if (status != SMS_EXISTS) return(status);
2807         vo++;
2808     }
2809
2810     return(SMS_SUCCESS);
2811 }
2812
2813
2814 /* validate_chars: verify that there are no illegal characters in
2815  * the string.  Legal characters are printing chars other than 
2816  * ", *, ?, \, [ and ].
2817  */
2818 static int illegalchars[] = {
2819     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2820     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2821     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2822     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2823     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2824     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2825     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2826     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2827     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2828     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2829     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2830     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2831     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2832     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2833     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2834     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2835 };
2836
2837 validate_chars(s)
2838 register char *s;
2839 {
2840     while (*s)
2841       if (illegalchars[*s++])
2842         return(SMS_BAD_CHAR);
2843     return(SMS_EXISTS);
2844 }
2845
2846
2847 validate_id(argv, vo)
2848     char *argv[];
2849     register struct valobj *vo;
2850 ##{
2851 ##  char *name;
2852 ##  char *table;
2853 ##  char *namefield;
2854 ##  char *idfield;
2855 ##  int id;
2856 ##  int rowcount;
2857     register char *c;
2858
2859     name = argv[vo->index];
2860     table = vo->table;
2861     /* minor kludge to upcasify machine names */
2862     if (!strcmp(table, "machine"))
2863         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2864     namefield = vo->namefield;
2865     idfield = vo->idfield;
2866     if (!strcmp(namefield, "uid")) {
2867 ##    retrieve (id = table.idfield) where table.namefield = int4(name)
2868       if (ingres_errno) return(sms_errcode);
2869 ##    inquire_equel (rowcount = "rowcount")
2870     } else {
2871 ##    retrieve (id = table.idfield) where table.namefield = name
2872       if (ingres_errno) return(sms_errcode);
2873 ##    inquire_equel (rowcount = "rowcount")
2874     }
2875     if (rowcount != 1) return(vo->error);
2876     *(int *)argv[vo->index] = id;
2877     return(SMS_EXISTS);
2878 ##}
2879
2880 validate_name(argv, vo)
2881     char *argv[];
2882     register struct valobj *vo;
2883 ##{
2884 ##  char *name;
2885 ##  char *table;
2886 ##  char *namefield;
2887 ##  int rowcount;
2888     register char *c;
2889
2890     name = argv[vo->index];
2891     table = vo->table;
2892     namefield = vo->namefield;
2893     if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2894         for (c = name; *c; c++)
2895           if (islower(*c))
2896             *c = toupper(*c);
2897     }
2898 ##  retrieve (rowcount = countu(table.namefield 
2899 ##            where table.namefield = name))
2900     if (ingres_errno) return(sms_errcode);
2901     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2902 ##}
2903
2904 validate_date(argv, vo)
2905     char *argv[];
2906     struct valobj *vo;
2907 ##{
2908 ##  char *idate;
2909 ##  double dd;
2910 ##  int errorno;
2911
2912     idate = argv[vo->index];
2913
2914 ##  retrieve (dd = interval("years", date(idate) - date("today")))
2915 ##  inquire_equel (errorno = "errorno")
2916     if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2917     return(SMS_EXISTS);
2918 ##}
2919
2920
2921 validate_rename(argv, vo)
2922 char *argv[];
2923 struct valobj *vo;
2924 ##{
2925 ##  char *name, *table, *namefield, *idfield;
2926 ##  int id;
2927     register char *c;
2928
2929     c = name = argv[vo->index];
2930     while (*c)
2931       if (illegalchars[*c++])
2932         return(SMS_BAD_CHAR);
2933     table = vo->table;
2934     /* minor kludge to upcasify machine names */
2935     if (!strcmp(table, "machine"))
2936         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2937     namefield = vo->namefield;
2938     idfield = vo->idfield;
2939     id = -1;
2940     if (idfield == 0) {
2941         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2942           return(SMS_EXISTS);
2943 ##      retrieve (id = any(table.namefield where table.namefield = name))
2944         if (ingres_errno) return(sms_errcode);
2945         if (id)
2946           return(vo->error);
2947         else
2948           return(SMS_EXISTS);
2949     }
2950 ##  retrieve (id = table.idfield) where table.namefield = name
2951     if (ingres_errno) return(sms_errcode);
2952     if (id == -1 || id == *(int *)argv[vo->index - 1])
2953       return(SMS_EXISTS);
2954     else
2955       return(vo->error);
2956 ##}
2957
2958
2959 validate_type(argv, vo)
2960     char *argv[];
2961     register struct valobj *vo;
2962 ##{
2963 ##  char *typename;
2964 ##  char *value;
2965 ##  int exists;
2966     register char *c;
2967
2968     typename = vo->table;
2969     c = value = argv[vo->index];
2970     while (*c)
2971       if (illegalchars[*c++])
2972         return(SMS_BAD_CHAR);
2973
2974     /* uppercase type fields */
2975     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2976
2977 ##  range of a is alias
2978 ##  repeat retrieve (exists = any(a.trans where a.name = @typename and
2979 ##                                    a.type = "TYPE" and
2980 ##                                    a.trans = @value))
2981     if (ingres_errno) return(sms_errcode);
2982     return (exists ? SMS_EXISTS : vo->error);
2983 ##}
2984
2985 /* validate member or type-specific data field */
2986
2987 validate_typedata(q, argv, vo)
2988     register struct query *q;
2989     register char *argv[];
2990     register struct valobj *vo;
2991 ##{
2992 ##  char *name;
2993 ##  char *field_type;
2994 ##  char data_type[129];
2995 ##  int id;
2996 ##  int rowcount;
2997     char *index();
2998     register char *c;
2999
3000     /* get named object */
3001     name = argv[vo->index];
3002
3003     /* get field type string (known to be at index-1) */
3004     field_type = argv[vo->index-1];
3005
3006     /* get corresponding data type associated with field type name */
3007 ##  repeat retrieve (data_type = alias.trans) 
3008 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
3009     if (ingres_errno) return(sms_errcode);
3010 ##  inquire_equel (rowcount = "rowcount")
3011     if (rowcount != 1) return(SMS_TYPE);
3012
3013     /* now retrieve the record id corresponding to the named object */
3014     if (index(data_type, ' '))
3015         *index(data_type, ' ') = 0;
3016     if (!strcmp(data_type, "user")) {
3017         /* USER */
3018 ##      repeat retrieve (id = users.users_id) where users.login = @name
3019 ##      inquire_equel (rowcount = "rowcount")
3020         if (rowcount != 1) return(SMS_USER);
3021
3022     } else if (!strcmp(data_type, "list")) {
3023         /* LIST */
3024 ##      repeat retrieve (id = list.list_id) where list.#name = @name
3025 ##      inquire_equel (rowcount = "rowcount")
3026         if (rowcount != 1) {
3027             /* if idfield is non-zero, then if argv[0] matches the string
3028              * that we're trying to resolve, we should get the value of
3029              * values.[idfield] for the id.
3030              */
3031             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3032                 set_next_object_id(q->validate->object_id, q->rtable);
3033                 name = vo->idfield;
3034 ##              repeat retrieve (id = values.value) where values.#name = @name
3035 ##              inquire_equel(rowcount = "rowcount")
3036                 if (rowcount != 1) return(SMS_LIST);
3037             } else
3038               return(SMS_LIST);
3039         }
3040     } else if (!strcmp(data_type, "machine")) {
3041         /* MACHINE */
3042         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3043 ##      repeat retrieve (id = machine.mach_id) where machine.#name = @name
3044 ##      inquire_equel (rowcount = "rowcount")
3045         if (rowcount != 1) return(SMS_MACHINE);
3046
3047     } else if (!strcmp(data_type, "string")) {
3048         /* STRING */
3049 ##      range of s is strings
3050 ##      repeat retrieve (id = s.string_id) where s.string = @name
3051 ##      inquire_equel (rowcount = "rowcount")
3052         if (rowcount == 0) {
3053             if (q->type != APPEND) return(SMS_STRING);
3054 ##          range of v is values
3055 ##          retrieve (id = v.value) where v.#name = "strings_id"
3056             id++;
3057 ##          replace v (value = id) where v.#name = "strings_id"
3058 ##          append to strings (string_id = id, string = name)
3059         }
3060     } else if (!strcmp(data_type, "none")) {
3061         id = 0;
3062     } else {
3063         return(SMS_TYPE);
3064     }
3065
3066     /* now set value in argv */
3067     *(int *)argv[vo->index] = id;
3068     
3069     return (SMS_EXISTS);
3070 ##}
3071
3072
3073 /* Lock the table named by the validation object */
3074
3075 lock_table(vo)
3076 struct valobj *vo;
3077 ##{
3078 ##  char *table, *idfield;
3079 ##  int rowcount;
3080
3081     table = vo->table;
3082     idfield = vo->idfield;
3083 ##  replace table (modtime = "now") where table.idfield = 0
3084     if (ingres_errno) return(sms_errcode);
3085 ##  inquire_equel (rowcount = "rowcount")
3086     if (rowcount != 1)
3087       return(vo->error);
3088     else
3089       return(SMS_EXISTS);
3090 ##}
3091
3092
3093 /* Check the database at startup time.  For now this just resets the
3094  * inprogress flags that the DCM uses.
3095  */
3096
3097 sanity_check_database()
3098 ##{
3099 ##}
This page took 0.273927 seconds and 5 git commands to generate.