/*****************************************************************************
 Excerpt from "Linux Programmer's Guide - Chapter 6"
 (C)opyright 1994-1995, Scott Burkett
 ***************************************************************************** 
 MODULE: msgtool.c
 *****************************************************************************
 A command line tool for tinkering with SysV style Message Queues
 *****************************************************************************/
/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * See the COPYING file for full license information.
 */

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "common.h"

#if HAVE_SYS_IPC_H
# include <sys/ipc.h>
#endif
#if HAVE_SYS_MSG_H
# include <sys/msg.h>
#endif

#define MAX_SEND_SIZE 80

struct mymsgbuf
{
  long mtype;
  char mtext[MAX_SEND_SIZE];
};

void send_message (int qid, struct mymsgbuf *qbuf, long type, char *text);
void read_message (int qid, struct mymsgbuf *qbuf, long type);
void remove_queue (int qid);
void change_queue_mode (int qid, char *mode);
void usage (void);


int
main (int argc, char *argv[])
{
  key_t key;
  int msgqueue_id;
  struct mymsgbuf qbuf;

  if (argc == 1)
    usage ();

  /* Create unique key via call to ftok() */
  key = ftok (".", 'm');

  /* Open the queue - create if necessary */
  if ((msgqueue_id = msgget (key, IPC_CREAT | 0660)) == -1)
    {
      perror ("msgget");
      exit (1);
    }

  switch (tolower (argv[1][0]))
    {
    case 's':
      send_message (msgqueue_id, (struct mymsgbuf *) &qbuf,
                    atol (argv[2]), argv[3]);
      break;
    case 'r':
      read_message (msgqueue_id, &qbuf, atol (argv[2]));
      break;
    case 'd':
      remove_queue (msgqueue_id);
      break;
    case 'm':
      change_queue_mode (msgqueue_id, argv[2]);
      break;

    default:
      usage ();

    }

  return (0);
}

void
send_message (int qid, struct mymsgbuf *qbuf, long type, char *text)
{
  /* Send a message to the queue */
  printf ("Sending a message ...\n");
  qbuf->mtype = type;
  strcpy (qbuf->mtext, text);

  if ((msgsnd (qid, (struct msgbuf *) qbuf,
               strlen (qbuf->mtext) + 1, 0)) == -1)
    {
      perror ("msgsnd");
      exit (1);
    }
}

void
read_message (int qid, struct mymsgbuf *qbuf, long type)
{
  /* Read a message from the queue */
  printf ("Reading a message ...\n");
  qbuf->mtype = type;
  msgrcv (qid, (struct msgbuf *) qbuf, MAX_SEND_SIZE, type, 0);

  printf ("Type: %ld Text: %s\n", qbuf->mtype, qbuf->mtext);
}

void
remove_queue (int qid)
{
  /* Remove the queue */
  msgctl (qid, IPC_RMID, 0);
}

void
change_queue_mode (int qid, char *mode)
{
  struct msqid_ds myqueue_ds;

  /* Get current info */
  msgctl (qid, IPC_STAT, &myqueue_ds);

  /* Convert and load the mode */
  sscanf (mode, "%ho", &myqueue_ds.msg_perm.mode);

  /* Update the mode */
  msgctl (qid, IPC_SET, &myqueue_ds);
}

void
usage (void)
{
  fprintf (stderr, "msgtool - A utility for tinkering with msg queues\n");
  fprintf (stderr, "\nUSAGE: msgtool (s)end <type> <messagetext>\n");
  fprintf (stderr, "               (r)ecv <type>\n");
  fprintf (stderr, "               (d)elete\n");
  fprintf (stderr, "               (m)ode <octal mode>\n");
  exit (1);
}
