]> andersk Git - moira.git/blob - server/qsupport.qc
Mike's changes; checked in prior to working over messages.
[moira.git] / server / qsupport.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *
8  *      $Log$
9  *      Revision 1.6  1987-08-04 01:10:02  wesommer
10  *      Changes by mike; checked in prior to my hacking.
11  *
12 Revision 1.5  87/07/30  14:54:13  wesommer
13 Added debugging code in an attempt to catch a flakey problem.
14
15 Revision 1.4  87/07/30  00:30:21  wesommer
16 replaced appends = appends+1 with appends = tbs.appends+1
17
18 Revision 1.3  87/07/30  00:26:11  wesommer
19 Changes by mike prior to "appends" fix.
20
21 Revision 1.2  87/07/29  16:00:39  wesommer
22 Fixed add_locker.
23
24 Revision 1.1  87/07/29  15:13:57  wesommer
25 Initial revision
26
27  */
28
29 #ifndef lint
30 static char *rcsid_qsupport_qc = "$Header$";
31 #endif lint
32
33 #include "query.h"
34 #include "sms_server.h"
35 #include <ctype.h>
36
37 #define SMS_SUCCESS 0
38
39 extern char *whoami;
40
41 /* Specialized Access Routines */
42
43 /**
44  ** access_user - verify that client name equals specified login name
45  **
46  ** Used by: update_user_shell
47  **          update_finger_by_login
48  **
49  **  - since field validation routines are called first, a users_id is
50  **    now in argv[0] instead of the login name.  Therefore, we must 
51  **    convert the client name to a users_id.
52  **/
53
54 access_user(q, argv, cl)
55     struct query *q;
56     char *argv[];
57     client *cl;
58 ##{
59     register struct krbname *krb;
60 ##  int client_id;
61 ##  char *client_name;
62 ##  int rowcount;
63
64     client_name = cl->kname.name;
65 ##  repeat retrieve (client_id = users.users_id) 
66 ##         where users.login = @client_name
67 ##  inquire_equel (rowcount = "rowcount")
68     if (rowcount != 1) return(SMS_PERM);
69     if (client_id != *(int *)argv[0]) return(SMS_PERM);
70
71     return(SMS_SUCCESS);
72 ##}
73     
74 /**
75  ** access_pop - same as access_user plus verifies that a user has only one
76  **              mailbox of type "POP"
77  **
78  ** Inputs:
79  **   argv[0] - users_id
80  **   argv[1] - type
81  **   argv[2] - mach_id
82  **   argv[3] - box
83  **
84  ** Description:
85  **   - if q->name = "add_pobox" and type = "POP", 
86  **        verify that no POP box already exists for user
87  **   - call access_user
88  **
89  **/
90
91 access_pop(q, argv, cl)
92     struct query *q;
93     char *argv[];
94     client *cl;
95 ##{
96 ##  int users_id;
97 ##  int mach_id;
98 ##  char *box;
99 ##  int exists;
100
101     if (!bcmp(q->name, "add_pobox", 10) && !bcmp(argv[1], "POP", 4)) {
102         users_id = *(int *)argv[0];
103         mach_id = *(int *)argv[2];
104         box = argv[3];
105 ##      range of p is pobox
106 ##      repeat retrieve (exists = any(p.#box where p.#users_id = @users_id
107 ##                                    and p.type = "POP" 
108 ##                                    and p.#mach_id = @mach_id
109 ##                                    and p.#box = @box))
110         if (exists) return(SMS_EXISTS);
111     }
112
113     return(access_user(q, argv, cl));
114 ##}
115
116 /**
117  ** access_list - check access for adding or deleting list members
118  **
119  ** Inputs: argv[0] - list_id
120  **         cl->krb.name - client name
121  **
122  ** - check that client is a member of the access control list
123  ** - OR, if q->shortname == {amtl | dfml} and
124  **       if list.flags & LF_PUBLIC, allow access if client = member
125  **
126  **/ 
127
128 access_list(q, argv, cl)
129     struct query *q;
130     char *argv[];
131     client *cl;
132 ##{
133 ##  int list_id;
134 ##  int acl_id;
135 ##  int flags;
136     int member_id;
137     char *client_type;
138     int client_id;
139     int status;
140     int exists;
141
142     list_id = *(int *)argv[0];
143 ##  repeat retrieve (acl_id = list.#acl_id, flags = list.#flags) 
144 ##         where list.#list_id = @list_id
145
146     /* parse client structure */
147     status = get_client(cl, &client_type, &client_id);
148     if (status != SMS_SUCCESS) return(status);
149
150     /* if amtl or dmfl and list is public allow client to add or delete self */
151     if (!bcmp("amtl", q->shortname, 4) || !bcmp("dmfl", q->shortname, 4)) {
152         if ((flags & LF_PUBLIC) && !bcmp("USER", argv[1], 4)) {
153             member_id = *(int *)argv[2];
154             if (member_id == client_id) return(SMS_SUCCESS);
155         }
156     }
157
158     /* check for client in access control list */
159     exists = find_member(acl_id, client_type, client_id, 0);
160     if (!exists) return(SMS_PERM);
161
162     return(SMS_SUCCESS);
163 ##}
164 \f
165 /**
166  ** Setup routine for add_user
167  **
168  ** Inputs: argv[0] - login
169  **         argv[1] - uid
170  **
171  ** Description:
172  **
173  ** - if argv[1] == "#" then set argv[1] = next(uid)
174  ** - if argv[0] == "#" then set argv[0] = "#<uid>"
175  **
176  **/
177
178 setup_add_user(q, argv, cl, access_check)
179     struct query *q;
180     register char *argv[];
181     client *cl;
182     int access_check;
183 ##{
184 ##  int nuid;
185 ##  int exists;
186
187     if (access_check) return(SMS_SUCCESS);
188
189     if (!bcmp(argv[1], "#", 2)) {
190 ##      range of u is users
191 ##      range of v is values
192 ##      repeat retrieve (nuid = v.value) where v.name = "uid"
193         exists = 1;
194         while (exists) {
195             nuid++;
196 ##          repeat retrieve (exists = any(u.#uid where u.#uid = @nuid))
197         }
198 ##      repeat replace v (value = @nuid) where v.name = "uid"
199         sprintf(argv[1], "%d", nuid);
200     }
201
202     if (!bcmp(argv[0], "#", 2)) {
203         sprintf(argv[0], "#%s", argv[1]);
204     }
205
206     return(SMS_SUCCESS);
207 ##}
208
209 /**
210  ** Setup routine for add_group
211  **
212  ** Inputs: none
213  **
214  ** Description: allocate next gid and store in values table
215  **
216  **/
217
218 setup_add_group(q, argv, cl, access_check)
219     struct query *q;
220     char *argv[];
221     client *cl;
222     int access_check;
223 ##{
224 ##  int ngid;
225 ##  int exists;
226
227     if (access_check) return(SMS_SUCCESS);
228
229 ##  range of g is groups
230 ##  range of v is values
231 ##  repeat retrieve (ngid = v.value) where v.name = "gid"
232     exists = 1;
233     while (exists) {
234         ngid++;
235 ##      repeat retrieve (exists = any(g.#gid where g.#gid = @ngid))
236     }
237
238 ##  repeat replace v (value = @ngid) where v.name = "gid"
239     return(SMS_SUCCESS);
240 ##}
241 \f
242 /**
243  ** setup_add_filesys - verify existance of referenced file systems
244  ** setup_update_filesys - same, except argv[1..5] --> argv[2..6]
245  **
246  ** Inputs:     Add         Update
247  **   argv[0] - label       label
248  **   argv[1] - type        new label
249  **   argv[2] - mach_id     type
250  **   argv[3] - name        mach_id
251  **   argv[4] - mount       name
252  **   argv[5] - access      mount
253  **   argv[6] -             access
254  **
255  ** Description:
256  **   - for type = RVD:
257  **        * verify mach_id/name in rvdvirt
258  **        * verify access in {r, x, R, X}
259  **   - for type = NFS:
260  **        * extract directory prefix from name
261  **        * verify mach_id/dir in nfsphys
262  **        * verify access in {r, w, R, W}
263  **
264  ** Errors:
265  **   SMS_RVD - no such rvd
266  **   SMS_NFS - specified directory not exported
267  **   SMS_FILESYS_ACCESS - invalid filesys access
268  **
269  **/
270
271 setup_add_filesys(q, argv)
272     struct query *q;
273     char *argv[];
274 {
275     char *type;
276     int mach_id;
277     char *name;
278     char *access;  
279
280     type = argv[1];
281     mach_id = *(int *)argv[2];
282     name = argv[3];
283     access = argv[5];
284
285     if (!bcmp(type, "RVD", 3))
286         return (check_rvd(mach_id, name, access));
287     else if (!bcmp(type, "NFS", 3))
288         return (check_nfs(mach_id, name, access));
289     else
290         return(SMS_SUCCESS);
291 }
292
293 setup_update_filesys(q, argv)
294     struct query *q;
295     char *argv[];
296 {
297     char *type;
298     int mach_id;
299     char *name;
300     char *access;  
301
302     type = argv[2];
303     mach_id = *(int *)argv[3];
304     name = argv[4];
305     access = argv[6];
306
307     if (!bcmp(type, "RVD", 3))
308         return (check_rvd(mach_id, name, access));
309     else if (!bcmp(type, "NFS", 3))
310         return (check_nfs(mach_id, name, access));
311     else
312         return(SMS_SUCCESS);
313 }
314
315 ##check_rvd(mach_id, name, access)
316 ##  int mach_id;
317 ##  char *name;
318     char *access;
319 ##{
320 ##  int rowcount;
321     char caccess;
322
323 ##  range of rv is rvdvirt
324 ##  retrieve (rowcount = any(rv.#name where rv.#mach_id = mach_id and
325 ##                           rv.#name = name))
326     if (rowcount == 0) return(SMS_RVD);
327
328     caccess = (isupper(*access)) ? tolower(*access) : *access;
329     if (caccess != 'r' && caccess != 'x') return(SMS_FILESYS_ACCESS);
330
331     return(SMS_SUCCESS);
332 ##}
333
334 ##check_nfs(mach_id, name, access)
335 ##  int mach_id;
336     char *name;
337     char *access;
338 ##{
339 ##  int rowcount;
340 ##  char dir[32];
341     char caccess;
342     register char *cp1;
343     register char *cp2;
344
345     caccess = (isupper(*access)) ? tolower(*access) : *access;
346     if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
347
348 ##  range of np is nfsphys
349 ##  retrieve (dir = np.#dir) where np.#mach_id = mach_id
350 ##  {
351          cp1 = name;
352          cp2 = dir;
353          while (*cp2) {
354              if (*cp1++ != *cp2) break;
355              cp2++;
356          }
357          if (*cp2 == 0) return(SMS_SUCCESS);
358 ##  }
359
360     return(SMS_NFS);
361 ##}
362 \f
363 /* Followup Routines */
364
365 set_user_modtime(q, argv)
366     struct query *q;
367     char *argv[];
368 ##{
369 ##  char *login;
370
371     login = argv[0];
372 ##  repeat replace u (modtime = "now") where u.#login = @login
373     return(SMS_SUCCESS);
374 ##}
375
376 set_user_modtime_by_id(q, argv)
377     struct query *q;
378     char *argv[];
379 ##{
380 ##  int users_id;
381
382     users_id = *(int *)argv[0];
383 ##  repeat replace users (modtime = "now") where users.#users_id = @users_id
384     return(SMS_SUCCESS);
385 ##}
386
387 set_list_modtime(q, argv)
388     struct query *q;
389     char *argv[];
390 ##{
391 ##  char *list_name;
392
393     list_name = argv[0];
394 ##  repeat replace list (modtime = "now") where list.name = @list_name
395     return(SMS_SUCCESS);
396 ##}
397
398 set_list_modtime_by_id(q, argv)
399     struct query *q;
400     char *argv[];
401 ##{
402 ##  int list_id;
403
404     list_id = *(int *)argv[0];
405 ##  repeat replace list (modtime = "now") where list.#list_id = @list_id
406     return(SMS_SUCCESS);
407 ##}
408
409 set_finger_modtime(q, argv)
410     struct query *q;
411     char *argv[];
412 ##{
413 ##  int users_id;
414
415     users_id = *(int *)argv[0];
416 ##  repeat replace f (modtime = "now") where f.#users_id = @users_id
417     return(SMS_SUCCESS);
418 ##}
419
420 /**
421  ** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
422  **
423  ** Inputs:
424  **   q->name - "add_pobox" or "delete_pobox"
425  **   argv[2] - mach_id
426  **
427  ** Description:
428  **   - incr/decr value field in serverhosts table for pop/mach_id
429  **
430  **/
431
432 set_pop_usage(q, argv)
433     struct query *q;
434     char *argv[];
435 ##{
436 ##  int mach_id;
437
438     mach_id = *(int *)argv[2];
439 ##  range of sh is serverhosts
440
441     if (!bcmp(q->name, "add_pobox", 10)) {
442 ##      repeat replace sh (value1 = sh.value1 + 1)
443 ##             where sh.service = "pop" and sh.#mach_id = @mach_id
444     } else if (!bcmp(q->name, "delete_pobox", 13)) {
445 ##      repeat replace sh (value1 = sh.value1 - 1)
446 ##             where sh.service = "pop" and sh.#mach_id = @mach_id
447     }
448
449     return(SMS_SUCCESS);
450 ##}
451
452 /**
453  ** delete_list_members - called after the delete_list query to clean up
454  **                       members table.
455  **
456  ** Inputs: argv[0] - list_id
457  **
458  ** Description:
459  **   - foreach string member: decr string refc; ifzero, delete string
460  **   - delete all members entries for this list_id
461  **
462  **/
463
464 delete_list_members(q, argv)
465     struct query *q;
466     register char *argv[];
467 ##{
468 ##  int list_id;
469 ##  int string_id;
470 ##  int refc;
471 ##  int rowcount;
472     struct save_queue *sq;
473     struct save_queue *sq_create();
474
475     list_id = *(int *)argv[0];
476     sq = sq_create();
477
478 ##  range of m is members
479 ##  repeat retrieve (string_id = m.member_id)
480 ##         where m.#list_id = @list_id and m.member_type = "STRING"
481 ##  {
482          sq_save_data(sq, string_id);
483 ##  }
484
485     while (sq_get_data(sq, &string_id)) {
486 ##      range of s is strings
487 ##      repeat retrieve (refc = s.#refc) where s.#string_id = @string_id
488 ##      inquire_equel (rowcount = "rowcount")
489         if (rowcount == 0) continue;
490         if (--refc == 0) {
491 ##          repeat delete s where s.#string_id = @string_id
492         } else {
493 ##          repeat replace s (#refc = @refc) where s.#string_id = @string_id
494         }
495     }
496     sq_destroy(sq);
497
498 ##  repeat delete m where m.#list_id = @list_id
499
500     return(SMS_SUCCESS);
501 ##}
502
503 /**
504  ** grvd_support - Support routine for get_rvd_servers query
505  **
506  ** Inputs:
507  **    q     - grvd query structure
508  **    sq    - save_queue struture: contains list of {machine, oper_acl_id,
509  **            admin_acl_id, shutdown_acl_id} records.
510  **    v     - validate structure (not used)
511  **    action - action routine
512  **    actarg - action routine argument
513  **
514  ** Description:
515  **   - translate acl_ids to list names
516  **
517  **/
518
519 grvd_support(q, sq, v, action, actarg)
520     struct query *q;
521     struct save_queue *sq;
522     struct validate *v;
523     int (*action)();
524     int actarg;
525 ##{
526     char **argv;
527     char *targv[4];
528 ##  char oper[33];
529 ##  char admin[33];
530 ##  char shutdown[33];
531 ##  int list_id;
532
533     targv[0] = oper;
534     targv[1] = admin;
535     targv[2] = shutdown;
536
537 ##  range of l is list
538
539     while (sq_get_data(sq, &argv)) {
540         sscanf(argv[0], "%d", &list_id);
541 ##      repeat retrieve (oper = l.name) where l.#list_id = @list_id
542         sscanf(argv[1], "%d", &list_id);
543 ##      repeat retrieve (admin = l.name) where l.#list_id = @list_id
544         sscanf(argv[2], "%d", &list_id);
545 ##      repeat retrieve (shutdown = l.name) where l.#list_id = @list_id
546         
547         (*action)(3, targv, actarg);
548         free(argv[0]);
549         free(argv[1]);
550         free(argv[2]);
551     }
552
553     sq_destroy(sq);
554     return(SMS_SUCCESS);
555 ##}
556
557 /**
558  ** set_next_object_id - set next object id in values table
559  **
560  ** Inputs: object - object name in values table
561  **
562  ** - called before an APPEND operation to set the next object id to
563  **   be used for the new record
564  **
565  **/
566
567 set_next_object_id(object)
568     char *object;
569 ##{
570 ##  char *name;
571
572     name = object;
573 ##  range of v is values
574 ##  repeat replace v (value = v.value + 1) where v.#name = @name
575     return(SMS_SUCCESS);
576 ##}
577
578 /**
579  ** get_query_need - check modtime of query's associated table against given
580  **                  time and return true if greater (false if not)
581  **
582  ** Inputs:
583  **   argv[0] - query name
584  **   argv[1] - time to compare against
585  **
586  **/
587
588 get_query_need(q, argv, action, actarg)
589     struct query *q;
590     register char *argv[];
591     int (*action)();
592 ##{
593     struct query *q1;
594 ##  char *last_get_time;
595 ##  char *table;
596 ##  int need;
597     char *result;
598     struct query *get_query_by_name();
599
600     q1 = get_query_by_name(argv[0]);
601
602     last_get_time = argv[1];
603     table = q1->rtable;
604
605     if (q1->type != RETRIEVE || table == (char *)0) return(SMS_NO_MATCH);
606
607 ##  range of tbs is tblstats
608 ##  repeat retrieve (need = any(tbs.modtime where tbs.#table = @table and
609 ##                              tbs.modtime > @last_get_time))
610     
611     result = (need) ? "true" : "false";
612     (*action)(1, &result, actarg);
613     return(SMS_SUCCESS);
614 ##}
615
616 \f
617 /**
618  ** add_locker - special query routine for creating a user locker
619  **
620  ** Inputs:
621  **   argv[0] - users_id
622  **   argv[1] - machine_id
623  **   argv[2] - device
624  **   argv[3] - initial quota
625  ** 
626  ** Description:
627  **   - get prefix directory (dir) for mount point on specified machine/device
628  **   - create filesys entry (label=<login>, type=NFS, machine=<machine>,
629  **     mount=<dir>/<login>, access=w, acl=dbadmin)
630  **   - increment allocated in nfsphys by quota
631  **   - create nfsquota entry
632  **
633  ** Errors:
634  **   - SMS_NFSPHYS - machine/device does not exist in nfsphys
635  **   - SMS_FILESYS_EXISTS - file system already exists
636  ** 
637  **/
638
639 add_locker(q, argv)
640     register struct query *q;
641     char *argv[];
642 ##{
643 ##  int users_id;
644 ##  int mach_id;
645 ##  char *device;
646 ##  int quota;
647 ##  int rowcount;
648 ##  char login[9];
649 ##  char dir[32];
650 ##  int allocated;
651 ##  char locker[64];
652 ##  char mount[64];
653 ##  int user_acl;
654
655     /* copy arguments */
656     users_id = *(int *)argv[0];
657     mach_id = *(int *)argv[1];
658     device = argv[2];
659     sscanf(argv[3], "%d", &quota);
660
661 ##  range of u is users
662 ##  range of f is filesys
663 ##  range of np is nfsphys
664 ##  range of tbs is tblstats
665
666     /* get login name */
667 ##  repeat retrieve (login = u.#login) where u.#users_id = @users_id
668
669     /* get user's acl id */
670 ##  repeat retrieve (user_acl = list.list_id) where list.name = @login
671
672     /* get filesystem directory prefix; give error if machine/device
673        pair not in nfsphys table */
674     printf("np.mach_id = %d and np.device = %s\n", mach_id, device);
675     
676 ##  repeat retrieve (dir = np.#dir, allocated = np.#allocated) 
677 ##         where np.#mach_id = @mach_id and np.#device = device
678 ##  inquire_equel (rowcount = "rowcount")
679     if (rowcount == 0) return(SMS_NFSPHYS);
680
681     /* make sure a filesys with user's name does not already exist */
682 ##  repeat retrieve (rowcount = any(f.label where f.label = @login))
683     if (rowcount != 0) return(SMS_FILESYS_EXISTS);
684
685     /* create a new filesys */
686     sprintf(locker, "%s/%s", dir, login);
687     sprintf(mount, "/mit/%s", login);
688 ##  repeat append filesys 
689 ##             (#label = @login, type = "NFS", #mach_id = @mach_id,
690 ##              name = @locker, access = "w", order = 1, #mount = @mount,
691 ##              acl_id = @user_acl)
692 ##  repeat replace tbs (appends = tbs.appends + 1, modtime = "now")
693 ##             where tbs.table = "filesys"
694
695     /* increment usage count in nfsphys table */
696     allocated += quota;
697 ##  replace np (#allocated = allocated) 
698 ##          where np.#mach_id = mach_id and np.#device = device
699 ##  repeat replace tbs (updates = tbs.updates + 1, modtime = "now")
700 ##             where tbs.table = "nfsphys"
701
702     /* create nfsquota entry */
703 ##  append nfsquota (#users_id = users_id, #mach_id = mach_id,
704 ##                   #device = device, #quota = quota)
705 ##  repeat replace tbs (appends = tbs.appends + 1, modtime = "now")
706 ##             where tbs.table = "nfsquota"
707
708     return(SMS_SUCCESS);
709 ##}
710
711 /**
712  ** delete_locker - special query routine for deleting a user locker
713  **
714  ** Inputs:
715  **   argv[0] - users_id
716  **   argv[1] - machine_id
717  **   argv[2] - device
718  **   argv[3] - quota
719  ** 
720  ** Description:
721  **   - delete filesys entry (label=<login>)
722  **   - decrement allocated in nfsphys by quota
723  **   - delete nfsquota entry
724  **
725  ** Errors:
726  **   - SMS_FILESYS - no filesys exists for user
727  ** 
728  **/
729
730 delete_locker(q, argv)
731     register struct query *q;
732     register char *argv[];
733 ##{
734 ##  int users_id;
735 ##  int mach_id;
736 ##  char *device;
737 ##  int quota;
738 ##  int rowcount;
739 ##  char login[9];
740
741     /* copy arguments */
742     users_id = *(int *)argv[0];
743     mach_id = *(int *)argv[1];
744     device = argv[2];
745     sscanf(argv[3], "%d", &quota);
746
747 ##  range of u is users
748 ##  range of f is filesys
749 ##  range of np is nfsphys
750 ##  range of nq is nfsquota
751 ##  range of tbs is tblstats
752
753     /* get login name */
754 ##  repeat retrieve (login = u.#login) where u.#users_id = @users_id
755
756     /* delete the filesys entry */
757 ##  repeat delete f where f.label = @login
758 ##  inquire_equel (rowcount = "rowcount")
759     if (rowcount == 0) return(SMS_FILESYS);
760 ##  repeat replace tbs (deletes = tbs.deletes + 1, modtime = "now")
761 ##             where tbs.table = "filesys"
762
763     /* decrement usage count in nfsphys table */
764 ##  replace np (#allocated = np.#allocated - quota) 
765 ##          where np.#mach_id = mach_id and np.#device = device
766 ##  repeat replace tbs (updates = tbs.updates + 1, modtime = "now")
767 ##             where tbs.table = "nfsphys"
768
769     /* delete nfsquota entry */
770 ##  delete nq where nq.#users_id = users_id and nq.#mach_id = mach_id and
771 ##                  nq.#device = device
772 ##  repeat replace tbs (deletes = tbs.deletes + 1, modtime = "now")
773 ##             where tbs.table = "nfsquota"
774
775     return(SMS_SUCCESS);
776 ##}
777 \f
778 /**
779  ** get_members_of_list - optimized query for retrieval of list members
780  **
781  ** Inputs:
782  **   argv[0] - list_id
783  **
784  ** Description:
785  **   - retrieve USER members, then LIST members, then STRING members
786  **
787  **/
788
789 get_members_of_list(q, argv, action, actarg)
790     struct query *q;
791     char *argv[];
792     int (*action)();
793     int actarg;
794 ##{
795 ##  int list_id;
796 ##  char member_name[129];
797     char *targv[2];
798
799     list_id = *(int *)argv[0];
800     targv[0] = "USER";
801     targv[1] = member_name;
802
803 ##  range of m is members
804 ##  repeat retrieve (member_name = users.login)
805 ##             where m.#list_id = @list_id and m.member_type = "USER"
806 ##                   and m.member_id = users.users_id
807 ##  {
808          (*action)(2, targv, actarg);
809 ##  }
810
811     targv[0] = "LIST";
812 ##  repeat retrieve (member_name = list.name)
813 ##             where m.#list_id = @list_id and m.member_type = "LIST"
814 ##                   and m.member_id = list.#list_id
815 ##  {
816          (*action)(2, targv, actarg);
817 ##  }
818
819     targv[0] = "STRING";
820 ##  repeat retrieve (member_name = strings.string)
821 ##             where m.#list_id = @list_id and m.member_type = "STRING"
822 ##                   and m.member_id = strings.string_id
823 ##  {
824          (*action)(2, targv, actarg);
825 ##  }
826
827     return(SMS_SUCCESS);
828 ##}
829
830 /**
831  ** get_all_poboxes - optimize query for retrieval of all poboxes
832  **
833  ** Description:
834  **   - retrieve LOCAL boxes, then POP boxes, then FOREIGN boxes
835  **
836  **/
837
838 get_all_poboxes(q, argv, action, actarg)
839     struct query *q;
840     char *argv[];
841     int (*action)();
842     int actarg;
843 ##{
844 ##  char login[9];
845 ##  char machine[129];
846 ##  char box[129];
847     char *targv[4];
848
849     targv[0] = login;
850     targv[2] = machine;
851     targv[3] = box;
852
853     targv[1] = "LOCAL";
854 ##  range of p is pobox
855 ##  repeat retrieve (login=users.#login, machine = #machine.name, box=p.#box)
856 ##             where p.type = "LOCAL" and p.users_id = users.users_id
857 ##                   and p.mach_id = #machine.mach_id
858 ##  {
859          (*action)(4, targv, actarg);
860 ##  }
861
862     targv[1] = "POP";
863 ##  repeat retrieve (login=users.#login, machine = #machine.name, box=p.#box)
864 ##             where p.type = "POP" and p.users_id = users.users_id
865 ##                   and p.mach_id = #machine.mach_id
866 ##  {
867          (*action)(4, targv, actarg);
868 ##  }
869
870     targv[1] = "FOREIGN";
871 ##  repeat retrieve (login=users.#login, machine=strings.string, box=p.#box)
872 ##             where p.type = "FOREIGN" and p.users_id = users.users_id
873 ##                   and p.mach_id = strings.string_id
874 ##  {
875          (*action)(4, targv, actarg);
876 ##  }
877
878     return(SMS_SUCCESS);
879 ##}
880 \f
881 /* Validation Routines */
882
883 validate_row(q, argv, v)
884     register struct query *q;
885     char *argv[];
886     register struct validate *v;
887 ##{
888 ##  char *rvar;
889 ##  char *table;
890 ##  char *name;
891 ##  char qual[128];
892 ##  int rowcount;
893
894     /* build where clause */
895     build_qual(v->qual, v->argc, argv, qual);
896
897     /* setup ingres variables */
898     rvar = q->rvar;
899     table = q->rtable;
900     name = v->field;
901
902     /* tell the logfile what we're doing */
903     com_err(whoami, 0, "validating row");
904     com_err(whoami, 0, qual);
905
906     /* look for the record */
907 ##  range of rvar is table
908 ##  retrieve (rowcount = count(rvar.name where qual))
909     com_err(whoami, 0, "row validated");
910     if (rowcount == 0) return(SMS_NO_MATCH);
911     if (rowcount > 1) return(SMS_NOT_UNIQUE);
912     return(SMS_EXISTS);
913 ##}
914
915 validate_fields(q, argv, vo, n)
916     struct query *q;
917     register char *argv[];
918     register struct valobj *vo;
919     register int n;
920 {
921     register int status;
922     char buf[64];
923
924     while (--n >= 0) {
925         switch (vo->type) {
926         case V_NAME:
927             sprintf(buf, "validating %s in %s: %s", 
928                     vo->namefield, vo->table, argv[vo->index]);
929             com_err(whoami, 0, buf);
930             status = validate_name(argv, vo);
931             break;
932
933         case V_ID:
934             sprintf(buf, "validating %s in %s: %s", 
935                     vo->idfield, vo->table, argv[vo->index]);
936             com_err(whoami, 0, buf);
937             status = validate_id(argv, vo);
938             break;
939
940         case V_TYPE:
941             sprintf(buf, "validating %s type: %s",
942                     vo->table, argv[vo->index]);
943             com_err(whoami, 0, buf);
944             status = validate_type(argv, vo);
945             break;
946
947         case V_TYPEDATA:
948             sprintf(buf, "validating type-specific data: %s",
949                     argv[vo->index]);
950             com_err(whoami, 0, buf);
951             status = validate_typedata(q, argv, vo);
952             break;
953
954         case V_FOLLOWUP:
955             status = SMS_EXISTS;
956             break;
957
958         }
959
960         if (status != SMS_EXISTS) return(status);
961         vo++;
962     }
963
964     return(SMS_SUCCESS);
965 }
966
967 validate_id(argv, vo)
968     char *argv[];
969     register struct valobj *vo;
970 ##{
971 ##  char *name;
972 ##  char *table;
973 ##  char *namefield;
974 ##  char *idfield;
975 ##  int id;
976 ##  int rowcount;
977
978     name = argv[vo->index];
979     table = vo->table;
980     namefield = vo->namefield;
981     idfield = vo->idfield;
982 ##  retrieve (id = table.idfield) where table.namefield = name
983 ##  inquire_equel (rowcount = "rowcount")
984     if (rowcount != 1) return(vo->error);
985     *(int *)argv[vo->index] = id;
986     return(SMS_EXISTS);
987 ##}
988
989 validate_name(argv, vo)
990     char *argv[];
991     register struct valobj *vo;
992 ##{
993 ##  char *name;
994 ##  char *table;
995 ##  char *namefield;
996 ##  int rowcount;
997
998     name = argv[vo->index];
999     table = vo->table;
1000     namefield = vo->namefield;
1001 ##  retrieve (rowcount = countu(table.namefield 
1002 ##            where table.namefield = name))
1003     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
1004 ##}
1005
1006 validate_type(argv, vo)
1007     char *argv[];
1008     register struct valobj *vo;
1009 ##{
1010 ##  char *typename;
1011 ##  char *value;
1012 ##  int rowcount;
1013     register char *c;
1014
1015     typename = vo->table;
1016     value = argv[vo->index];
1017
1018     /* uppercase type fields */
1019     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
1020
1021 ##  range of a is alias
1022 ##  repeat retrieve (rowcount = count(a.trans where a.name = @typename and
1023 ##                                    a.type = "TYPE" and
1024 ##                                    a.trans = @value))
1025     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
1026 ##}
1027
1028 /* validate member or type-specific data field */
1029
1030 validate_typedata(q, argv, vo)
1031     register struct query *q;
1032     register char *argv[];
1033     register struct valobj *vo;
1034 ##{
1035 ##  char *name;
1036 ##  char *field_type;
1037 ##  char data_type[17];
1038 ##  int id;
1039 ##  int refc;
1040 ##  int rowcount;
1041
1042     /* get named object */
1043     name = argv[vo->index];
1044
1045     /* get field type string (known to be at index-1) */
1046     field_type = argv[vo->index-1];
1047
1048     /* get corresponding data type associated with field type name */
1049 ##  repeat retrieve (data_type = alias.trans) 
1050 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
1051 ##  inquire_equel (rowcount = "rowcount")
1052     if (rowcount != 1) return(SMS_TYPE);
1053
1054     /* now retrieve the record id corresponding to the named object */
1055
1056     if (!strcmp(data_type, "user")) {
1057         /* USER */
1058 ##      repeat retrieve (id = users.users_id) where users.login = @name
1059 ##      inquire_equel (rowcount = "rowcount")
1060         if (rowcount != 1) return(SMS_USER);
1061
1062     } else if (!strcmp(data_type, "list")) {
1063         /* LIST */
1064 ##      repeat retrieve (id = list.list_id) where list.#name = @name
1065 ##      inquire_equel (rowcount = "rowcount")
1066         if (rowcount != 1) return(SMS_LIST);
1067
1068     } else if (!strcmp(data_type, "machine")) {
1069         /* MACHINE */
1070 ##      repeat retrieve (id = machine.mach_id) where machine.#name = @name
1071 ##      inquire_equel (rowcount = "rowcount")
1072         if (rowcount != 1) return(SMS_MACHINE);
1073
1074     } else if (!strcmp(data_type, "string")) {
1075         /* STRING */
1076 ##      range of s is strings
1077 ##      repeat retrieve (id = s.string_id, refc = s.#refc) 
1078 ##             where s.string = @name
1079 ##      inquire_equel (rowcount = "rowcount")
1080         if (rowcount == 0) {
1081             if (q->type != APPEND) return(SMS_STRING);
1082 ##          range of v is values
1083 ##          retrieve (id = v.value) where v.#name = "strings_id"
1084             id++;
1085 ##          replace v (value = id) where v.#name = "strings_id"
1086 ##          append to strings (string_id = id, string = name, #refc = 1)
1087         } else if (rowcount == 1) {
1088             if (q->type == APPEND || q->type == DELETE) {
1089                 refc += (q->type == APPEND) ? 1 : -1;
1090                 if (refc > 0) {
1091 ##                  replace s (#refc = refc) where s.string_id = id
1092                 } else {
1093 ##                  delete s where s.string_id = id
1094                 }
1095             }
1096         }
1097     } else {
1098         return(SMS_TYPE);
1099     }
1100
1101     /* now set value in argv */
1102     *(int *)argv[vo->index] = id;
1103     
1104     return (SMS_EXISTS);
1105 ##}
1106
1107 \f
1108 translate_ids(q, sq, v, action, actarg)
1109     register struct query *q;
1110     register struct save_queue *sq;
1111     register struct validate *v;
1112     register int (*action)();
1113     int actarg;
1114 ##{
1115 ##  char *name;
1116 ##  char *field_type;
1117 ##  char data_type[17];
1118 ##  int id;
1119 ##  int rowcount;
1120     register int i;
1121     struct valobj *vo;
1122     char **argv;
1123
1124     for (i = 0; i < v->objcnt; i++) {
1125         vo = &v->valobj[i];
1126         if (vo->type == V_FOLLOWUP) break;
1127     }
1128
1129     /* for each row */
1130     while (sq_get_data(sq, &argv)) {
1131
1132         /* get object id */
1133         i = vo->index;
1134         sscanf(argv[i], "%d", &id);
1135         free(argv[i]);
1136         name = (char *)malloc(129);
1137         argv[i] = name;
1138
1139         /* get field type string (known to be at index-1) */
1140         field_type = argv[vo->index-1];
1141
1142         /* get corresponding data type associated with field type name */
1143 ##      repeat retrieve (data_type = alias.trans) 
1144 ##             where alias.#name = @field_type and alias.type = "TYPEDATA"
1145 ##      inquire_equel (rowcount = "rowcount")
1146         if (rowcount != 1) {
1147             sprintf(name, "%d", id);
1148             (*action)(q->vcnt, argv, actarg);
1149             continue;
1150         }
1151
1152         /* retrieve object name */
1153
1154         if (!strcmp(data_type, "user")) {
1155             /* USER */
1156 ##          repeat retrieve (name = users.login) where users.users_id = @id
1157 ##          inquire_equel (rowcount = "rowcount")
1158
1159         } else if (!strcmp(data_type, "list")) {
1160             /* LIST */
1161 ##          repeat retrieve (name = list.#name) where list.list_id = @id
1162 ##          inquire_equel (rowcount = "rowcount")
1163
1164         } else if (!strcmp(data_type, "machine")) {
1165             /* MACHINE */
1166 ##          repeat retrieve (name = machine.#name) where machine.mach_id = @id
1167 ##          inquire_equel (rowcount = "rowcount")
1168
1169         } else if (!strcmp(data_type, "string")) {
1170             /* STRING */
1171 ##          repeat retrieve (name = strings.string) 
1172 ##                 where strings.string_id = @id
1173 ##          inquire_equel (rowcount = "rowcount")
1174
1175         } else {
1176             rowcount = 0;
1177         }
1178
1179         /* if there wasn't a corresponding object name, then use the id */
1180         if (rowcount != 1) sprintf(name, "%d", id);
1181
1182         /* send the data */
1183         (*action)(q->vcnt, argv, actarg);
1184
1185         /* free saved data */
1186         for (i = 0; i < q->vcnt; i++) 
1187             free(argv[i]);
1188         free(argv);
1189     }
1190
1191     sq_destroy(sq);
1192     return (SMS_SUCCESS);
1193 ##}
1194 \f
1195 /*
1196  * Local Variables:
1197  * mode: c
1198  * c-indent-level: 4
1199  * c-continued-statement-offset: 4
1200  * c-brace-offset: -4
1201  * c-argdecl-indent: 4
1202  * c-label-offset: -4
1203  * End:
1204  */
This page took 0.142886 seconds and 5 git commands to generate.