/*
 * dipcref.c
 *
 * Allows the user to view and delete some information registered 
 * in referee linked lists. Part of dipcx program.
 *
 * By Kamran Karimi
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <pwd.h>

#include "dipcx.h"

static int first_time = 0;

static char TypeStr[3][15] = 
                         {"Shared Memory", "Message Queue", "Semaphore Set" };

static struct bd_link
{
 int num;
 struct back_door_message bdm;
 struct bd_link *next, *prev;
} first_link;
static struct bd_link *last_link;

int get_referee_list(void)
{
 int want_trans, act_trans;
 char ux_name[80], dipcd_home[80];
 int ux_sockfd, ux_len;
 struct sockaddr_un ux_addr;
 struct back_door_message bd_message;
 struct bd_link *bdl;
 int panel_num;
 struct passwd *dipcdpw;
   
 if(!first_time)
 {
  bdl = first_link.next;
  while(bdl)
  {
   last_link = bdl->next;
   free(bdl);
   bdl = last_link;
  }   
 }
 first_link.next = first_link.prev = NULL;
 last_link = &first_link; 
  
 first_time = 1;                                

 dipcdpw = getpwnam("dipcd");
 if(dipcdpw == NULL)
 {
  show_ok_notice("User 'dipcd' was not found");
  return -1; 
 }
 strcpy(dipcd_home, dipcdpw->pw_dir);
 if(dipcd_home[strlen(dipcd_home) - 1] ==  '/')
  dipcd_home[strlen(dipcd_home) - 1] = 0;
 sprintf(ux_name,"%s/%s", dipcd_home, REFEREE_BACKDOOR);
 bzero((char *) &ux_addr,sizeof(ux_addr));
 ux_addr.sun_family = AF_UNIX;
 strcpy(ux_addr.sun_path,ux_name);
 ux_len = strlen(ux_addr.sun_path) + sizeof(ux_addr.sun_family);

 ux_sockfd = ring(AF_UNIX, (struct sockaddr *) &ux_addr, ux_len);
 if(ux_sockfd < 0)
 {
  show_ok_2_notice("Can't connect to the referee", strerror(errno));
  return -1;
 }  
 bd_message.cmd = BACK_DOOR_INFO;
 want_trans = sizeof(bd_message);
 act_trans = writen(ux_sockfd,(char *)&bd_message, want_trans);
 if(act_trans < want_trans)
 {
  show_ok_2_notice("Could not send the request", strerror(errno));
  close(ux_sockfd);                 
  return -1;
 }
 do
 {
  act_trans = readn(ux_sockfd,(char *)&bd_message, want_trans);
  if(act_trans < want_trans)
  {
   show_ok_2_notice("Could not receive the information", strerror(errno));
   break;
  }
  if(bd_message.arg1 < 0) break;
  bdl = malloc(sizeof(struct bd_link));
  if(bdl == NULL)
  {
   show_ok_notice("Out of memory");
   break;
  } 
  bdl->bdm = bd_message;
  bdl->next = NULL;
  bdl->prev = last_link;
  last_link->next = bdl;
  last_link = bdl;
 } while(1);
  /* show the information */
 bdl = first_link.next;
  
 panel_num = -1;
 while(bdl)
 {
  char buff[80];
   
  panel_num++;
  bdl->num = panel_num;
   
  sprintf(buff, "%s   %d\n", TypeStr[bdl->bdm.arg1], bdl->bdm.arg2);

  xv_set(panel_list, 
   PANEL_LIST_INSERT, panel_num,
   PANEL_LIST_STRING, panel_num, buff,
   PANEL_LIST_CLIENT_DATA, panel_num, panel_num,
   NULL);
                                       
  bdl = bdl->next;
 } 
 return panel_num; 
}

int get_referee_info(int num)
{
 char buff[80], buff2[80], buff3[80];  
 struct bd_link *bdl;
 struct in_addr addr;

 bdl = first_link.next;
 while(bdl)
 {
  if(bdl->num == num) break;
  bdl = bdl->next;
 } 
 if(bdl == NULL)
 {
  show_ok_notice("The requested entry was not found");
  return FAIL;
 } 
  
 addr.s_addr = bdl->bdm.arg5;
 sprintf(buff,"Type: %s   Key: %d", TypeStr[bdl->bdm.arg1], bdl->bdm.arg2);
 sprintf(buff2,"DIPC: %s    Address: %s", (bdl->bdm.arg4) ? "Yes" : "No",
                                                inet_ntoa(addr));
 if(bdl->bdm.arg1 == 0) /* SHM */         
  sprintf(buff3,"Size: %d", bdl->bdm.arg3);
 else if(bdl->bdm.arg1 == 1) /* MSG */
  buff3[0] = 0;
 else if(bdl->bdm.arg1 == 2) /* SEM */         
  sprintf(buff3,"Number of Semaphores: %d", bdl->bdm.arg3); 
 
 show_ok_3_notice(buff, buff2, buff3);
 return SUCCESS;
}


int rem_referee_info(int num)
{
 int want_trans, act_trans;
 char ux_name[80], dipcd_home[80];
 int ux_sockfd, ux_len;
 struct sockaddr_un ux_addr;
 struct back_door_message bd_message;
 struct bd_link *bdl;
 struct passwd *dipcdpw;

 bdl = first_link.next;
 while(bdl)
 {
  if(bdl->num == num) break;
  bdl = bdl->next;
 } 
 if(bdl == NULL)
 {
  show_ok_notice("The requested entry was not found");
  return FAIL;
 }

 bd_message.arg1 = bdl->bdm.arg1;
 bd_message.arg2 = bdl->bdm.arg2;
 bd_message.arg5 = bdl->bdm.arg5;
 
 bd_message.cmd = BACK_DOOR_REMOVE;

 dipcdpw = getpwnam("dipcd");
 if(dipcdpw == NULL)
 {
  show_ok_notice("User 'dipcd' was not found");
  return FAIL;
 }
 strcpy(dipcd_home, dipcdpw->pw_dir);
 if(dipcd_home[strlen(dipcd_home) - 1] ==  '/')
  dipcd_home[strlen(dipcd_home) - 1] = 0;
 sprintf(ux_name,"%s/%s", dipcd_home, REFEREE_BACKDOOR);
 bzero((char *) &ux_addr,sizeof(ux_addr));
 ux_addr.sun_family = AF_UNIX;
 strcpy(ux_addr.sun_path,ux_name);
 ux_len = strlen(ux_addr.sun_path) + sizeof(ux_addr.sun_family);
 
 ux_sockfd = ring(AF_UNIX, (struct sockaddr *) &ux_addr, ux_len);
 if(ux_sockfd < 0)
 {
  show_ok_2_notice("Can't connect to the referee", strerror(errno));
  return FAIL;
 }
 want_trans = sizeof(bd_message);
 act_trans = writen(ux_sockfd,(char *)&bd_message, want_trans);
 if(act_trans < want_trans)
 {
  show_ok_2_notice("Could not send the request", strerror(errno));        
  close(ux_sockfd);
  return FAIL;
 }
 bd_message.arg1 = -1; /* default */
 act_trans = readn(ux_sockfd,(char *)&bd_message, want_trans);
 /* if(act_trans < want_trans)
 {
  show_ok_2_notice("Could not receive the information", strerror(errno));
 } */
 if(bd_message.arg1 < 0)
  show_ok_notice("Failed to delete the entry");
 /* else
  printf("Entry deleted\n"); */

 xv_set(panel_list, 
  PANEL_LIST_DELETE, num,
  NULL);
 
 return SUCCESS; 
}
