]> andersk Git - moira.git/blob - clients/mailmaint/mailmaint.c
reversed the default of a yes-or-no question;
[moira.git] / clients / mailmaint / mailmaint.c
1 /*
2  *      $Source$
3  *      $Header$
4  */
5
6 #ifndef lint
7 static char rcsid_mailmaint_c[] = "$Header$";
8 #endif lint
9
10 /***********************************************************************/
11 /*  mailmaint.c - pjlevine - 20 August 1987 
12     
13 */
14 /***********************************************************************/
15 #include <stdio.h>
16 #include <pwd.h>
17 #include <menu.h>
18 #include <signal.h>
19 #include <strings.h>
20 #include <curses.h>
21 #include <sys/types.h>
22 #include <ctype.h>
23 #include "mit-copyright.h"
24
25 #define STARTCOL 0
26 #define STARTROW 3
27 #define SECONDCOL 30
28 #define DISPROW 15
29 #define LISTMAX 50
30 #define LISTSIZE 32
31 #define CTL(ch)  ((ch) & 037)
32 #define MAX(A,B) ((A) > (B) ? (A) : (B))
33
34 static char *whoami;
35 static int status;
36 static void scream();
37 extern char *strsave();
38
39 typedef struct list_info {
40     char *acl;
41     char *desc;
42     char *expdate;
43 }         List_info;
44
45 static char *ascbuff = {"0123456789"};
46 static int 
47 print_2(), print_1();
48 static List_info *current_li = (List_info *) NULL;
49 static int get_list_info();
50 static int fetch_list_info();
51
52 char *malloc();
53 char *rindex();
54 char *getlogin();
55 extern char *strsave();
56 char *getenv();
57 char *calloc();
58
59 uid_t getuid();
60
61 typedef struct _menu {
62     int num_items;
63     char *title;
64     char **items;
65 }     MENU;
66
67 MENU *main_menu, *help_menu;
68
69 int position[2], oldpos[2];
70 int level, found_some, currow, page, num_members;
71 int moreflg, toggle, first_time;
72 char *uname;
73
74
75 /****************************************************/
76 /*ARGSUSED*/
77 main(argc, argv)
78     int argc;
79     char *argv[];
80
81 {
82
83     int use_menu = 1;
84     char buf[BUFSIZ];
85
86     init_sms_err_tbl();
87     init_krb_err_tbl();
88
89     if ((whoami = rindex(argv[0], '/')) == NULL)
90         whoami = argv[0];
91     else
92         whoami++;
93     uname = calloc(20, 1);
94     if ((current_li = (List_info *) malloc(sizeof(List_info)))
95         == (List_info *) NULL) {
96         (void) sprintf(buf, ": allocating list info");
97         goto punt;
98     }
99     else {
100         current_li->acl = (char *) NULL;
101         current_li->desc = (char *) NULL;
102         current_li->expdate = (char *) NULL;
103     }
104     if ((uname = getlogin()) == NULL) {
105         struct passwd *getpwuid();
106
107         uname = getpwuid((int) getuid())->pw_name;
108     }
109     uname = (uname && strlen(uname)) ? strsave(uname) : "";
110
111     printf("Connecting to database for %s...please hold on.\n", uname);
112
113     status = sms_connect();
114     if (status) {
115         (void) sprintf(buf, "\nConnection to SMS server failed");
116         goto punt;
117     }
118
119     status = sms_auth();
120     if (status) {
121         (void) sprintf(buf, "\nAuthorization failed.\n");
122         goto punt;
123     }
124
125     if (use_menu) {
126         (void) initscr();
127         if ((LINES < 24) || (COLS < 60)) {
128             Put_message("Display window too small.\n\n");
129             (void) sprintf(buf, "Current window parameters are (%d \
130 lines, %d columns)\n", LINES, COLS);
131             Put_message(buf);
132             Put_message("Please resize your window\n");
133             Put_message("to at least 24 lines and 60 columns.\n");
134             exit(0);
135         }
136         raw();
137         noecho();
138         position[0] = oldpos[0] = 1;
139         level = 0;
140         pack_main_menu();
141         pack_help_menu();
142         display_menu(main_menu);
143         get_main_input();
144         cls();
145         endwin();
146     }
147     exit(0);
148
149 punt:
150     com_err(whoami, status, buf);
151     exit(1);
152 }
153
154 /****************************************************/
155 get_main_input()
156 {
157     int c;
158     int retflg;
159
160     while (1) {
161         oldpos[level] = position[level];
162         retflg = 0;
163         currow = DISPROW + 2;
164         page = 1;
165         toggle = num_members = moreflg = 0;
166         c = getchar();
167         if (c == 13) {
168             if (position[level] == 7)
169                 c = 'q';
170             else
171                 c = ascbuff[position[level]];
172             retflg = 1;
173         }
174         switch (c) {
175         case 'L' & 037: /* clear screen */
176             display_menu(main_menu);
177             break;
178         case 'q':
179         case 'Q':               /* quit */
180             position[level] = 7;
181             highlight(main_menu);
182             if (retflg) {
183                 cls();
184                 return;
185             }
186             break;
187         case '1':               /* show all lists */
188             position[level] = 1;
189             if (retflg) {
190                 show_all();
191             }
192             break;
193         case '2':               /* get all members of a list */
194             position[level] = 2;
195             if (retflg) {
196                 (void) list_members();
197             }
198             break;
199         case '3':               /* display list which user is a recipient */
200             position[level] = 3;
201             if (retflg) {
202                 list_by_member();
203             }
204             break;
205         case '4':               /* show description */
206             position[level] = 4;
207             if (retflg) {
208                 show_list_info();
209             }
210             break;
211         case '5':               /* add to list */
212             position[level] = 5;
213             if (retflg) {
214                 add_member();
215             }
216             break;
217         case '6':               /* delete */
218             position[level] = 6;
219             if (retflg) {
220                 delete_member();
221             }
222             break;
223         case 27:                /* up arrow */
224             c = getchar();
225             if (c == 91) {
226                 c = getchar();
227                 if (c == 65) {
228                     position[level]--;
229                     if (!position[level])
230                         position[level] = 7;
231                 }
232                 else {
233                     if (c == 66) {
234                         position[level]++;
235                         if (position[level] > 7)
236                             position[level] = 1;
237                     }
238                 }
239             }
240             break;
241         default:
242             printf("%c", 7);
243             break;
244         }
245         highlight(main_menu);
246     }
247 }
248
249 /****************************************************/
250 show_list_info()
251 {
252     char *buf;
253     char c;
254
255     show_text(DISPROW, STARTCOL, "Show information about a list.\n\r");
256     buf = calloc((unsigned)1024, 1);
257     if (Prompt("Enter List Name: ", buf, LISTSIZE) == 1) {
258         Put_message("\n\r");
259         if (fetch_list_info(buf, current_li) == 0) {
260             (void) sprintf(buf, "Description: %s\n\r", current_li->desc);
261             if (strlen(buf) > 60)
262                 (void) display_buff(buf);
263             else
264                 show_text(currow, STARTCOL, buf);
265             currow++;
266             (void) sprintf(buf, "List Administrator: %s", current_li->acl);
267             show_text(currow, STARTCOL, buf);
268             currow++;
269             (void) sprintf(buf, "Expiration date: %s", current_li->expdate);
270             show_text(currow, STARTCOL, buf);
271             currow++;
272         }
273         else {
274             show_text(currow, STARTCOL, "madm: No such list found.");
275             currow++;
276         }
277         show_text(currow, STARTCOL, "Press any Key to continue...");
278         (void) getchar();
279     }
280     clrwin(DISPROW);
281 }
282
283 /****************************************************/
284 display_buff(buf)
285     char *buf;
286 {
287     int i, cnt;
288     char *printbuf;
289     int maxcol;
290
291     maxcol = COLS;
292     if (maxcol >= 80)
293         maxcol = 80;
294
295     cnt = 0;
296     printbuf = calloc((unsigned)maxcol, 1);
297     for (i = 0; i <= strlen(buf); i++) {
298         printbuf[cnt] = buf[i];
299         cnt++;
300         if (cnt >= maxcol) {
301             (void) start_display_buff(printbuf);
302             cnt = 0;
303             free(printbuf);
304             printbuf = calloc((unsigned)maxcol, 1);
305         }
306     }
307     if (strlen(buf) % maxcol != 0) {
308         (void) start_display_buff(printbuf);
309         free(printbuf);
310     }
311     return (0);
312 }
313
314 /****************************************************/
315 start_display_buff(buff)
316     char *buff;
317 {
318     char buffer[5];
319
320     num_members++;
321     if (moreflg)
322         return (0);
323     if (currow >= LINES - 2) {
324         page++;
325         currow++;
326         mvcur(0, 0, currow, STARTCOL);
327         refresh();
328         if (Prompt("--RETURN for more, ctl-c to exit--", buffer, 1) == 0) {
329             Put_message("Flushing query...");
330             moreflg = 1;
331             return (0);
332         }
333         clrwin(DISPROW + 2);
334         currow = DISPROW + 2;
335         show_text(currow, STARTCOL, "continued");
336         currow++;
337     }
338     show_text(currow, STARTCOL, buff);
339     currow++;
340     return (0);
341 }
342
343 /****************************************************/
344 add_member()
345 {
346     static char *argv[] = {
347         "add_member_to_list",
348         0,
349         0,
350         0
351         };
352     char *buf;
353     char c;
354
355     show_text(DISPROW, STARTCOL, "Add yourself to a list\n\r");
356     buf = calloc(LISTMAX, 1);
357     if (Prompt("Enter List Name: ", buf, LISTSIZE) == 1) {
358         Put_message("\r\n");
359         argv[1] = strsave(buf);
360         argv[2] = strsave("user");
361         argv[3] = strsave(uname);
362         if (status = sms_query_internal(3, argv, scream, (char *) NULL)) {
363             Put_message("\r\n");
364             com_err(whoami, status, " found.\n");
365         }
366         else {
367             (void) sprintf(buf, "User %s added to list\r", uname);
368             show_text(DISPROW + 3, STARTCOL, buf);
369         }
370         currow = DISPROW + 4;
371         show_text(DISPROW + 4, STARTCOL, "Press any Key to continue...");
372         (void) getchar();
373     }
374     clrwin(DISPROW);
375 }
376
377 /****************************************************/
378 delete_member()
379 {
380     static char *argv[] = {
381         "delete_member_from_list",
382         0,
383         0,
384         0
385         };
386     char *buf;
387     char c;
388
389     show_text(DISPROW, STARTCOL, "Remove yourself from a list\n\r");
390     buf = calloc(LISTMAX, 1);
391     if (Prompt("Enter List Name: ", buf, LISTSIZE) == 1) {
392         Put_message("\r\n");
393         argv[1] = strsave(buf);
394         argv[2] = strsave("user");
395         argv[3] = strsave(uname);
396         if (status = sms_query_internal(3, argv, scream, (char *) NULL)) {
397             Put_message("\r\n");
398             com_err(whoami, status, " found.\n");
399         }
400         else {
401             (void) sprintf(buf, "User %s deleted from list\r", uname);
402             show_text(DISPROW + 3, STARTCOL, buf);
403         }
404         currow = DISPROW + 4;
405         show_text(DISPROW + 4, STARTCOL, "Press any Key to continue...");
406         (void) getchar();
407     }
408     clrwin(DISPROW);
409 }
410
411 /****************************************************/
412 list_by_member()
413 {
414     char *nargv[3];
415     char *buf;
416     char c;
417
418     nargv[1] = strsave("user");
419     nargv[2] = strsave(uname);
420     buf = calloc(BUFSIZ, 1);
421     (void) sprintf(buf, "%s is on the following lists:\r", uname);
422     show_text(DISPROW, STARTCOL, buf);
423     mvcur(0, 0, currow, STARTCOL);
424     refresh();
425     if (status = sms_query("get_lists_of_member", 2, nargv + 1,
426                            print_1, (char *) NULL)) {
427         Put_message("\r\n");
428         com_err(whoami, status, " in get_lists_of_member");
429     }
430     show_text(currow, STARTCOL, "Press any Key to continue...");
431     (void) getchar();
432     clrwin(DISPROW);
433     return;
434 }
435
436 /****************************************************/
437 show_all()
438 {
439     char c;
440
441     show_text(DISPROW, STARTCOL, "This function may take a \
442 while... proceed? [y] ");
443     c = getchar();
444     if (c == 'y' || c == 'Y') {
445         move(DISPROW + 1, STARTCOL);
446         addstr("Processing query...please hold");
447         refresh();
448         (void) list_all_groups();
449     }
450     else
451         erase_line(DISPROW, STARTCOL);
452     return;
453
454 }
455
456 /****************************************************/
457 /*ARGSUSED*/
458 static int
459 print_1(argc, argv, callback)
460     int argc;
461     char *argv[], *callback;
462 {
463     char buf[BUFSIZ];
464
465     /* no newline 'cause Put_message adds one */
466     (void) sprintf(buf, "%s\r", argv[0]);
467     (void) start_display(buf);
468
469     return (0);
470 }
471
472 /****************************************************/
473 /*ARGSUSED*/
474 static int
475 print_all(argc, argv, callback)
476     int argc;
477     char *argv[], *callback;
478 {
479     char buf[BUFSIZ];
480
481     if (moreflg)
482         return (0);
483     if (first_time) {
484         erase_line(DISPROW + 1, STARTCOL);
485         show_text(DISPROW + 1, STARTCOL, "All mailing lists:");
486         first_time = 0;
487     }
488     (void) sprintf(buf, "%s\r", argv[0]);
489     (void) start_display(buf);
490
491     return (0);
492 }
493
494 /****************************************************/
495 list_all_groups()
496 {
497
498     first_time = 1;
499     if (status = sms_query("get_all_visible_maillists", 0, (char **) NULL,
500                            print_all, (char *) NULL)) {
501         Put_message("\r\n");
502         com_err(whoami, status, " in list_all_groups\n");
503     }
504     end_display();
505
506     return (DM_NORMAL);         /* HA! */
507 }
508
509 /****************************************************/
510 list_members()
511 {
512     char *argv[1];
513     char *buf;
514     char buffer[80];
515
516     found_some = 0;
517     move(DISPROW, STARTCOL);
518     mvcur(0, 0, DISPROW, STARTCOL);
519     refresh();
520     buf = calloc(LISTMAX, 1);
521     if (Prompt("Enter List Name: ", buf, LISTSIZE) == 1) {
522         (void) sprintf(buffer, "The members of list '%s' are:", buf);
523         show_text(DISPROW + 1, STARTCOL, buffer);
524         argv[0] = buf;
525         if (status = sms_query("get_members_of_list", 1, argv,
526                                print_2, (char *) NULL)) {
527             Put_message("\r\n");
528             com_err(whoami, status, " found.\n");
529             currow++;
530         }
531         if (!found_some) {
532             show_text(currow, STARTCOL, "List is empty (no members).");
533             currow++;
534         }
535         end_display();
536         return(0);
537     }
538     clrwin(DISPROW);
539     return (DM_NORMAL);         /* HA! */
540 }
541
542 /****************************************************/
543 /*ARGSUSED*/
544 static int
545 print_2(argc, argv, callback)
546     int argc;
547     char *argv[], *callback;
548 {
549     char buf[BUFSIZ];
550
551     found_some = 1;
552     (void) sprintf(buf, "%s %s", argv[0], argv[1]);
553     (void) start_display(buf);
554
555     return (0);
556 }
557
558 /****************************************************/
559 start_display(buff)
560     char *buff;
561 {
562     char *buffer;
563
564     num_members++;
565     if (moreflg)
566         return(0);
567     buffer = calloc(50, 1);
568     if (currow >= LINES - 2) {
569         page++;
570         currow++;
571         mvcur(0, 0, currow, STARTCOL);
572         refresh();
573         if (Prompt("--RETURN for more, ctl-c to exit--", buffer, 1) == 0) {
574             Put_message("Flushing query...");
575             moreflg = 1;
576             return (0);
577         }
578         clrwin(DISPROW + 2);
579         currow = DISPROW + 2;
580         (void) sprintf(buffer, "Continued (Page %d)", page);
581         show_text(currow, STARTCOL, buffer);
582         currow++;
583         toggle = 0;
584     }
585     if (!toggle)
586         show_text(currow, STARTCOL, buff);
587     else {
588         show_text(currow, SECONDCOL, buff);
589         currow++;
590     }
591     toggle = !toggle;
592     return(0);
593 }
594
595 /****************************************************/
596 end_display()
597 {
598     char *buffer, c;
599
600     if (moreflg) {
601         clrwin(DISPROW);
602         return;
603     }
604
605     buffer = calloc(50, 1);
606     currow++;
607     (void) sprintf(buffer, "End of List. %d Total Members\r", num_members);
608     show_text(currow, STARTCOL, buffer);
609     currow++;
610     show_text(currow, STARTCOL, "Press any key to continue...");
611     (void) getchar();
612     clrwin(DISPROW);
613
614 }
615
616 /****************************************************/
617 display_menu(menu)
618     MENU *menu;
619 {
620     int i;
621
622     cls();
623     title(menu->title);
624     mvcur(0, 0, STARTROW, STARTCOL);
625     refresh();
626     for (i = 0; i <= menu->num_items - 1; i++) {
627         move(STARTROW + i, STARTCOL);
628         standend();
629         addstr(menu->items[i]);
630         refresh();
631     }
632     center_text(STARTROW + menu->num_items + 2,
633                 "Enter a number, <up arrow>, or <down arrow>.");
634     if (!level)
635         center_text(STARTROW + menu->num_items + 3,
636                     "Press 'q' to exit, <return> to confirm choice.");
637     else
638         center_text(STARTROW + menu->num_items + 3,
639         "Press 'q' to exit, 'r' for main menu, <return> to confirm choice.");
640
641     if (!level)
642         highlight(main_menu);
643 }
644
645 /****************************************************/
646 pack_main_menu()
647 {
648     char *buf;
649
650     main_menu = (MENU *) malloc((unsigned) sizeof(MENU));
651     main_menu->num_items = 7;
652     main_menu->items = (char **) malloc((unsigned) sizeof(char *) * main_menu->num_items);
653
654     buf = calloc(50, 1);
655     (void) sprintf(buf, "Mail List Program for %s", uname);
656     main_menu->title = strsave(buf);
657     main_menu->items[0] = strsave("1.  Show all mailing lists.");
658     main_menu->items[1] = strsave("2.  Get all members of a mailing list.");
659     main_menu->items[2] = strsave("3.  Display lists of which you are a member.");
660     main_menu->items[3] = strsave("4.  Show description of list.");
661     main_menu->items[4] = strsave("5.  Add yourself to a mailing list.");
662     main_menu->items[5] = strsave("6.  Delete yourself from a mailing list.");
663     main_menu->items[6] = strsave("q.  Quit.");
664 }
665
666 /****************************************************/
667 pack_help_menu()
668 {
669     help_menu = (MENU *) malloc((unsigned) sizeof(MENU));
670     help_menu->num_items = 5;
671     help_menu->items = (char **) malloc((unsigned) sizeof(char *) * help_menu->num_items);
672
673     help_menu->title = strsave("madm is designed as a basic mail list administration program.");
674     help_menu->items[0] = strsave("if you need to perform more advanced list manipulation like");
675     help_menu->items[1] = strsave("adding lists, or changing list characteristics, refer to the");
676     help_menu->items[2] = strsave("program listmaint.");
677     help_menu->items[3] = strsave(" ");
678     help_menu->items[4] = strsave("Press any key to continue.");
679 }
680
681 /****************************************************/
682 highlight(menu)
683     MENU *menu;
684 {
685
686
687     if (oldpos[level] != position[level]) {
688         move(STARTROW + oldpos[level] - 1, STARTCOL);
689         standend();
690         addstr(menu->items[oldpos[level] - 1]);
691         refresh();
692     }
693
694     move(STARTROW + position[level] - 1, STARTCOL);
695     standout();
696     addstr(menu->items[position[level] - 1]);
697     refresh();
698     standend();
699     refresh();
700 }
701
702 /****************************************************/
703 title(buff)
704     char *buff;
705 {
706     move(0, MAX(0, (COLS - strlen(buff)) >> 1));
707     standout();
708     addstr(buff);
709     refresh();
710     standend();
711 }
712
713 /****************************************************/
714 center_text(row, buff)
715     int row;
716     char *buff;
717 {
718     move(row, MAX(0, (COLS - strlen(buff)) >> 1));
719     addstr(buff);
720     refresh();
721 }
722
723 /****************************************************/
724 show_text(row, col, buff)
725     int row, col;
726     char *buff;
727 {
728     mvcur(0, 0, row, col);
729     refresh();
730     printf("%s", buff);
731 }
732
733 /****************************************************/
734 erase_line(row, col)
735     int row, col;
736 {
737     char *buff;
738     int i;
739
740     buff = calloc((unsigned)COLS, 1);
741     for (i = 0; i <= COLS - 2; i++)
742         buff[i] = ' ';
743     buff[i] = 0;                /* just to be sure ! */
744     move(row, col);
745     mvcur(0, 0, row, col);
746     printf("%s", buff);
747     refresh();
748 }
749
750 /****************************************************/
751 cls()
752 {
753     clear();
754     refresh();
755 }
756
757 /****************************************************/
758 clrwin(erase_row)
759     int erase_row;
760 {
761     int i;
762     char *buff;
763     int maxcol;
764
765     maxcol = COLS;
766     if (maxcol > 80)
767         maxcol = 80;            /* limit width */
768
769     buff = calloc((unsigned)maxcol + 1, 1);
770     for (i = 0; i <= maxcol - 1; i++)
771         buff[i] = ' ';
772     buff[i] = 0;                /* just to be sure ! */
773     mvcur(0, 0, erase_row, STARTCOL);
774     refresh();
775     for (i = erase_row; i <= currow - 1; i++) {
776         printf("%s\n\r", buff);
777     }
778     printf("%s", buff);
779     mvcur(erase_row, STARTCOL, STARTROW + oldpos[level] - 1, STARTCOL);
780     refresh();
781 }
782
783 /****************************************************/
784
785 static void 
786 scream()
787 {
788     com_err(whoami, status, "\nAn SMS update returned a value -- programmer \
789 botch\n");
790     sms_disconnect();
791     exit(1);
792 }
793
794 /****************************************************/
795 /*ARGSUSED*/
796 static int 
797 fetch_list_info(list, li)
798     char *list;
799     List_info *li;
800 {
801     char *argv[1];
802
803     argv[0] = list;
804     if ((status = sms_query("get_list_info", 1, argv,
805                             get_list_info, (char *) NULL)) == 0) {
806         return status;
807     }
808     else {
809         com_err(whoami, status, " found.\n");
810         return status;
811     }
812 }
813
814 /* ARGSUSED */
815 static int 
816 get_list_info(argc, argv)
817     int argc;
818     char **argv;
819 {
820
821     if (current_li->acl)
822         free(current_li->acl);
823     current_li->acl = strsave(argv[2]);
824     if (current_li->desc)
825         free(current_li->desc);
826     current_li->desc = strsave(argv[3]);
827     if (current_li->expdate)
828         free(current_li->expdate);
829     current_li->expdate = strsave(argv[4]);
830     return (0);
831 }
832
833
834
835
836 /****************************************************/
837 /* Prompt the user for input */
838 int 
839 Prompt(prompt, buf, buflen)
840     char *prompt;
841     char *buf;
842     int buflen;
843 {
844     int c;
845     char *p;
846     int x, oldx;
847
848     printf("%s", prompt);
849     refresh();
850     for (p = buf; abs(strlen(p) - strlen(buf)) <= buflen;) {
851         refresh();
852         c = getchar();
853         switch (c) {
854         case CTL('C'):
855             return 0;
856         case CTL('Z'):
857             return 0;
858         case CTL('L'):
859             cls();
860             display_menu(main_menu);
861             return (0);
862         case '\n':
863         case '\r':
864             Put_message("\r");
865             *p = '\0';
866             if (strlen(buf) < 1)/* only \n or \r in buff */
867                 return (-1);
868             else
869                 return (1);
870         case '\b':
871         case '\177':
872             if (p > buf) {
873                 p--;
874                 x--;
875                 Put_message("\b");
876                 Put_message(" ");
877                 Put_message("\b");
878             }
879             break;
880         case CTL('U'):
881         case CTL('G'):
882         case CTL('['):
883             x = oldx;
884             p = buf;
885             break;
886         default:
887             if (abs(strlen(p) - strlen(buf)) >= buflen) {
888                 printf("%c", 7);
889                 break;
890             }
891             if (isprint(c)) {
892                 (void) addch(c);
893                 *p++ = c;
894                 x++;
895             }
896             else
897                 (void) putchar(CTL('G'));
898             break;
899         }
900     }
901     return(0);
902 }
903
904 /*
905  * Local Variables:
906  * mode: c
907  * c-indent-level: 4
908  * c-continued-statement-offset: 4
909  * c-brace-offset: -4
910  * c-argdecl-indent: 4
911  * c-label-offset: -4
912  * End: 
913  */
This page took 0.107499 seconds and 5 git commands to generate.