]> andersk Git - moira.git/blob - server/qsupport.qc
increase size of filesys pathname
[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[81];
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 /* setup_sshi: don't exclusive lock the machine table during
804  * set_server_host_internal.
805  */
806
807 setup_sshi(q, argv, cl)
808     struct query  *q;
809     char **argv;
810     client *cl;
811 ##{
812 ##  set lockmode session where readlock = system
813 ##}
814
815
816 \f
817 /* FOLLOWUP ROUTINES */
818
819 /* generic set_modtime routine.  This takes the table name from the query,
820  * and will update the modtime, modby, and modwho fields in the entry in
821  * the table whose name field matches argv[0].
822  */
823
824 set_modtime(q, argv, cl)
825     struct query *q;
826     char *argv[];
827     client *cl;
828 ##{
829 ##  char *name, *entity, *table;
830 ##  int who;
831
832     entity = cl->entity;
833     who = cl->users_id;
834     table = q->rtable;
835     name = argv[0];
836
837 ##  replace table (modtime = "now", modby = who, modwith = entity)
838 ##       where table.#name = name
839     return(SMS_SUCCESS);
840 ##}
841
842 /* generic set_modtime_by_id routine.  This takes the table name from
843  * the query, and the id name from the validate record,
844  * and will update the modtime, modby, and modwho fields in the entry in
845  * the table whose id matches argv[0].
846  */
847
848 set_modtime_by_id(q, argv, cl)
849     struct query *q;
850     char **argv;
851     client *cl;
852 ##{
853 ##  char *entity, *table, *id_name;
854 ##  int who, id;
855
856     entity = cl->entity;
857     who = cl->users_id;
858     table = q->rtable;
859     id_name = q->validate->object_id;
860
861     id = *(int *)argv[0];
862 ##  replace table (modtime = "now", modby = who, modwith = entity)
863 ##       where table.id_name = id
864     return(SMS_SUCCESS);
865 ##}
866
867
868 /* Sets the finger modtime on a user record.  The users_id will be in argv[0].
869  */
870
871 set_finger_modtime(q, argv, cl)
872     struct query *q;
873     char *argv[];
874     client *cl;
875 ##{
876 ##  int users_id, who;
877 ##  char *entity;
878
879     entity = cl->entity;
880     who = cl->users_id;
881     users_id = *(int *)argv[0];
882
883 ##  repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
884 ##       where u.#users_id = @users_id
885     return(SMS_SUCCESS);
886 ##}
887
888
889 /* Sets the pobox modtime on a user record.  The users_id will be in argv[0].
890  */
891
892 set_pobox_modtime(q, argv, cl)
893     struct query *q;
894     char **argv;
895     client *cl;
896 ##{
897 ##  int users_id, who;
898 ##  char *entity;
899
900     entity = cl->entity;
901     who = cl->users_id;
902     users_id = *(int *)argv[0];
903
904 ##  repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
905 ##       where users.#users_id = @users_id
906     return(SMS_SUCCESS);
907 ##}
908
909
910 /* Like set_modtime, but uppercases the name first.
911  */
912
913 set_uppercase_modtime(q, argv, cl)
914     struct query *q;
915     char **argv;
916     client *cl;
917 ##{
918 ##  char *name, *entity, *table;
919 ##  int who;
920
921     entity = cl->entity;
922     who = cl->users_id;
923     table = q->rtable;
924     name = argv[0];
925
926 ##  replace table (modtime = "now", modby = who, modwith = entity)
927 ##       where table.#name = uppercase(name)
928     return(SMS_SUCCESS);
929 ##}
930
931
932 /* Sets the modtime on the machine whose mach_id is in argv[0].  This routine
933  * is necessary for add_machine_to_cluster becuase the table that query
934  * operates on is "mcm", not "machine".
935  */
936
937 set_mach_modtime_by_id(q, argv, cl)
938     struct query *q;
939     char **argv;
940     client *cl;
941 ##{
942 ##  char *entity;
943 ##  int who, id;
944
945     entity = cl->entity;
946     who = cl->users_id;
947
948     id = *(int *)argv[0];
949 ##  range of m is machine
950 ##  repeat replace m (modtime = "now", modby = @who, modwith = @entity)
951 ##       where m.mach_id = @id
952     return(SMS_SUCCESS);
953 ##}
954
955
956 /* Sets the modtime on the cluster whose mach_id is in argv[0].  This routine
957  * is necessary for add_cluster_data and delete_cluster_data becuase the
958  * table that query operates on is "svc", not "cluster".
959  */
960
961 set_cluster_modtime_by_id(q, argv, cl)
962     struct query *q;
963     char **argv;
964     client *cl;
965 ##{
966 ##  char *entity;
967 ##  int who, id;
968
969     entity = cl->entity;
970     who = cl->users_id;
971
972     id = *(int *)argv[0];
973 ##  range of c is cluster
974 ##  repeat replace c (modtime = "now", modby = @who, modwith = @entity)
975 ##       where c.clu_id = @id
976     return(SMS_SUCCESS);
977 ##}
978
979
980 /* sets the modtime on the serverhost where the service name is in argv[0]
981  * and the mach_id is in argv[1].
982  */
983
984 set_serverhost_modtime(q, argv, cl)
985     struct query *q;
986     char **argv;
987     client *cl;
988 ##{
989 ##  char *entity, *serv;
990 ##  int who, id;
991
992     entity = cl->entity;
993     who = cl->users_id;
994
995     serv = argv[0];
996     id = *(int *)argv[1];
997 ##  repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
998 ##       where sh.service = uppercase(@serv) and sh.mach_id = @id
999     return(SMS_SUCCESS);
1000 ##}
1001
1002
1003 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1004  * directory name is in argv[1].
1005  */
1006
1007 set_nfsphys_modtime(q, argv, cl)
1008     struct query *q;
1009     char **argv;
1010     client *cl;
1011 ##{
1012 ##  char *entity, *dir;
1013 ##  int who, id;
1014
1015     entity = cl->entity;
1016     who = cl->users_id;
1017
1018     id = *(int *)argv[0];
1019     dir = argv[1];
1020 ##  repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1021 ##       where np.#dir = @dir and np.mach_id = @id
1022     return(SMS_SUCCESS);
1023 ##}
1024
1025
1026 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1027  * label.
1028  */
1029
1030 set_filesys_modtime(q, argv, cl)
1031     struct query *q;
1032     char *argv[];
1033     client *cl;
1034 ##{
1035 ##  char *label, *entity;
1036 ##  int who;
1037
1038     entity = cl->entity;
1039     who = cl->users_id;
1040
1041     label = argv[0];
1042     if (!strcmp(q->shortname, "ufil"))
1043       label = argv[1];
1044
1045 ##  repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1046 ##                     #phys_id = @var_phys_id)  where fs.#label = @label
1047     return(SMS_SUCCESS);
1048 ##}
1049
1050
1051 /* sets the modtime on a zephyr class, where argv[0] contains the class
1052  * name.
1053  */
1054
1055 set_zephyr_modtime(q, argv, cl)
1056     struct query *q;
1057     char *argv[];
1058     client *cl;
1059 ##{
1060 ##  char *class, *entity;
1061 ##  int who;
1062
1063     entity = cl->entity;
1064     who = cl->users_id;
1065
1066     class = argv[0];
1067
1068 ##  repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1069 ##                     where z.#class = @class
1070     return(SMS_SUCCESS);
1071 ##}
1072
1073
1074 /* fixes the modby field.  This will be the second to last thing in the
1075  * argv, the argv length is determined from the query structure.  It is
1076  * passed as a pointer to an integer.  This will either turn it into a
1077  * username, or # + the users_id.
1078  */
1079 followup_fix_modby(q, sq, v, action, actarg, cl)
1080     struct query *q;
1081     register struct save_queue *sq;
1082     struct validate *v;
1083     register int (*action)();
1084     register int actarg;
1085     client *cl;
1086 ##{
1087     register int i, j;
1088     char **argv, *malloc();
1089 ##  int id, rowcount;
1090 ##  char *name;
1091
1092     i = q->vcnt - 2;
1093     while (sq_get_data(sq, &argv)) {
1094         id = atoi(argv[i]);
1095         free(argv[i]);
1096         argv[i] = malloc(9);
1097         name = argv[i];
1098 ##      repeat retrieve (name = users.login) where users.users_id = @id
1099 ##      inquire_equel(rowcount = "rowcount")
1100         if (rowcount != 1) {
1101             sprintf(argv[i], "#%d", id);
1102         }
1103         (*action)(q->vcnt, argv, actarg);
1104         for (j = 0; j < q->vcnt; j++)
1105           free(argv[j]);
1106         free(argv);
1107     }
1108     sq_destroy(sq);
1109     return(SMS_SUCCESS);
1110 ##}
1111
1112
1113 /**
1114  ** followup_ausr - add finger and pobox entries, set_user_modtime
1115  **
1116  ** Inputs:
1117  **     argv[0] - login (add_user)
1118  **     argv[3] - last name
1119  **     argv[4] - first name
1120  **     argv[5] - middle name
1121  **
1122  **/
1123
1124 followup_ausr(q, argv, cl)
1125     struct query *q;
1126     char *argv[];
1127     client *cl;
1128 ##{
1129 ##  int who;
1130 ##  char *login, *entity;
1131 ##  char fullname[129];
1132
1133     login = argv[0];
1134     who = cl->users_id;
1135     entity = cl->entity;
1136
1137     /* build fullname */
1138     if (strlen(argv[4]) && strlen(argv[5]))
1139         sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1140     else if (strlen(argv[4]))
1141         sprintf(fullname, "%s %s", argv[4], argv[3]);
1142     else
1143         sprintf(fullname, "%s", argv[3]);
1144
1145     /* create finger entry, pobox & set modtime on user */
1146 ##  repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1147 ##           #fullname=@fullname, mit_affil = u.mit_year,
1148 ##           fmodtime="now", fmodby=@who, fmodwith=@entity,
1149 ##           potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1150 ##      where u.#login = @login
1151
1152     return(SMS_SUCCESS);
1153 ##}
1154
1155
1156 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1157  * type in argv[1].  Then completes the upcall to the user.
1158  *
1159  * argv[2] is of the form "123:234" where the first integer is the machine
1160  * ID if it is a pop box, and the second is the string ID if it is an SMTP
1161  * box.  argv[1] should be "POP", "SMTP", or "NONE".  Boxes of type NONE
1162  * are skipped.
1163  */
1164
1165 followup_gpob(q, sq, v, action, actarg, cl)
1166     register struct query *q;
1167     register struct save_queue *sq;
1168     register struct validate *v;
1169     register int (*action)();
1170     int actarg;
1171     client *cl;
1172 ##{
1173     char **argv, *index();
1174     char *ptype, *p;
1175 ##  char box[129], *name;
1176 ##  int mid, sid, rowcount;
1177
1178     /* for each row */
1179     while (sq_get_data(sq, &argv)) {
1180         sms_trim_args(2, argv);
1181         ptype = argv[1];
1182         p = index(argv[2], ':');
1183         *p++ = 0;
1184         mid = atoi(argv[2]);
1185         sid = atoi(p);
1186         free(argv[2]);
1187
1188         if (!strcmp(ptype, "POP")) {
1189 ##          repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1190 ##          inquire_equel(rowcount = "rowcount")
1191             if (rowcount != 1)
1192               return(SMS_MACHINE);
1193         } else if (!strcmp(ptype, "SMTP")) {
1194 ##          repeat retrieve (box=strings.string) where strings.string_id=@sid
1195 ##          inquire_equel(rowcount = "rowcount")
1196             if (rowcount != 1)
1197               return(SMS_STRING);
1198         } else /* ptype == "NONE" */ {
1199             goto skip;
1200         }
1201
1202         if (!strcmp(q->shortname, "gpob")) {
1203             sid = atoi(argv[4]);
1204             free(argv[4]);
1205             argv[4] = malloc(9);
1206             name = argv[4];
1207 ##          repeat retrieve (name = users.login) where users.users_id = @sid
1208 ##          inquire_equel(rowcount = "rowcount")
1209             if (rowcount != 1)
1210               sprintf(name, "#%d", sid);
1211         }
1212
1213         argv[2] = box;
1214         (*action)(q->vcnt, argv, actarg);
1215     skip:
1216         /* free saved data */
1217         free(argv[0]);
1218         free(argv[1]);
1219         free(argv);
1220     }
1221
1222     sq_destroy(sq);
1223     return (SMS_SUCCESS);
1224 ##}
1225
1226
1227 /* followup_glin: fix the ace_name in argv[8].  argv[7] will contain the
1228  * ace_type: "LIST", "USER", or "NONE".  Decode the id in argv[8] into the
1229  * proper name based on the type, and repace that string in the argv.
1230  * Also fixes the modby field by called followup_fix_modby.
1231  */
1232
1233 followup_glin(q, sq, v, action, actarg, cl)
1234     register struct query *q;
1235     register struct save_queue *sq;
1236     register struct validate *v;
1237     register int (*action)();
1238     int actarg;
1239     client *cl;
1240 ##{
1241     char **argv, *malloc(), *realloc(), *type;
1242 ##  char *name;
1243 ##  int id, rowcount;
1244     int i, idx;
1245
1246     idx = 8;
1247     if (!strcmp(q->shortname, "gsin"))
1248       idx = 12;
1249
1250     while (sq_get_data(sq, &argv)) {
1251         sms_trim_args(q->vcnt, argv);
1252
1253         id = atoi(argv[i = q->vcnt - 2]);
1254         free(argv[i]);
1255         name = argv[i] = malloc(9);
1256 ##      repeat retrieve (name = users.login) where users.users_id = @id
1257 ##      inquire_equel(rowcount = "rowcount")
1258         if (rowcount != 1)
1259           sprintf(argv[i], "#%d", id);
1260
1261         id = atoi(argv[idx]);
1262         type = argv[idx - 1];
1263         if ((name = malloc(33)) == NULL)
1264             return(SMS_NO_MEM);
1265
1266         if (!strcmp(type, "LIST")) {
1267 ##          repeat retrieve (name = list.#name) where list.list_id = @id
1268 ##          inquire_equel(rowcount = "rowcount")
1269             if (rowcount != 1)
1270                 strcpy(name, "???");
1271         } else if (!strcmp(type, "USER")) {
1272 ##          repeat retrieve (name = users.login) where users.users_id = @id
1273 ##          inquire_equel(rowcount = "rowcount")
1274             if (rowcount != 1)
1275                 strcpy(name, "???");
1276         } else if (!strcmp(type, "KERBEROS")) {
1277 ##          repeat retrieve (name = strings.string) where strings.string_id = @id
1278 ##          inquire_equel(rowcount = "rowcount")
1279             if (rowcount != 1)
1280                 strcpy(name, "???");
1281         } else if (!strcmp(type, "NONE")) {
1282             strcpy(name, "NONE");
1283         } else
1284           strcpy(name, "???");
1285         free(argv[idx]);
1286         argv[idx] = name;
1287
1288         if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1289             argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1290             strcpy(argv[6], UNIQUE_GID);
1291         }
1292
1293         /* send the data */
1294         (*action)(q->vcnt, argv, actarg);
1295
1296         /* free saved data */
1297         for (i = 0; i < q->vcnt; i++) 
1298             free(argv[i]);
1299         free(argv);
1300     }
1301
1302     sq_destroy(sq);
1303     return (SMS_SUCCESS);
1304 ##}
1305
1306
1307 /** followup_amtl - followup for amtl and dmfl; when adding a list 
1308  **                 member to a maillist, make member list a maillist also
1309  **                 unless list is a user-group.
1310  **                 Then set_list_modtime_by_id.
1311  **
1312  ** Inputs:
1313  **   argv[0] - list_id
1314  **   argv[1] - member_type
1315  **   argv[2] - member_id
1316  **
1317  **/
1318
1319 followup_amtl(q, argv, cl)
1320     struct query *q;
1321     char *argv[];
1322     client *cl;
1323 ##{
1324 ##  int list_id;
1325 ##  int member_id;
1326 ##  int exists, who;
1327 ##  char *entity;
1328
1329     list_id = *(int *)argv[0];
1330     entity = cl->entity;
1331     who = cl->users_id;
1332
1333 ##  range of l is list
1334 ##  repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1335 ##       where l.#list_id = @list_id
1336
1337     /* if query is not amtl or if member_type is not LIST then return */
1338     if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4)) 
1339         return(SMS_SUCCESS);
1340
1341     member_id = *(int *)argv[2];
1342
1343     /* is parent list a mailing list? */
1344 ##  repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1345     if (!exists)
1346         return(SMS_SUCCESS);
1347
1348     /* list is not a user-group; add list to maillist table */
1349 ##  repeat replace l (maillist = 1) where l.#list_id = @member_id
1350     return(SMS_SUCCESS);
1351 ##}
1352
1353
1354 /* followup_anfq: Add allocation to nfsphys after creating quota.
1355  *   argv[0] = filsys_id
1356  *   argv[2] = ascii(quota)
1357  */
1358
1359 followup_anfq(q, argv, cl)
1360     struct query  *q;
1361     char **argv;
1362     client *cl;
1363 ##{
1364 ##  int quota, user, fs, who;
1365 ##  char *entity;
1366
1367     fs = *(int *)argv[0];
1368     user = *(int *)argv[1];
1369     quota = atoi(argv[2]);
1370     who = cl->users_id;
1371     entity = cl->entity;
1372
1373 ##  repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1374 ##      where nq.filsys_id = @fs and nq.users_id = @user
1375 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1376 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1377     return(SMS_SUCCESS);
1378 ##}
1379
1380
1381 /* followup_gzcl:
1382  */
1383
1384 followup_gzcl(q, sq, v, action, actarg, cl)
1385     register struct query *q;
1386     register struct save_queue *sq;
1387     register struct validate *v;
1388     register int (*action)();
1389     int actarg;
1390     client *cl;
1391 ##{
1392 ##  char *name;
1393 ##  int rowcount, id;
1394     char **argv;
1395     int i;
1396
1397     while (sq_get_data(sq, &argv)) {
1398         sms_trim_args(q->vcnt, argv);
1399
1400         id = atoi(argv[i = q->vcnt - 2]);
1401         free(argv[i]);
1402         name = argv[i] = malloc(9);
1403 ##      repeat retrieve (name = users.login) where users.users_id = @id
1404 ##      inquire_equel(rowcount = "rowcount")
1405         if (rowcount != 1)
1406           sprintf(argv[i], "#%d", id);
1407
1408         for (i = 1; i < 8; i+=2) {
1409             id = atoi(argv[i+1]);
1410             free(argv[i+1]);
1411             if ((name = argv[i+1] = malloc(33)) == NULL)
1412               return(SMS_NO_MEM);
1413             if (!strcmp(argv[i], "LIST")) {
1414 ##              repeat retrieve (name = list.#name) where list.list_id = @id
1415 ##              inquire_equel(rowcount = "rowcount")
1416                 if (rowcount != 1)
1417                   strcpy(name, "???");
1418             } else if (!strcmp(argv[i], "USER")) {
1419 ##              repeat retrieve (name = users.login) where users.users_id = @id
1420 ##              inquire_equel(rowcount = "rowcount")
1421                 if (rowcount != 1)
1422                   strcpy(name, "???");
1423             } else if (!strcmp(argv[i], "KERBEROS")) {
1424 ##              repeat retrieve (name = strings.string) where strings.string_id = @id
1425 ##              inquire_equel(rowcount = "rowcount")
1426                 if (rowcount != 1)
1427                   strcpy(name, "???");
1428             } else if (!strcmp(argv[i], "NONE")) {
1429                 strcpy(name, "NONE");
1430             } else {
1431                 strcpy(name, "???");
1432             }
1433         }
1434
1435         /* send the data */
1436         (*action)(q->vcnt, argv, actarg);
1437
1438         /* free saved data */
1439         for (i = 0; i < q->vcnt; i++) 
1440             free(argv[i]);
1441         free(argv);
1442     }
1443     sq_destroy(sq);
1444     return(SMS_SUCCESS);
1445 ##}
1446
1447
1448 /* followup_gsha:
1449  */
1450
1451 followup_gsha(q, sq, v, action, actarg, cl)
1452     register struct query *q;
1453     register struct save_queue *sq;
1454     register struct validate *v;
1455     register int (*action)();
1456     int actarg;
1457     client *cl;
1458 ##{
1459 ##  char *name;
1460 ##  int rowcount, id;
1461     char **argv;
1462     int i;
1463
1464     while (sq_get_data(sq, &argv)) {
1465         sms_trim_args(q->vcnt, argv);
1466
1467         id = atoi(argv[4]);
1468         free(argv[4]);
1469         name = argv[4] = malloc(9);
1470 ##      repeat retrieve (name = users.login) where users.users_id = @id
1471 ##      inquire_equel(rowcount = "rowcount")
1472         if (rowcount != 1)
1473           sprintf(argv[4], "#%d", id);
1474
1475         id = atoi(argv[2]);
1476         free(argv[2]);
1477         if ((name = argv[2] = malloc(33)) == NULL)
1478           return(SMS_NO_MEM);
1479         if (!strcmp(argv[1], "LIST")) {
1480 ##          repeat retrieve (name = list.#name) where list.list_id = @id
1481 ##          inquire_equel(rowcount = "rowcount")
1482             if (rowcount != 1)
1483               strcpy(name, "???");
1484         } else if (!strcmp(argv[1], "USER")) {
1485 ##          repeat retrieve (name = users.login) where users.users_id = @id
1486 ##          inquire_equel(rowcount = "rowcount")
1487             if (rowcount != 1)
1488               strcpy(name, "???");
1489         } else if (!strcmp(argv[1], "KERBEROS")) {
1490 ##          repeat retrieve (name = strings.string) where strings.string_id = @id
1491 ##          inquire_equel(rowcount = "rowcount")
1492             if (rowcount != 1)
1493               strcpy(name, "???");
1494         } else if (!strcmp(argv[1], "NONE")) {
1495             strcpy(name, "NONE");
1496         } else {
1497             strcpy(name, "???");
1498         }
1499
1500         /* send the data */
1501         (*action)(q->vcnt, argv, actarg);
1502
1503         /* free saved data */
1504         for (i = 0; i < q->vcnt; i++) 
1505             free(argv[i]);
1506         free(argv);
1507     }
1508     sq_destroy(sq);
1509     return(SMS_SUCCESS);
1510 ##}
1511
1512
1513 \f
1514 /* Special query routines */
1515
1516 /* set_pobox - this does all of the real work.
1517  *       argv = user_id, type, box
1518  * if type is POP, then box should be a machine, and its ID should be put in
1519  * pop_id.  If type is SMTP, then box should be a string and its ID should
1520  * be put in box_id.  If type is NONE, then box doesn't matter.
1521  */
1522
1523 int set_pobox(q, argv, cl)
1524     struct query *q;
1525     char **argv;
1526     client *cl;
1527 ##{
1528 ##  int user, id, rowcount;
1529 ##  char *box, potype[9];
1530
1531     box = argv[2];
1532     user = *(int *)argv[0];
1533
1534 ##  repeat retrieve (id = users.pop_id, potype = users.#potype)
1535 ##              where users.users_id = @user
1536     if (!strcmp(strtrim(potype), "POP"))
1537       set_pop_usage(id, -1);
1538
1539     if (!strcmp(argv[1], "POP")) {
1540 ##      repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1541 ##      inquire_equel(rowcount = "rowcount")
1542         if (rowcount != 1)
1543             return(SMS_MACHINE);
1544 ##      repeat replace users (#potype = "POP", pop_id = @id)
1545 ##              where users.users_id = @user
1546         set_pop_usage(id, 1);
1547     } else if (!strcmp(argv[1], "SMTP")) {
1548 ##      range of s is strings
1549 ##      repeat retrieve (id = s.string_id) where s.string = @box
1550 ##      inquire_equel (rowcount = "rowcount")
1551         if (rowcount == 0) {
1552 ##          range of v is values
1553 ##          repeat retrieve (id = v.value) where v.name = "strings_id"
1554             id++;
1555 ##          repeat replace v (value = @id) where v.name = "strings_id"
1556 ##          append to strings (string_id = id, string = box)
1557         }
1558 ##      repeat replace users (#potype = "SMTP", box_id = @id) 
1559 ##             where users.users_id = @user
1560     } else /* argv[1] == "NONE" */ {
1561 ##      repeat replace users (#potype = "NONE") where users.users_id = @user
1562     }
1563
1564     set_pobox_modtime(q, argv, cl);
1565 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1566 ##      where tblstats.#table = "users"
1567     return(SMS_SUCCESS);
1568 ##}
1569
1570
1571 /* get_list_info:  passed a wildcard list name, returns lots of stuff about
1572  * each list.  This is tricky:  first build a queue of all requested
1573  * data.  Rest of processing consists of fixing gid, ace_name, and modby.
1574  */
1575
1576 get_list_info(q, aargv, cl, action, actarg)
1577     register struct query *q;
1578     char **aargv;
1579     client *cl;
1580     register int (*action)();
1581     int actarg;
1582 ##{
1583     char *argv[13], *malloc(), *realloc();
1584 ##  char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1585 ##  char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1586 ##  char modby[9], modwith[9];
1587 ##  int id, rowcount, acl_id, hid, modby_id;
1588     int returned;
1589     struct save_queue *sq, *sq_create();
1590
1591     returned = rowcount = 0;
1592     name = aargv[0];
1593
1594     sq = sq_create();
1595 ##  range of l is list
1596 ##  repeat retrieve (id = l.list_id) where l.#name = @name {
1597         sq_save_data(sq, id);
1598         rowcount++;
1599 ##  }
1600     if (rowcount == 0)
1601       return(SMS_NO_MATCH);
1602
1603     argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1604     argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1605     argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1606     argv[12] = modwith;
1607
1608     while (sq_get_data(sq, &id)) {
1609         if (id == 0)
1610           continue;
1611         argv[6] = gid;
1612 ##      repeat retrieve (listname = l.#name, active = text(l.#active), 
1613 ##              public = text(l.#public), hidden = text(l.#hidden),
1614 ##              hid = l.#hidden, maillist = text(l.#maillist),
1615 ##              group = text(l.#group), gid = text(l.#gid),
1616 ##              acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1617 ##              desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1618 ##              modwith =l.#modwith)
1619 ##          where l.list_id = @id
1620
1621         if (atoi(gid) == -1)
1622             argv[6] = UNIQUE_GID;
1623
1624         if (!strcmp(acl_type, "LIST")) {
1625 ##          repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1626 ##          inquire_equel(rowcount = "rowcount")
1627             if (rowcount != 1)
1628                 strcpy(acl_name, "???");
1629         } else if (!strcmp(acl_type, "USER")) {
1630 ##          repeat retrieve (acl_name = users.#login)
1631 ##              where users.users_id = @acl_id
1632 ##          inquire_equel(rowcount = "rowcount")
1633             if (rowcount != 1)
1634                 strcpy(acl_name, "???");
1635         } else if (!strcmp(acl_type, "KERBEROS")) {
1636 ##          repeat retrieve (acl_name = strings.string)
1637 ##              where strings.string_id = @acl_id
1638 ##          inquire_equel(rowcount = "rowcount")
1639             if (rowcount != 1)
1640                 strcpy(acl_name, "???");
1641         } else if (!strcmp(acl_type, "NONE")) {
1642             strcpy(acl_name, "NONE");
1643         } else
1644           strcpy(acl_name, "???");
1645
1646 ##      repeat retrieve (modby = users.login) where users.users_id = @modby_id
1647 ##      inquire_equel(rowcount = "rowcount")
1648         if (rowcount != 1)
1649           sprintf(modby, "#%d", id);
1650
1651         sms_trim_args(q->vcnt, argv);
1652         returned++;
1653         (*action)(q->vcnt, argv, actarg);
1654     }
1655
1656     sq_destroy(sq);
1657 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1658 ##      where tblstats.#table = "list"
1659
1660     return (SMS_SUCCESS);
1661 ##}
1662
1663
1664 /* get_ace_use - given a type and a name, return a type and a name.
1665  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1666  * and argv[1] will contain the ID of the entity in question.  The R*
1667  * types mean to recursively look at every containing list, not just
1668  * when the object in question is a direct member.  On return, the
1669  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1670  */
1671
1672 int get_ace_use(q, argv, cl, action, actarg)
1673     struct query *q;
1674     char *argv[];
1675     client *cl;
1676     int (*action)();
1677     int actarg;
1678 ##{
1679     int found = 0;
1680 ##  char *atype;
1681 ##  int aid, listid, id;
1682     struct save_queue *sq, *sq_create();
1683
1684     atype = argv[0];
1685     aid = *(int *)argv[1];
1686     if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
1687         !strcmp(atype, "KERBEROS")) {
1688         return(get_ace_internal(atype, aid, action, actarg));
1689     }
1690
1691     sq = sq_create();
1692     if (!strcmp(atype, "RLIST")) {
1693         sq_save_data(sq, aid);
1694         /* get all the list_id's of containing lists */
1695 ##      range of m is members
1696         while (sq_get_data(sq, &id)) {
1697 ##          repeat retrieve (listid = m.list_id)
1698 ##              where m.member_type = "LIST" and m.member_id = @id {
1699               sq_save_unique_data(sq, listid);
1700 ##          }
1701           }
1702         /* now process each one */
1703         while (sq_get_data(sq, &id)) {
1704             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1705               found++;
1706         }
1707     }
1708
1709     if (!strcmp(atype, "RUSER")) {
1710 ##      range of m is members
1711 ##      repeat retrieve (listid = m.list_id)
1712 ##              where m.member_type = "USER" and m.member_id = @aid {
1713             sq_save_data(sq, listid);
1714 ##      }
1715         /* get all the list_id's of containing lists */
1716         while (sq_get_data(sq, &id)) {
1717 ##          repeat retrieve (listid = m.list_id)
1718 ##              where m.member_type = "LIST" and m.member_id = @id {
1719               sq_save_unique_data(sq, listid);
1720 ##          }
1721           }
1722         /* now process each one */
1723         while (sq_get_data(sq, &id)) {
1724             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1725               found++;
1726         }
1727         if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1728           found++;
1729     }
1730
1731     if (!strcmp(atype, "RKERBERO")) {
1732 ##      range of m is members
1733 ##      repeat retrieve (listid = m.list_id)
1734 ##              where m.member_type = "KERBEROS" and m.member_id = @aid {
1735             sq_save_data(sq, listid);
1736 ##      }
1737         /* get all the list_id's of containing lists */
1738         while (sq_get_data(sq, &id)) {
1739 ##          repeat retrieve (listid = m.list_id)
1740 ##              where m.member_type = "LIST" and m.member_id = @id {
1741               sq_save_unique_data(sq, listid);
1742 ##          }
1743           }
1744         /* now process each one */
1745         while (sq_get_data(sq, &id)) {
1746             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1747               found++;
1748         }
1749         if (get_ace_internal("KERBEROS", aid, action, actarg) == SMS_SUCCESS)
1750           found++;
1751     }
1752
1753     sq_destroy(sq);     
1754     if (!found) return(SMS_NO_MATCH);
1755     return(SMS_SUCCESS);
1756 ##}
1757
1758
1759 /* This looks up a single list or user for ace use.  atype must be "USER"
1760  * or "LIST", and aid is the ID of the corresponding object.  This is used
1761  * by get_ace_use above.
1762  */
1763
1764 ##get_ace_internal(atype, aid, action, actarg)
1765 ##  char *atype;
1766 ##  int aid;
1767     int (*action)();
1768     int actarg;
1769 ##{
1770     char *rargv[2];
1771     int found = 0;
1772 ##  char name[33];
1773
1774     rargv[1] = name;
1775     if (!strcmp(atype, "LIST")) {
1776         rargv[0] = "FILESYS";
1777 ##      repeat retrieve (name = filesys.label) 
1778 ##              where filesys.owners = @aid {
1779             (*action)(2, rargv, actarg);
1780             found++;
1781 ##      }
1782
1783         rargv[0] = "QUERY";
1784 ##      repeat retrieve (name = capacls.capability)
1785 ##              where capacls.list_id = @aid {
1786             (*action)(2, rargv, actarg);
1787             found++;
1788 ##      }
1789     } else if (!strcmp(atype, "USER")) {
1790         rargv[0] = "FILESYS";
1791 ##      repeat retrieve (name = filesys.label) 
1792 ##              where filesys.owner = @aid {
1793             (*action)(2, rargv, actarg);
1794             found++;
1795 ##      }
1796     }
1797
1798     rargv[0] = "LIST";
1799 ##  repeat retrieve (name = list.#name) 
1800 ##              where list.acl_type = @atype and list.acl_id = @aid {
1801          (*action)(2, rargv, actarg);
1802          found++;
1803 ##  }
1804
1805     rargv[0] = "SERVICE";
1806 ##  repeat retrieve (name = servers.#name) 
1807 ##              where servers.acl_type = @atype and servers.acl_id = @aid {
1808          (*action)(2, rargv, actarg);
1809          found++;
1810 ##  }
1811
1812     rargv[0] = "HOSTACCESS";
1813 ##  repeat retrieve (name = machine.#name)
1814 ##              where machine.mach_id = hostaccess.mach_id and 
1815 ##                   hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1816         (*action)(2, rargv, actarg);
1817         found++;
1818 ##  }
1819     rargv[0] = "ZEPHYR";
1820 ##  repeat retrieve (name = zephyr.class) 
1821 ##              where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1822 ##                    zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1823 ##                    zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1824 ##                    zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1825          (*action)(2, rargv, actarg);
1826          found++;
1827 ##  }
1828
1829     if (!found) return(SMS_NO_MATCH);
1830     return(SMS_SUCCESS);
1831 ##}
1832
1833
1834 /* get_lists_of_member - given a type and a name, return the name and flags
1835  * of all of the lists of the given member.  The member_type is one of
1836  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1837  * and argv[1] will contain the ID of the entity in question.  The R*
1838  * types mean to recursively look at every containing list, not just
1839  * when the object in question is a direct member.
1840  */
1841
1842 int get_lists_of_member(q, argv, cl, action, actarg)
1843     struct query *q;
1844     char *argv[];
1845     client *cl;
1846     int (*action)();
1847     int actarg;
1848 ##{
1849     int found = 0;
1850 ##  char *atype;
1851 ##  int aid, listid, id;
1852     struct save_queue *sq, *sq_create();
1853
1854     atype = argv[0];
1855     aid = *(int *)argv[1];
1856     if (!strcmp(atype, "LIST") ||
1857         !strcmp(atype, "USER") ||
1858         !strcmp(atype, "STRING") ||
1859         !strcmp(atype, "KERBEROS")) {
1860       return(glom_internal(atype, aid, action, actarg));
1861     }
1862
1863     sq = sq_create();
1864     if (!strcmp(atype, "RLIST")) {
1865         sq_save_data(sq, aid);
1866         /* get all the list_id's of containing lists */
1867 ##      range of m is members
1868         while (sq_get_data(sq, &id)) {
1869 ##          repeat retrieve (listid = m.list_id)
1870 ##              where m.member_type = "LIST" and m.member_id = @id {
1871               sq_save_unique_data(sq, listid);
1872 ##          }
1873           }
1874         /* now process each one */
1875         while (sq_get_data(sq, &id)) {
1876             if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1877               found++;
1878         }
1879     }
1880
1881     if (!strcmp(atype, "RUSER")) {
1882 ##      range of m is members
1883 ##      repeat retrieve (listid = m.list_id)
1884 ##              where m.member_type = "USER" and m.member_id = @aid {
1885             sq_save_data(sq, listid);
1886 ##      }
1887         /* get all the list_id's of containing lists */
1888         while (sq_get_data(sq, &id)) {
1889 ##          repeat retrieve (listid = m.list_id)
1890 ##              where m.member_type = "LIST" and m.member_id = @id {
1891               sq_save_unique_data(sq, listid);
1892 ##          }
1893           }
1894         /* now process each one */
1895         while (sq_get_data(sq, &id)) {
1896             if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1897               found++;
1898         }
1899         if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1900           found++;
1901     }
1902
1903     if (!strcmp(atype, "RSTRING")) {
1904 ##      range of m is members
1905 ##      repeat retrieve (listid = m.list_id)
1906 ##              where m.member_type = "STRING" and m.member_id = @aid {
1907             sq_save_data(sq, listid);
1908 ##      }
1909         /* get all the list_id's of containing lists */
1910         while (sq_get_data(sq, &id)) {
1911 ##          repeat retrieve (listid = m.list_id)
1912 ##              where m.member_type = "LIST" and m.member_id = @id {
1913               sq_save_unique_data(sq, listid);
1914 ##          }
1915           }
1916         /* now process each one */
1917         while (sq_get_data(sq, &id)) {
1918             if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1919               found++;
1920         }
1921         if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1922           found++;
1923     }
1924
1925     if (!strcmp(atype, "RKERBERO")) {
1926 ##      range of m is members
1927 ##      repeat retrieve (listid = m.list_id)
1928 ##              where m.member_type = "KERBEROS" and m.member_id = @aid {
1929             sq_save_data(sq, listid);
1930 ##      }
1931         /* get all the list_id's of containing lists */
1932         while (sq_get_data(sq, &id)) {
1933 ##          repeat retrieve (listid = m.list_id)
1934 ##              where m.member_type = "LIST" and m.member_id = @id {
1935               sq_save_unique_data(sq, listid);
1936 ##          }
1937           }
1938         /* now process each one */
1939         while (sq_get_data(sq, &id)) {
1940             if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1941               found++;
1942         }
1943         if (glom_internal("KERBEROS", aid, action, actarg) == SMS_SUCCESS)
1944           found++;
1945     }
1946
1947 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1948 ##      where tblstats.#table = "members"
1949     sq_destroy(sq);     
1950     if (!found) return(SMS_NO_MATCH);
1951     return(SMS_SUCCESS);
1952 ##}
1953
1954
1955 /* This looks up a single list, user, or string as a member.  atype must be
1956  * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1957  * This is used by get_lists_of_members above.
1958  */
1959
1960 ##glom_internal(atype, aid, action, actarg)
1961 ##  char *atype;
1962 ##  int aid;
1963     int (*action)();
1964     int actarg;
1965 ##{
1966     char *rargv[6];
1967     int found = 0;
1968 ##  char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1969
1970     rargv[0] = name;
1971     rargv[1] = active;
1972     rargv[2] = public;
1973     rargv[3] = hidden;
1974     rargv[4] = maillist;
1975     rargv[5] = group;
1976 ##  repeat retrieve (name = list.#name, active = text(list.#active), 
1977 ##                   public = text(list.#public), hidden = text(list.#hidden),
1978 ##                   maillist = text(list.#maillist), group = text(list.#group))
1979 ##              where list.list_id = m.list_id and
1980 ##                    m.member_type = @atype and m.member_id = @aid {
1981          (*action)(6, rargv, actarg);
1982          found++;
1983 ##  }
1984
1985     if (!found) return(SMS_NO_MATCH);
1986     return(SMS_SUCCESS);
1987 ##}
1988
1989
1990 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1991  * the five flags associated with each list.  It will return the name of
1992  * each list that meets the quailifications.  It does this by building a
1993  * where clause based on the arguments, then doing a retrieve.
1994  */
1995
1996 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1997
1998 int qualified_get_lists(q, argv, cl, action, actarg)
1999     struct query *q;
2000     char *argv[];
2001     client *cl;
2002     int (*action)();
2003     int actarg;
2004 {
2005     return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2006                          "l", "name", lflags));
2007 }
2008
2009
2010 /** get_members_of_list - optimized query for retrieval of list members
2011  **
2012  ** Inputs:
2013  **   argv[0] - list_id
2014  **
2015  ** Description:
2016  **   - retrieve USER members, then LIST members, then STRING members
2017  **/
2018
2019 get_members_of_list(q, argv, cl, action, actarg)
2020     struct query *q;
2021     char *argv[];
2022     client *cl;
2023     int (*action)();
2024     int actarg;
2025 ##{
2026 ##  int list_id;
2027 ##  char member_name[129];
2028     char *targv[2];
2029
2030     list_id = *(int *)argv[0];
2031     targv[0] = "USER";
2032     targv[1] = member_name;
2033
2034 ##  range of m is members
2035 ##  repeat retrieve (member_name = users.login)
2036 ##             where m.#list_id = @list_id and m.member_type = "USER"
2037 ##                   and m.member_id = users.users_id
2038 ##             sort by #member_name
2039 ##  {
2040          (*action)(2, targv, actarg);
2041 ##  }
2042
2043     targv[0] = "LIST";
2044 ##  repeat retrieve (member_name = list.name)
2045 ##             where m.#list_id = @list_id and m.member_type = "LIST"
2046 ##                   and m.member_id = list.#list_id
2047 ##             sort by #member_name
2048 ##  {
2049          (*action)(2, targv, actarg);
2050 ##  }
2051
2052     targv[0] = "STRING";
2053 ##  repeat retrieve (member_name = strings.string)
2054 ##             where m.#list_id = @list_id and m.member_type = "STRING"
2055 ##                   and m.member_id = strings.string_id
2056 ##             sort by #member_name
2057 ##  {
2058          (*action)(2, targv, actarg);
2059 ##  }
2060
2061     targv[0] = "KERBEROS";
2062 ##  repeat retrieve (member_name = strings.string)
2063 ##             where m.#list_id = @list_id and m.member_type = "KERBEROS"
2064 ##                   and m.member_id = strings.string_id
2065 ##             sort by #member_name
2066 ##  {
2067          (*action)(2, targv, actarg);
2068 ##  }
2069
2070 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2071 ##      where tblstats.#table = "members"
2072     return(SMS_SUCCESS);
2073 ##}
2074
2075
2076 /* count_members_of_list: this is a simple query, but it cannot be done
2077  * through the dispatch table.
2078  */
2079
2080 int count_members_of_list(q, argv, cl, action, actarg)
2081     struct query *q;
2082     char *argv[];
2083     client *cl;
2084     int (*action)();
2085     int actarg;
2086 ##{
2087 ##  int  list, ct = 0;
2088     char *rargv[1], countbuf[5];
2089
2090     list = *(int *)argv[0];
2091     rargv[0] = countbuf;
2092 ##  repeat retrieve (ct = count(members.list_id where members.list_id = @list))
2093     sprintf(countbuf, "%d", ct);
2094     (*action)(1, rargv, actarg);
2095 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2096 ##      where tblstats.#table = "members"
2097     return(SMS_SUCCESS);
2098 ##}
2099
2100
2101 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2102  * the three flags associated with each service.  It will return the name of
2103  * each service that meets the quailifications.  It does this by building a
2104  * where clause based on the arguments, then doing a retrieve.
2105  */
2106
2107 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2108
2109 int qualified_get_server(q, argv, cl, action, actarg)
2110     struct query *q;
2111     char *argv[];
2112     client *cl;
2113     int (*action)();
2114     int actarg;
2115 {
2116     return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2117                          "s", "name", sflags));
2118 }
2119
2120
2121 /* generic qualified get routine, used by qualified_get_lists,
2122  * qualified_get_server, and qualified_get_serverhost.
2123  *   Args:
2124  *      start - a simple where clause, must not be empty
2125  *      range - the name of the range variable
2126  *      field - the field to return
2127  *      flags - an array of strings, names of the flag variables
2128  */
2129
2130 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2131     struct query *q;
2132     char *argv[];
2133     int (*action)();
2134     int actarg;
2135     char *start;
2136     char *range;
2137     char *field;
2138     char *flags[];
2139 ##{
2140 ##  char name[33], qual[256], *rvar, *rtbl, *rfield;
2141     char *rargv[1], buf[32];
2142 ##  int rowcount, i;
2143
2144     strcpy(qual, start);
2145     for (i = 0; i < q->argc; i++) {
2146         if (!strcmp(argv[i], "TRUE")) {
2147             sprintf(buf, " and %s.%s != 0", range, flags[i]);
2148             (void) strcat(qual, buf);
2149         } else if (!strcmp(argv[i], "FALSE")) {
2150             sprintf(buf, " and %s.%s = 0", range, flags[i]);
2151             (void) strcat(qual, buf);
2152         }
2153     }
2154       
2155     rargv[0] = name;
2156     rvar = range;
2157     rtbl = q->rtable;
2158     rfield = field;
2159 ##  range of rvar is rtbl
2160 ##  retrieve (name = rvar.rfield) where qual {
2161         (*action)(1, rargv, actarg);
2162 ##  }
2163 ##  inquire_equel(rowcount = "rowcount")
2164 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2165 ##      where tblstats.#table = @rtbl
2166     if (rowcount == 0)
2167       return(SMS_NO_MATCH);
2168     return(SMS_SUCCESS);
2169 ##}
2170
2171
2172 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2173  * the five flags associated with each serverhost.  It will return the name of
2174  * each service and host that meets the quailifications.  It does this by 
2175  * building a where clause based on the arguments, then doing a retrieve.
2176  */
2177
2178 static char *shflags[6] = { "service", "enable", "override", "success",
2179                             "inprogress", "hosterror" };
2180
2181 int qualified_get_serverhost(q, argv, cl, action, actarg)
2182     struct query *q;
2183     char *argv[];
2184     client *cl;
2185     int (*action)();
2186     int actarg;
2187 ##{
2188 ##  char sname[33], mname[33], qual[256];
2189     char *rargv[2], buf[32];
2190 ##  int rowcount, i;
2191
2192     sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2193             argv[0]);
2194     for (i = 1; i < q->argc; i++) {
2195         if (!strcmp(argv[i], "TRUE")) {
2196             sprintf(buf, " and sh.%s != 0", shflags[i]);
2197             strcat(qual, buf);
2198         } else if (!strcmp(argv[i], "FALSE")) {
2199             sprintf(buf, " and sh.%s = 0", shflags[i]);
2200             strcat(qual, buf);
2201         }
2202     }
2203       
2204     rargv[0] = sname;
2205     rargv[1] = mname;
2206 ##  range of sh is serverhosts
2207 ##  retrieve (sname = sh.service, mname = machine.name) where qual {
2208         (*action)(2, rargv, actarg);
2209 ##  }
2210 ##  inquire_equel(rowcount = "rowcount")
2211 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2212 ##      where tblstats.#table = "serverhosts"
2213     if (rowcount == 0)
2214       return(SMS_NO_MATCH);
2215     return(SMS_SUCCESS);
2216 ##}
2217
2218
2219 /* register_user - change user's login name and allocate a pobox, group,
2220  * filesystem, and quota for them.  The user's status must start out as 0,
2221  * and is left as 2.  Arguments are: user's UID, new login name, and user's
2222  * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY, 
2223  * SMS_FS_STAFF, SMS_FS_MISC).
2224  */
2225
2226 register_user(q, argv, cl)
2227     struct query *q;
2228     char **argv;
2229     client *cl;
2230 ##{
2231 ##  char *login, dir[65], *entity, *directory, machname[33];
2232 ##  int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2233 ##  int size, alloc, pid, m_id;
2234     int maxsize;
2235
2236     entity = cl->entity;
2237     who = cl->users_id;
2238
2239     uid = atoi(argv[0]);
2240     login = argv[1];
2241     utype = atoi(argv[2]);
2242
2243 ##  range of u is users
2244 ##  range of l is list
2245 ##  range of sh is serverhosts
2246 ##  range of n is nfsphys
2247 ##  range of m is machine
2248
2249     /* find user */
2250 ##  repeat retrieve (users_id = u.#users_id)
2251 ##      where u.#uid = @uid and u.status = 0
2252 ##  inquire_equel(rowcount = "rowcount");
2253     if (rowcount == 0)
2254       return(SMS_NO_MATCH);
2255     if (rowcount > 1)
2256       return(SMS_NOT_UNIQUE);
2257
2258     /* check new login name */
2259 ##  repeat retrieve (flag = any(u.#login where u.#login = @login))
2260     if (ingres_errno) return(sms_errcode);
2261     if (flag) return(SMS_IN_USE);
2262 ##  repeat retrieve (flag = any(l.#name where l.#name = @login))
2263     if (ingres_errno) return(sms_errcode);
2264     if (flag) return(SMS_IN_USE);
2265 ##  repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2266     if (ingres_errno) return(sms_errcode);
2267     if (flag) return(SMS_IN_USE);
2268     com_err(whoami, 0, "new login name OK");
2269
2270     /* choose place for pobox, put in mid */
2271 ##  repeat retrieve (mid = sh.mach_id, machname = m.name)
2272 ##    where sh.service = "POP" and m.mach_id = sh.mach_id and
2273 ##      sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2274 ##  inquire_equel(rowcount = "rowcount");
2275     if (rowcount == 0)
2276       return(SMS_NO_POBOX);
2277
2278     /* change login name, set pobox */
2279 ##  repeat replace u (#login = @login, status = 2, modtime = "now",
2280 ##                    modby = @who, modwith = @entity, potype="POP",
2281 ##                    pop_id = @mid, pmodtime="now", pmodby=@who,
2282 ##                    pmodwith=@entity)
2283 ##      where u.#users_id = @users_id
2284 ##  inquire_equel(rowcount = "rowcount");
2285     if (rowcount != 1)
2286       return(SMS_INTERNAL);
2287     set_pop_usage(mid, 1);
2288     com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2289             trim(machname));
2290
2291     /* create group list */
2292     if (set_next_object_id("gid", "list"))
2293       return(SMS_NO_ID);
2294     if (set_next_object_id("list_id", "list"))
2295       return(SMS_NO_ID);
2296 ##  repeat retrieve (list_id = values.value) where values.name = "list_id"
2297 ##  inquire_equel(rowcount = "rowcount");
2298     if (rowcount != 1)
2299       return(SMS_INTERNAL);
2300 ##  repeat append list (name = @login, #list_id = @list_id, active = 1,
2301 ##                      public = 0, hidden = 0, maillist = 0, group = 1,
2302 ##                      #gid = values.value, desc = "User Group",
2303 ##                      acl_type = "USER", acl_id = @users_id, modtime = "now",
2304 ##                      modby = @who, modwith = @entity)
2305 ##      where values.name = "gid"
2306 ##  inquire_equel(rowcount = "rowcount");
2307     if (rowcount != 1)
2308       return(SMS_INTERNAL);
2309 ##  repeat append members (#list_id = @list_id, member_type = "USER",
2310 ##                         member_id = @users_id)
2311 ##  inquire_equel(rowcount = "rowcount");
2312     if (rowcount != 1)
2313       return(SMS_INTERNAL);
2314     com_err(whoami, 0, "group list created");
2315
2316     /* decide where to put filesystem */
2317     maxsize = 0;
2318     directory = NULL;
2319 ##  repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2320 ##                   flag = n.status, size = n.#size, alloc = n.allocated) {
2321         if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2322             maxsize = size - alloc;
2323             if (directory)
2324               free(directory);
2325             directory = strsave(dir);
2326             pid = nid;
2327             m_id = mid;
2328         }
2329 ##  }
2330     if (maxsize == 0)
2331       return(SMS_NO_FILESYS);
2332
2333     /* create filesystem */
2334     if (set_next_object_id("filsys_id", "filesys"))
2335       return(SMS_NO_ID);
2336 ##  repeat append filesys (filsys_id = values.value, phys_id = @pid,
2337 ##                         label = @login, type = "NFS", mach_id = @m_id,
2338 ##                         name = @directory + "/" + @login,
2339 ##                         mount = "/mit/" + @login,
2340 ##                         access = "w", comments = "User Locker",
2341 ##                         owner = @users_id, owners = @list_id, createflg = 1,
2342 ##                         lockertype = "HOMEDIR", modtime = "now",
2343 ##                         modby = @who, modwith = @entity)
2344 ##      where values.name = "filsys_id"
2345 ##  inquire_equel(rowcount = "rowcount");
2346     if (rowcount != 1)
2347       return(SMS_INTERNAL);
2348     com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2349             directory, login);
2350
2351     /* set quota */
2352 ##  repeat retrieve (quota = values.value) where values.name = "def_quota"
2353 ##  inquire_equel(rowcount = "rowcount");
2354     if (rowcount != 1)
2355       return(SMS_NO_QUOTA);
2356 ##  repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2357 ##                          #quota = @quota, phys_id = @pid, modtime = "now",
2358 ##                          modby = @who, modwith = @entity)
2359 ##      where values.name = "filsys_id"
2360 ##  inquire_equel(rowcount = "rowcount");
2361     if (rowcount != 1)
2362       return(SMS_INTERNAL);
2363 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2364 ##      where nfsphys.nfsphys_id = filesys.#phys_id and
2365 ##            filesys.filsys_id = values.value and values.name = "filsys_id"
2366 ##  inquire_equel(rowcount = "rowcount");
2367     if (rowcount != 1)
2368       return(SMS_INTERNAL);
2369     com_err(whoami, 0, "quota of %d assigned", quota);
2370
2371 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2372 ##      where tblstats.table = "users"
2373 ##  repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2374 ##      where tblstats.table = "list" or tblstats.table = "filesys" or
2375 ##            tblstats.table = "nfsquota"
2376     return(SMS_SUCCESS);
2377 ##}
2378
2379
2380
2381 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2382  **
2383  ** Inputs:
2384  **   id of machine
2385  **   delta (will be +/- 1)
2386  **
2387  ** Description:
2388  **   - incr/decr value field in serverhosts table for pop/mach_id
2389  **
2390  **/
2391
2392 static int set_pop_usage(id, count)
2393 int id;
2394 int count;
2395 ##{
2396 ##  int mach_id = id;
2397 ##  int n = count;
2398
2399 ##  range of sh is serverhosts
2400 ##  repeat replace sh (value1 = sh.value1 + @n)
2401 ##         where sh.service = "POP" and sh.#mach_id = @mach_id
2402
2403     return(SMS_SUCCESS);
2404 ##}
2405
2406
2407 \f
2408 /* Validation Routines */
2409
2410 validate_row(q, argv, v)
2411     register struct query *q;
2412     char *argv[];
2413     register struct validate *v;
2414 ##{
2415 ##  char *rvar;
2416 ##  char *table;
2417 ##  char *name;
2418 ##  char qual[128];
2419 ##  int rowcount;
2420
2421     /* build where clause */
2422     build_qual(v->qual, v->argc, argv, qual);
2423
2424     /* setup ingres variables */
2425     rvar = q->rvar;
2426     table = q->rtable;
2427     name = v->field;
2428
2429     if (log_flags & LOG_VALID)
2430         /* tell the logfile what we're doing */
2431         com_err(whoami, 0, "validating row: %s", qual);
2432     
2433     /* look for the record */
2434 ##  range of rvar is table
2435 ##  retrieve (rowcount = count(rvar.name where qual))
2436     if (ingres_errno) return(sms_errcode);
2437     if (rowcount == 0) return(SMS_NO_MATCH);
2438     if (rowcount > 1) return(SMS_NOT_UNIQUE);
2439     return(SMS_EXISTS);
2440 ##}
2441
2442 validate_fields(q, argv, vo, n)
2443     struct query *q;
2444     register char *argv[];
2445     register struct valobj *vo;
2446     register int n;
2447 {
2448     register int status;
2449
2450     while (--n >= 0) {
2451         switch (vo->type) {
2452         case V_NAME:
2453             if (log_flags & LOG_VALID)
2454                 com_err(whoami, 0, "validating %s in %s: %s", 
2455                     vo->namefield, vo->table, argv[vo->index]);
2456             status = validate_name(argv, vo);
2457             break;
2458
2459         case V_ID:
2460             if (log_flags & LOG_VALID)
2461                 com_err(whoami, 0, "validating %s in %s: %s", 
2462                     vo->idfield, vo->table, argv[vo->index]);
2463             status = validate_id(argv, vo);
2464             break;
2465
2466         case V_DATE:
2467             if (log_flags & LOG_VALID)
2468                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2469             status = validate_date(argv, vo);
2470             break;
2471
2472         case V_TYPE:
2473             if (log_flags & LOG_VALID)
2474                 com_err(whoami, 0, "validating %s type: %s",
2475                     vo->table, argv[vo->index]);
2476             status = validate_type(argv, vo);
2477             break;
2478
2479         case V_TYPEDATA:
2480             if (log_flags & LOG_VALID)
2481                 com_err(whoami, 0, "validating typed data (%s): %s",
2482                     argv[vo->index - 1], argv[vo->index]);
2483             status = validate_typedata(q, argv, vo);
2484             break;
2485
2486         case V_RENAME:
2487             if (log_flags & LOG_VALID)
2488                 com_err(whoami, 0, "validating rename %s in %s",
2489                         argv[vo->index], vo->table);
2490             status = validate_rename(argv, vo);
2491             break;
2492
2493         case V_CHAR:
2494             if (log_flags & LOG_VALID)
2495               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2496             status = validate_chars(argv[vo->index]);
2497             break;
2498
2499         case V_SORT:
2500             status = SMS_EXISTS;
2501             break;
2502
2503         case V_LOCK:
2504             status = lock_table(vo);
2505             break;
2506         }
2507
2508         if (status != SMS_EXISTS) return(status);
2509         vo++;
2510     }
2511
2512     return(SMS_SUCCESS);
2513 }
2514
2515
2516 /* validate_chars: verify that there are no illegal characters in
2517  * the string.  Legal characters are printing chars other than 
2518  * ", *, ?, \, [ and ].
2519  */
2520 static int illegalchars[] = {
2521     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2522     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2523     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2524     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2525     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2526     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2527     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2528     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2529     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2530     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2531     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2532     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2533     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2534     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2535     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2536     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2537 };
2538
2539 validate_chars(s)
2540 register char *s;
2541 {
2542     while (*s)
2543       if (illegalchars[*s++])
2544         return(SMS_BAD_CHAR);
2545     return(SMS_EXISTS);
2546 }
2547
2548
2549 validate_id(argv, vo)
2550     char *argv[];
2551     register struct valobj *vo;
2552 ##{
2553 ##  char *name;
2554 ##  char *table;
2555 ##  char *namefield;
2556 ##  char *idfield;
2557 ##  int id;
2558 ##  int rowcount;
2559     register char *c;
2560
2561     name = argv[vo->index];
2562     table = vo->table;
2563     /* minor kludge to upcasify machine names */
2564     if (!strcmp(table, "machine"))
2565         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2566     namefield = vo->namefield;
2567     idfield = vo->idfield;
2568     if (!strcmp(namefield, "uid")) {
2569 ##    retrieve (id = table.idfield) where table.namefield = int4(name)
2570       if (ingres_errno) return(sms_errcode);
2571 ##    inquire_equel (rowcount = "rowcount")
2572     } else {
2573 ##    retrieve (id = table.idfield) where table.namefield = name
2574       if (ingres_errno) return(sms_errcode);
2575 ##    inquire_equel (rowcount = "rowcount")
2576     }
2577     if (rowcount != 1) return(vo->error);
2578     *(int *)argv[vo->index] = id;
2579     return(SMS_EXISTS);
2580 ##}
2581
2582 validate_name(argv, vo)
2583     char *argv[];
2584     register struct valobj *vo;
2585 ##{
2586 ##  char *name;
2587 ##  char *table;
2588 ##  char *namefield;
2589 ##  int rowcount;
2590     register char *c;
2591
2592     name = argv[vo->index];
2593     table = vo->table;
2594     namefield = vo->namefield;
2595     if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2596         for (c = name; *c; c++)
2597           if (islower(*c))
2598             *c = toupper(*c);
2599     }
2600 ##  retrieve (rowcount = countu(table.namefield 
2601 ##            where table.namefield = name))
2602     if (ingres_errno) return(sms_errcode);
2603     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2604 ##}
2605
2606 validate_date(argv, vo)
2607     char *argv[];
2608     struct valobj *vo;
2609 ##{
2610 ##  char *idate;
2611 ##  double dd;
2612 ##  int errorno;
2613
2614     idate = argv[vo->index];
2615
2616 ##  retrieve (dd = interval("years", date(idate) - date("today")))
2617 ##  inquire_equel (errorno = "errorno")
2618     if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2619     return(SMS_EXISTS);
2620 ##}
2621
2622
2623 validate_rename(argv, vo)
2624 char *argv[];
2625 struct valobj *vo;
2626 ##{
2627 ##  char *name, *table, *namefield, *idfield;
2628 ##  int id;
2629     register char *c;
2630
2631     c = name = argv[vo->index];
2632     while (*c)
2633       if (illegalchars[*c++])
2634         return(SMS_BAD_CHAR);
2635     table = vo->table;
2636     /* minor kludge to upcasify machine names */
2637     if (!strcmp(table, "machine"))
2638         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2639     namefield = vo->namefield;
2640     idfield = vo->idfield;
2641     id = -1;
2642     if (idfield == 0) {
2643         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2644           return(SMS_EXISTS);
2645 ##      retrieve (id = any(table.namefield where table.namefield = name))
2646         if (ingres_errno) return(sms_errcode);
2647         if (id)
2648           return(vo->error);
2649         else
2650           return(SMS_EXISTS);
2651     }
2652 ##  retrieve (id = table.idfield) where table.namefield = name
2653     if (ingres_errno) return(sms_errcode);
2654     if (id == -1 || id == *(int *)argv[vo->index - 1])
2655       return(SMS_EXISTS);
2656     else
2657       return(vo->error);
2658 ##}
2659
2660
2661 validate_type(argv, vo)
2662     char *argv[];
2663     register struct valobj *vo;
2664 ##{
2665 ##  char *typename;
2666 ##  char *value;
2667 ##  int exists;
2668     register char *c;
2669
2670     typename = vo->table;
2671     c = value = argv[vo->index];
2672     while (*c)
2673       if (illegalchars[*c++])
2674         return(SMS_BAD_CHAR);
2675
2676     /* uppercase type fields */
2677     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2678
2679 ##  range of a is alias
2680 ##  repeat retrieve (exists = any(a.trans where a.name = @typename and
2681 ##                                    a.type = "TYPE" and
2682 ##                                    a.trans = @value))
2683     if (ingres_errno) return(sms_errcode);
2684     return (exists ? SMS_EXISTS : vo->error);
2685 ##}
2686
2687 /* validate member or type-specific data field */
2688
2689 validate_typedata(q, argv, vo)
2690     register struct query *q;
2691     register char *argv[];
2692     register struct valobj *vo;
2693 ##{
2694 ##  char *name;
2695 ##  char *field_type;
2696 ##  char data_type[129];
2697 ##  int id;
2698 ##  int rowcount;
2699     char *index();
2700     register char *c;
2701
2702     /* get named object */
2703     name = argv[vo->index];
2704
2705     /* get field type string (known to be at index-1) */
2706     field_type = argv[vo->index-1];
2707
2708     /* get corresponding data type associated with field type name */
2709 ##  repeat retrieve (data_type = alias.trans) 
2710 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
2711     if (ingres_errno) return(sms_errcode);
2712 ##  inquire_equel (rowcount = "rowcount")
2713     if (rowcount != 1) return(SMS_TYPE);
2714
2715     /* now retrieve the record id corresponding to the named object */
2716     if (index(data_type, ' '))
2717         *index(data_type, ' ') = 0;
2718     if (!strcmp(data_type, "user")) {
2719         /* USER */
2720 ##      repeat retrieve (id = users.users_id) where users.login = @name
2721 ##      inquire_equel (rowcount = "rowcount")
2722         if (rowcount != 1) return(SMS_USER);
2723
2724     } else if (!strcmp(data_type, "list")) {
2725         /* LIST */
2726 ##      repeat retrieve (id = list.list_id) where list.#name = @name
2727 ##      inquire_equel (rowcount = "rowcount")
2728         if (rowcount != 1) {
2729             /* if idfield is non-zero, then if argv[0] matches the string
2730              * that we're trying to resolve, we should get the value of
2731              * values.[idfield] for the id.
2732              */
2733             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2734                 set_next_object_id(q->validate->object_id, q->rtable);
2735                 name = vo->idfield;
2736 ##              repeat retrieve (id = values.value) where values.#name = @name
2737 ##              inquire_equel(rowcount = "rowcount")
2738                 if (rowcount != 1) return(SMS_LIST);
2739             } else
2740               return(SMS_LIST);
2741         }
2742     } else if (!strcmp(data_type, "machine")) {
2743         /* MACHINE */
2744         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2745 ##      repeat retrieve (id = machine.mach_id) where machine.#name = @name
2746 ##      inquire_equel (rowcount = "rowcount")
2747         if (rowcount != 1) return(SMS_MACHINE);
2748
2749     } else if (!strcmp(data_type, "string")) {
2750         /* STRING */
2751 ##      range of s is strings
2752 ##      repeat retrieve (id = s.string_id) where s.string = @name
2753 ##      inquire_equel (rowcount = "rowcount")
2754         if (rowcount == 0) {
2755             if (q->type != APPEND) return(SMS_STRING);
2756 ##          range of v is values
2757 ##          retrieve (id = v.value) where v.#name = "strings_id"
2758             id++;
2759 ##          replace v (value = id) where v.#name = "strings_id"
2760 ##          append to strings (string_id = id, string = name)
2761         }
2762     } else if (!strcmp(data_type, "none")) {
2763         id = 0;
2764     } else {
2765         return(SMS_TYPE);
2766     }
2767
2768     /* now set value in argv */
2769     *(int *)argv[vo->index] = id;
2770     
2771     return (SMS_EXISTS);
2772 ##}
2773
2774
2775 /* Lock the table named by the validation object */
2776
2777 lock_table(vo)
2778 struct valobj *vo;
2779 ##{
2780 ##  char *table, *idfield;
2781 ##  int rowcount;
2782
2783     table = vo->table;
2784     idfield = vo->idfield;
2785 ##  replace table (modtime = "now") where table.idfield = 0
2786     if (ingres_errno) return(sms_errcode);
2787 ##  inquire_equel (rowcount = "rowcount")
2788     if (rowcount != 1)
2789       return(vo->error);
2790     else
2791       return(SMS_EXISTS);
2792 ##}
2793
2794
2795 /* This looks up a login name and returns the SMS internal ID.  It is used
2796  * by authenticate to put the users_id in the client structure.
2797  */
2798
2799 int get_users_id(name)
2800 char *name;
2801 ##{
2802 ##  int id, rowcount;
2803 ##  char *login;
2804
2805     login = name;
2806
2807 ##  range of u is users
2808 ##  repeat retrieve (id = u.#users_id) where u.#login = @login
2809 ##  inquire_equel (rowcount = "rowcount")
2810     
2811     if (rowcount == 1)
2812         return(id);
2813     else
2814         return(0);
2815 ##}
2816
2817
2818 /* Check the database at startup time.  For now this just resets the
2819  * inprogress flags that the DCM uses.
2820  */
2821
2822 sanity_check_database()
2823 ##{
2824 ##}
This page took 0.256483 seconds and 5 git commands to generate.