/*
 * dipcshm.c
 *
 * Allows the user to view some information in a shared memory manager's 
 * 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 Panel_item shm_panel_list;

static int first_time = 1;

static char *TypeStr[3] = {"WANT_ACCESS", "PENDING AK", "ACCESSING" };

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


int get_shm_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 in_addr addr;
 int panel_num;
 struct passwd *dipcdpw;
 
 dipcdpw = getpwnam("dipcd");
 if(dipcdpw == NULL)
 {
  show_ok_notice("User 'dipcd' was not found\n");
  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.%d", dipcd_home, SHM_BACKDOOR, num);
 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);

 if(!first_time)
 {
  bdl = first_link.next;
  while(bdl)
  {
   last_link = bdl->next;
   free(bdl);
   bdl = last_link;
  }
 }
 first_time = 0; 
 first_link.next = first_link.prev = NULL;
 last_link = &first_link;
                                 
 ux_sockfd = ring(AF_UNIX, (struct sockaddr *) &ux_addr, ux_len);
 if(ux_sockfd < 0)
 {
  show_ok_2_notice("Can't connect to the shared memory manager", 
                                                         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);
 }
 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);
 
 panel_num = -1;
 bdl = first_link.next;
 while(bdl)
 {
  char buff[80];
   
  addr.s_addr = bdl->bdm.arg5;

  panel_num++;
  bdl->num = panel_num;   
  sprintf(buff, "%4d   %s   %6s   %-15.15s", bdl->bdm.arg3, TypeStr[bdl->bdm.arg1], 
                            (bdl->bdm.arg2) ? "WRITER" : "READER",
                            inet_ntoa(addr));  
  
  xv_set(shm_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 shm_remove_manager(int key)
{
 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 passwd *dipcdpw;

 dipcdpw = getpwnam("dipcd");
 if(dipcdpw == NULL)
 {
  show_ok_notice("User 'dipcd' was not found\n");
  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.%d", dipcd_home, SHM_BACKDOOR, key);
 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 shared memory manager",
                                                     strerror(errno));
  return FAIL;
 }  
 bd_message.cmd = BACK_DOOR_EXIT;
 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));
  return FAIL;
 }
 return SUCCESS; 
}


void which_shm_entry(Panel_item item, char *string, caddr_t client_data,
                                         Panel_list_op op, Event *event)
{
/* printf("item: %d\n", (int) client_data); */
}


int get_shm_list(int num)
{ 
 clean_all();
 
 display_shm = 1;  

 shm_panel = (Panel) xv_create(frame, PANEL, NULL);
                                
 shm_panel_list = xv_create(shm_panel, PANEL_LIST,
         PANEL_LIST_DISPLAY_ROWS, 15,
         PANEL_READ_ONLY, TRUE,
         PANEL_LIST_STRINGS, NULL,
         PANEL_LIST_CLIENT_DATAS, NULL,
         PANEL_NOTIFY_PROC, which_shm_entry,
         NULL);
 
 if(get_shm_info(num) == -1)
 {
  clean_all();
  return FAIL;
 }

 window_fit(shm_panel);
 window_fit(frame);
 
 return SUCCESS;
}
