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