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