Listing 6

/* Program:            usrsnd
 *
 * Filename:           listing1.c
 *
 * Description:        Demonstration program that uses a message
 *                 queue to enable users to send one line messages
 *                 to each other.
 *
 * Contents:           main(), send_mssg(), recv_mssg(),
 *                 get_msg_queue()
 *
 * Author/Programmer:  W. J. Freda
 *                 Automated Concepts Inc.
 */
#include <stdio.h>
#include <signal.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define KEY      0x5642412
static struct mssg {
   long mtype;         /* Message type */
   char mtext[BUFSIZ];     /* Message text */
} Msgbuf;
static int Msqid;           /* Message queue identifier */
static int Firstime=1;

/* MAIN
 *
 * DESCRIPTION:    Provides a simple menu that ties the
 *             send_msg() and recv_msg() functions
 *             together.
 *
 * INPUT:      NONE
 * OUTPUT:     Program termination
*/
main()
{
   char *mssg, *recv_mssg();
   char selection[80];

   while(1) {
       printf("\n\n\t1) Send a message to a specific user\n");
       printf("\t2) Receive messages\n");
       printf("\t3) Exit\n");
       printf("\n\t\tEnter selection: ");

       gets(selection);

       switch(*selection) {
           case '1':
               send_mssg();
               break;
           case '2':
               if ((mssg=recv_mssg()) == NULL)
                   printf("\n\nNo messages on queue\n\n");

               else 
                   printf("\n\n%s\n\n",mssg);
               break;
           case '3':
               exit(0);
           default:
               printf("\tInvalid selection.\n\n");
               break;
       }
   }
}


/* SEND_MSSG FUNCTION
 *
 * DESCRIPTION:    Prompts the user for a username and message
 *             and sends the message to that user via a message
 *             queue. The user can read the message using
 *             rcv_mssg().
 *
 *  INPUT:     NONE
 *  OUTPUT:    0 If successful
 *             -1 Otherwise
*/
send_mssg()
{
   extern int Msqid;           /* Message queue identifier  */
   extern struct mssg Msgbuf;  /* Message structure         */
   extern int errno;
   int msglen;             /* Length of message        */
   char message[BUFSIZ];       /* Message text             */
   char username [20];
   struct passwd *pass, *getpwnam();

   if (Firstime) {
       if ((Msqid=get_msg_queue()) == -1)
           return(-1);

       Firstime=0;
   }

   /* Prompt for user name */
   printf("\n\nSend message to which user? ");
   gets(username);

   /* Validate username */
   setpwent();
   pass=getpwnam(username);
   endpwent();

   if (pass == NULL) {
       printf("Invalid username.\n\n");
       return(0);
   }

   /* Prompt user for a message to send */
   printf("Enter message: ");
   gets(Msgbuf.mtext);

   if (*(Msgbuf.mtext) == NULL)
       /* Nothing to send */
       return(0);

   /* Set the message length */
   msglen=strlen(Msgbuf.mtext);

   /* Set the message type equal to the userid
    * we want to send the message to.
   */
   Msgbuf.mtype = pass->pw_uid;

   /* Send the message. The IPC_NOWAIT flag informs msgsnd()
    * not to send the message if the message queue is full.
    * Without the IPC_NOWAIT flag this process would be put
    * to sleep by the kernel until the message can be sent.
   */

   if (msgsnd(Msqid, &Msgbuf, msglen, IPC_NOWAIT) == -1)  {
       /* Error occurred */
       return(-1);
   }

   return(0);
}


/* RECV_MSSG FUNCTION       char *recv_mssg()
 *
 *  DESCRIPTION:    Attempts to retrieve a message from the
 *              message queue.
 *
 *  INPUT:      NONE
 *  OUTPUT:     text    Returns a pointer to the first
 *                  character of the message text.
 *              NULL    If there are no messages or an
 *                  error occurred.
*/
char *recv_mssg()
{
   extern int Msqid;           /*  Message queue identifier */
   extern struct mssg Msgbuf;  /*  Message structure        */
   extern int Firstime;
   int uid;                    /*  User id                  */
   int len;

   if (Firstime) {
       if ((Msqid=get_msg_queue()) == -1) {
           return(NULL);
       }
       Firstime=0;
   }

   /* Get the user id */
   uid=getuid();

   /* Receive a message. The IPC_NOWAIT flag informs msgrcv()
    * to return immediately if no message is on queue. Without
    * the IPC_NOWAIT flag this process would be put to sleep by
    * the kernel until a message of type uid is received.
   */
   if ((len=msgrcv(Msqid, &Msgbuf, BUFSIZ, uid, IPC_NOWAIT)) == -1)
       return(NULL);

   /* Null terminate the message */
   Msgbuf.mtext[len]=NULL;
   return(Msgbuf.mtext);
}

/* GET_MSG_QUEUE FUNCTION
 *
 *  DESCRIPTION:    Gets and possibly creates a message
 *              queue identifier via the msgget(2)
 *              system call.
 *
 * INPUT:       NONE
 * OUTPUT:      qid Message queue ID
 *              -1 Otherwise
*/
get_msg_queue()
{
   int qid;

   /* Acquire a message queue.
    * The IPC_CREAT flag informs msgget() to create
    * the message queue with the permission 0666.
    * The IPC_CREAT flags inform msgget() to create
    * the message queue if it doesn't already exist.
   */
   if ((qid=msgget((key_t)KEY, 0666  |  IPC_CREAT)) == -1) {
       return(-1);
   }

   return(qid);
}