home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume3 / send / send.c < prev    next >
C/C++ Source or Header  |  1989-02-03  |  13KB  |  635 lines

  1. /*
  2. **  send.c
  3. **
  4. **    Written by: Keith Gabryelski (ag@elgar.UUCP)
  5. **
  6. **        Released into public domain June 14, 1988.
  7. **            Please keep this header.
  8. */
  9.  
  10. #include <stdio.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <utmp.h>
  14. #include <pwd.h>
  15. #include <errno.h>
  16.  
  17. extern errno;
  18.  
  19. extern struct passwd *getpwuid(), *getpwnam();
  20.  
  21. extern FILE *fopen();
  22. extern char *getlogin(), *strrchr(), *ctime(), *malloc(), *realloc();
  23. extern char *ttyname(), *strcpy(), *strncpy(), *strcat();
  24. extern long time();
  25.  
  26. extern char *sys_errlist[];
  27. extern int sys_nerr;
  28. extern void setutent();
  29.  
  30. #undef TRUE
  31. #undef FALSE
  32. #define TRUE            1
  33. #define FALSE            0
  34. #define UNUSED            -1
  35.  
  36. #define NORMAL            0
  37. #define FAST            1
  38.  
  39. #define    SENDS_FILENAME        "/.sends"    /* must have the '/' */
  40. #define    DEAD_SEND_FILENAME    "/dead.send"    /* must have the '/' */
  41.  
  42. #define MESSAGE_SEPARATOR    0x1F
  43.  
  44. char *puterr(), *get_typed_message(), *cat_message(), *myfgets();
  45. char *get_last_sender();
  46. int reply(), send(), shout();
  47.  
  48. struct
  49. {
  50.     char *name;                /* Command name.    */
  51.     int (*function)();            /* Function to use.    */
  52.     int type;                /* Parameters.        */
  53.     char *text;                /* First word in header.*/
  54. }
  55. command_table[] =
  56. {
  57.     {"fr", reply, FAST, "Reply"},
  58.     {"freply", reply, FAST, "Reply"},
  59.     {"fs", send, FAST, "Message"},
  60.     {"fsend", send, FAST, "Message"},
  61.     {"reply", reply, NORMAL, "Reply"},
  62.     {"send", send, NORMAL, "Message"},
  63.     {"shout", shout, NORMAL, "Shout"},
  64.     {NULL, }
  65. };
  66.  
  67. int argc, uid;
  68. char **argv, *progname;
  69. char login_name[] = "        \0",        /* eight chars plus nul */
  70.      tty_name[] = "            \0";        /* twelve chars plus a nul */
  71.  
  72. char *
  73. mymalloc(size)
  74. unsigned size;
  75. {
  76.     char *p;
  77.  
  78.     if ((p = malloc(size)) == NULL)
  79.     {
  80.     (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  81.     exit(-1);
  82.     }
  83.  
  84.     return p;
  85. }
  86.  
  87. char *
  88. myrealloc(p, size)
  89. char *p;
  90. unsigned size;
  91. {
  92.     if (p == NULL)
  93.     {
  94.     if ((p = malloc(size)) == NULL)
  95.     {
  96.         (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  97.         exit(-1);
  98.     }
  99.     }
  100.     else if ((p = realloc(p, size)) == NULL)
  101.     {
  102.     (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  103.     exit(-1);
  104.     }
  105.  
  106.     return p;
  107. }
  108.  
  109. main(largc, largv)
  110. int largc;
  111. char **largv;
  112. {
  113.     char *ptr;
  114.     int i;
  115.     struct passwd *pt;
  116.  
  117.     progname = *largv++;  --largc;
  118.     argv = largv;  argc = largc;
  119.  
  120.     uid = getuid();
  121.  
  122.     pt = getpwuid(uid);
  123.  
  124.     if ((ptr = getlogin()) == NULL)
  125.     if ((ptr = pt->pw_name) == NULL)
  126.         ptr = "somebody";        /* can't figure this guy out */
  127.  
  128.     (void) strncpy(login_name, ptr, 8);
  129.  
  130.     if ((ptr = ttyname(0)) == NULL)
  131.     strcpy(tty_name, "tty??");
  132.     else
  133.     strncpy(tty_name, ((ptr= strrchr(ptr, '/')) ? ptr+1 : "tty??"), 12);
  134.  
  135.     i = 0;
  136.     while (command_table[i].name != NULL)
  137.     if (strcmp(progname, command_table[i].name))
  138.         ++i;
  139.     else
  140.         break;
  141.  
  142.     if (command_table[i].name == NULL)
  143.     send(NORMAL, "Message");
  144.     else
  145.     (*command_table[i].function)(command_table[i].type,
  146.                      command_table[i].text);
  147.  
  148.     exit(0);
  149. }
  150.  
  151. /*
  152. ** reply --
  153. **           Reply to a previously sent message.  This routine uses the
  154. **           (from) user name of the last message sent as the user to
  155. **           send a message to.
  156. */
  157.  
  158. reply(type, text)
  159. int type;
  160. char *text;
  161. {
  162.     char **send_to_list = (char **)mymalloc(0);
  163.     char *message;
  164.  
  165.     /*
  166.     ** make send_to_list initially have one element -- NULL.
  167.     **
  168.     ** Even though only one user is ever gonna get a message,
  169.     ** I still use the add_to_list() routine.
  170.     */
  171.  
  172.     send_to_list = (char **)myrealloc(send_to_list, sizeof(char *));
  173.     send_to_list[0] = NULL;
  174.  
  175.     add_to_list(&send_to_list, get_last_sender());
  176.  
  177.     message = get_typed_message();
  178.  
  179.     send_message(send_to_list, message, type, text);
  180. }
  181.  
  182. /*
  183. ** send - generic send-a-message-to-one-or-more-users routine.
  184. **
  185. **
  186. **
  187. */
  188.  
  189. send(type, text)
  190. int type;
  191. char *text;
  192. {
  193.     char **send_to_list = (char **)mymalloc(0);
  194.     char *message;
  195.  
  196.     /*
  197.     ** make send_to_list initially have one element -- NULL.
  198.     **
  199.     */
  200.  
  201.     send_to_list = (char **)myrealloc(send_to_list, sizeof(char *));
  202.     send_to_list[0] = NULL;
  203.  
  204.     if (argc < 1)
  205.     {
  206.     fprintf(stderr, "%s: usage: %s user1, [user2,] [...,] [message]\n",
  207.         progname, progname);
  208.     exit(-1);
  209.     }
  210.  
  211.     while (*argv != NULL)
  212.     {
  213.     --argc;
  214.     if ((*argv)[strlen(*argv)-1] == ',')
  215.     {
  216.         (*argv)[strlen(*argv)-1] = '\0';
  217.         add_to_list(&send_to_list, *argv++);
  218.     }
  219.     else
  220.     {
  221.         add_to_list(&send_to_list, *argv++);
  222.         break;
  223.     }
  224.     }
  225.  
  226.     message = get_typed_message();
  227.  
  228.     send_message(send_to_list, message, type, text);
  229. }
  230.  
  231. /*
  232. ** shout -- Send a message to all logged in users.
  233. **
  234. **
  235. */
  236.  
  237. shout(type, text)
  238. int type;
  239. char *text;
  240. {
  241.     char **send_to_list = (char **)mymalloc(0);
  242.     char *message;
  243.     struct utmp *getutent(), *ut;
  244.  
  245.     /*
  246.     ** make send_to_list initially have one element -- NULL.
  247.     **
  248.     */
  249.  
  250.     send_to_list = (char **)myrealloc(send_to_list, sizeof(char *));
  251.     send_to_list[0] = NULL;
  252.  
  253.     setutent();
  254.  
  255.     while ((ut = getutent()) != (struct utmp *)NULL)
  256.     if (ut->ut_type == USER_PROCESS)
  257.         add_to_list(&send_to_list, ut->ut_line);
  258.  
  259.     message = get_typed_message();
  260.  
  261.     send_message(send_to_list, message, type, text);
  262. }
  263.  
  264. /*
  265. ** get_typed_message() --
  266. **                         Get arguments for a message of the command line
  267. **                         and take input from stdin if the last argument
  268. **                         is "-" or no message was given on the command
  269. **                         line.
  270. */
  271.  
  272. char *
  273. get_typed_message()
  274. {
  275.     char *buffer = mymalloc(1);
  276.     int old_argc;
  277.  
  278.     *buffer = '\0';
  279.  
  280.     old_argc = argc;
  281.     while (argc > 0 && !(argc == 1 && !strcmp(*argv, "-")))
  282.     {
  283.     buffer = cat_message(buffer, *argv++);
  284.     buffer = cat_message(buffer, " ");
  285.     --argc;
  286.     }
  287.  
  288.     if (argc || !old_argc)
  289.     {
  290.     char *line = mymalloc(BUFSIZ);
  291.  
  292.     while ((line = myfgets(line, BUFSIZ, stdin)) != NULL)
  293.         buffer = cat_message(buffer, line);
  294.     }
  295.  
  296.     /*
  297.     ** That extra <cr> or ' '. ack...
  298.     */
  299.  
  300.     if (buffer[strlen(buffer)-1] == '\n' || buffer[strlen(buffer)-1] == ' ')
  301.     buffer[strlen(buffer)-1] = '\0';
  302.  
  303.     return buffer;
  304. }
  305.  
  306. char *
  307. myfgets(buffer, size, stream)
  308. char *buffer;
  309. int size;
  310. FILE *stream;
  311. {
  312.     int c, length = 0;
  313.  
  314.     while ((c = getc(stream)) != EOF && c != '\n' && (length-1) < size)
  315.     if (c >= ' ')
  316.         buffer[length++] = c;
  317.  
  318.     if (c == '\n')
  319.     buffer[length++] = c;
  320.  
  321.     buffer[length++] = '\0';
  322.  
  323.     return  c == EOF ? NULL : buffer;
  324. }
  325.  
  326. char *
  327. cat_message(buffer, line)
  328. char *buffer, *line;
  329. {
  330.     buffer = myrealloc(buffer, strlen(buffer) + strlen(line) + 1);
  331.     strcat(buffer, line);
  332.     return buffer;
  333. }
  334.  
  335. char *
  336. get_last_sender()
  337. {
  338.     char *ptr, *sends_filename = mymalloc(0);
  339.     char dummy[50];
  340.     static char name[50];
  341.     int c, n;
  342.     struct passwd *pt;
  343.     FILE *fp;
  344.  
  345.     pt = getpwuid(uid);
  346.  
  347.     if ((ptr = pt->pw_dir) != NULL)
  348.     {
  349.     sends_filename = myrealloc(sends_filename, strlen(ptr) +
  350.                    sizeof(SENDS_FILENAME) + 1);
  351.  
  352.     strcpy(sends_filename, ptr);
  353.     strcat(sends_filename, SENDS_FILENAME);
  354.  
  355.     if ((fp = fopen(sends_filename, "r")) == (FILE *)NULL)
  356.     {
  357.         fprintf(stderr, "%s: No reply possible, can't open %s (%s).\n",
  358.             progname, sends_filename, puterr(errno));
  359.         exit(-1);
  360.     }
  361.  
  362.     *name = '\0';
  363.     while (fscanf(fp, "[%s %s %s (%s", dummy, dummy, dummy,
  364.                name) == 4)
  365.         while ((c = getc(fp)) != MESSAGE_SEPARATOR && c != EOF)
  366.         ;
  367.  
  368.     fclose(fp);
  369.  
  370.     if (name[strlen(name)-1] == ')')
  371.         name[strlen(name)-1] = '\0';
  372.  
  373.     if (*name == '\0')
  374.     {
  375.         fprintf(stderr, "%s: no sends.\n", progname);
  376.         exit(-1);
  377.     }
  378.     }
  379.     else
  380.     {
  381.     fprintf(stderr, "%s: No reply possible, no home directory.\n",
  382.         progname);
  383.  
  384.     exit(-1);
  385.     }
  386.  
  387.     return name;
  388. }
  389.  
  390. send_message(user_list, message, type, text)
  391. char **user_list, *message;
  392. int type;
  393. char *text;
  394. {
  395.     char *date_text, *ptr, *sends_filename = mymalloc(0);
  396.     char **sent_to_list = (char **)mymalloc(0);
  397.     char **sends_list = (char **)mymalloc(0);
  398.     int sendit = TRUE, sent = FALSE, failed = FALSE, need_crlf = FALSE;
  399.     long clock[1];
  400.     struct utmp *getutent(), *ut;
  401.     struct passwd *pt;
  402.     struct stat stbuf;
  403.     FILE *fp;
  404.     static char device[] = "/dev/            \0";
  405.  
  406.     /* setup null sent_to_list */
  407.  
  408.     sent_to_list = (char **)myrealloc(sent_to_list, sizeof(char *));
  409.     sent_to_list[0] = NULL;
  410.  
  411.     sends_list = (char **)myrealloc(sends_list, sizeof(char *));
  412.     sends_list[0] = NULL;
  413.  
  414.     /* get the date without a terminating <cr> */
  415.  
  416.     clock[0] = time((long *)0);
  417.     date_text = ctime(clock);
  418.     date_text[24] = '\0';
  419.  
  420.     /* find user/tty in utmp */
  421.  
  422.     while (*user_list != NULL)
  423.     {
  424.     setutent();
  425.     sendit = UNUSED;
  426.     sent = FALSE;
  427.  
  428.     while ((ut = getutent()) != (struct utmp *)NULL)
  429.     {
  430.         if ((ut->ut_type == USER_PROCESS) &&
  431.         ((!strncmp(ut->ut_user, *user_list, 8)) ||
  432.          (!strncmp(ut->ut_line, *user_list, 12))))
  433.         {
  434.         sendit = TRUE;
  435.  
  436.         if (add_to_list(&sent_to_list, ut->ut_line))
  437.         {
  438.             sent = TRUE;
  439.             break;
  440.         }
  441.  
  442.         strncpy(device+5, ut->ut_line, 12);
  443.  
  444.         if (uid != 0)
  445.         {
  446.             if (stat(device, &stbuf) == -1)
  447.             {
  448.             fprintf(stderr, "%s: Couldn't stat %s (%s).\n",
  449.                 progname, device, puterr(errno));
  450.             sendit = FALSE;
  451.             failed = TRUE;
  452.             }
  453.             else
  454.             if (!stbuf.st_mode&2)
  455.             {
  456.                 fprintf(stderr,
  457.                     "[%s/%s]: Is not receiving sends.\n",
  458.                     ut->ut_user, ut->ut_line);
  459.                 sendit = FALSE;
  460.                 failed = TRUE;
  461.             }
  462.         }
  463.  
  464.         /* open device and send the message */
  465.  
  466.         if (sendit)
  467.         {
  468.             if ((fp = fopen(device, "w")) == (FILE *)NULL)
  469.             fprintf(stderr, "%s: could not open %s (%s).\n",
  470.                 progname, device, puterr(errno));
  471.             else
  472.             {
  473.             if (type&FAST)
  474.                 fprintf(fp, "\007\n[%s/%s: %s]\n", login_name,
  475.                     tty_name, message);
  476.             else
  477.                 fprintf(fp, "\007\n[%s from %s (%s) %s]\n%s\n",
  478.                     text, login_name, tty_name, date_text,
  479.                     message);
  480.  
  481.             printf("[%s/%s] ", ut->ut_user, ut->ut_line);
  482.  
  483.             need_crlf = sent = TRUE;
  484.  
  485.             fclose(fp);
  486.  
  487.             /* write send to ~user/.sends file */
  488.             if (!add_to_list(&sends_list, ut->ut_user))
  489.             {
  490.                 pt = getpwnam(ut->ut_user);
  491.  
  492.                 if ((ptr = pt->pw_dir) != NULL)
  493.                 {
  494.                 sends_filename =
  495.                     myrealloc(sends_filename, strlen(ptr) +
  496.                           sizeof(SENDS_FILENAME) + 1);
  497.  
  498.                 strcpy(sends_filename, ptr);
  499.                 strcat(sends_filename, SENDS_FILENAME);
  500.  
  501.                 if ((fp = fopen(sends_filename, "a+")) !=
  502.                     (FILE *)NULL)
  503.                     fprintf(fp, "[%s from %s (%s) %s]\n%s\n%c",
  504.                         text, login_name, tty_name,
  505.                         date_text, message,
  506.                         MESSAGE_SEPARATOR);
  507.  
  508.                 fclose(fp);
  509.                 }
  510.             }
  511.             }
  512.         }
  513.         }
  514.     }
  515.  
  516.     if (!sent)
  517.     {
  518.         failed = TRUE;
  519.         if (sendit == UNUSED)
  520.         {
  521.         /*
  522.         ** Decide what the user tried to type in.  Was it a user
  523.         ** who isn't logged in or maybe a tty device that no user
  524.         ** is logged on to or maybe a mistyped username.
  525.         */
  526.  
  527.         if ((pt = getpwuid(*user_list)) == (struct passwd *)NULL)
  528.         {
  529.             int status;
  530.  
  531.             strncpy(device+5, *user_list, 12);
  532.  
  533.             status = stat(device, &stbuf);
  534.  
  535.             if (status == -1 || !stbuf.st_mode&S_IFCHR)
  536.             fprintf(stderr, "%s: no user %s.\n", progname,
  537.                 *user_list);
  538.             else
  539.             fprintf(stderr, "%s: no user logged on device %s.\n",
  540.                 progname, *user_list);
  541.         }
  542.         else
  543.             fprintf(stderr, "%s: %s not logged in.\n", progname,
  544.                 *user_list);
  545.         }
  546.     }
  547.     ++user_list;
  548.     }
  549.  
  550.     if (failed)
  551.     {
  552.     char *dead_filename = malloc(0);
  553.  
  554.     pt = getpwuid(uid);
  555.  
  556.     if ((ptr = pt->pw_dir) == NULL)
  557.     {
  558.         dead_filename = myrealloc(dead_filename, sizeof("/tmp/") +
  559.                       sizeof(login_name) + 
  560.                       sizeof(DEAD_SEND_FILENAME) + 1);
  561.  
  562.         strcpy(dead_filename, "/tmp/");
  563.         strcat(dead_filename, login_name);
  564.         strcat(dead_filename, DEAD_SEND_FILENAME);
  565.     }
  566.     else
  567.     {
  568.         dead_filename = myrealloc(dead_filename, strlen(ptr) +
  569.                        sizeof(DEAD_SEND_FILENAME) + 1);
  570.         strcpy(dead_filename, ptr);
  571.         strcat(dead_filename, DEAD_SEND_FILENAME);
  572.     }
  573.  
  574.     if ((fp = fopen(dead_filename, "a+")) != (FILE *)NULL)
  575.     {
  576.         fprintf(fp, "[%s from %s (%s) %s]\n%s\n%c", text, login_name,
  577.             tty_name, date_text, message, MESSAGE_SEPARATOR);
  578.  
  579.         fprintf(stderr, "%s: message copied to %s.\n", progname,
  580.             dead_filename);
  581.         
  582.     }
  583.  
  584.     fclose(fp);
  585.     free(dead_filename);
  586.     }
  587.  
  588.     if (need_crlf)
  589.     putchar('\n');
  590.  
  591.     free(sends_filename);
  592. }
  593.  
  594. add_to_list(list, name)
  595. char ***list, *name;
  596. {
  597.     register int i;
  598.  
  599.     for (i = 0; (*list)[i] != NULL; ++i)
  600.     if (!strcmp((*list)[i], name))
  601.         return TRUE;
  602.  
  603.     *list = (char **)myrealloc(*list, sizeof(char *) * (i + 2));
  604.     (*list)[i] = mymalloc(strlen(name)+1);
  605.     strcpy((*list)[i], name);
  606.     (*list)[i+1] = NULL;
  607.  
  608.     return FALSE;
  609. }
  610.  
  611. /*
  612. **
  613. **free_list(list)
  614. **char **list;
  615. **{
  616. **    register int i;
  617. **
  618. **    for (i = 0; list[i] != NULL; ++i)
  619. **    free(list[i]);
  620. **
  621. **    free(list);
  622. **}
  623. */
  624.  
  625. char *
  626. puterr(error)
  627. int error;
  628. {
  629.     static char qwerty[42];
  630.  
  631.     (void) sprintf(qwerty, "Unknown error %d", error);
  632.  
  633.     return ((unsigned)error >= sys_nerr) ? qwerty : sys_errlist[error];
  634. }
  635.