/* tty line ISDN status monitor
 *
 * (c) 1995-97 Volker Götz
 * (c) 2000 Paul Slootman <paul@isdn4linux.de>
 *
 * $Id: imontty.c,v 1.5 2000/06/29 17:38:26 akool Exp $
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <linux/isdn.h>
#include "imontty.h"

struct phone_entry {
   struct phone_entry *next;
   char phone[30];
   char name[30];
};

static struct phone_entry *phones = NULL;
static int show_names = 1;

static int Star(char *, char *);

/*
 * Wildmat routines
 */
static int wildmat(char *s, char *p) {
  register int   last;
  register int   matched;
  register int   reverse;

  for ( ; *p; s++, p++)
    switch (*p) {
    case '\\':
      /* Literal match with following character; fall through. */
      p++;
    default:
      if (*s != *p)
	return(0);
      continue;
    case '?':
      /* Match anything. */
      if (*s == '\0')
	return(0);
      continue;
    case '*':
      /* Trailing star matches everything. */
      return(*++p ? Star(s, p) : 1);
    case '[':
      /* [^....] means inverse character class. */
      if ((reverse = (p[1] == '^')))
	p++;
      for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
	/* This next line requires a good C compiler. */
	if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
	  matched = 1;
      if (matched == reverse)
	return(0);
      continue;
    }
  return(*s == '\0');
}

static int Star(char *s, char *p) {
  while (wildmat(s, p) == 0)
    if (*++s == '\0')
      return(0);
  return(1);
}

/*
 * Read phonebook file and create a linked
 * list of phone entries.
 */
static void readphonebook(char *phonebook) {
  FILE *f;
  struct phone_entry *p;
  struct phone_entry *q;
  char line[255];
  char *s;

  if (!(f = fopen(phonebook, "r"))) {
    sprintf(line, "Can't open `%.200s'", phonebook);
    perror(line);
    return;
  }
  p = phones;
  while (p) {
    q = p->next;
    free(p);
    p = q;
  }
  phones = NULL;
  while (fgets(line,sizeof(line),f)) {
    if ((s = strchr(line,'\n')))
      *s = '\0';
    if (line[0]=='#')
      continue;
    s = strchr(line,'\t');
    *s++ = '\0';
    if (strlen(line) && strlen(s)) {
      q = malloc(sizeof(struct phone_entry));
      q->next = phones;
      strncpy(q->phone, line, sizeof(q->phone)-1);
      q->phone[sizeof(q->phone)-1] = 0;
      strncpy(q->name, s, sizeof(q->name)-1);
      q->name[sizeof(q->name)-1] = 0;
      phones = q;
    }
  }
  fclose(f);
  if (!phones)
    show_names = 0;
}

/*
 * Find a phone number in list of phone entries.
 * If found, return corresponding name, else
 * return number string.
 */
char *find_name(char *num) {
  struct phone_entry *p = phones;
  static char tmp[30];

  sprintf(tmp, "%-.28s", num);
  if (!show_names)
	return(tmp);
  while (p) {
    if (wildmat(num, p->phone)) {
      sprintf(tmp, "%-.28s", p->name);
      break;
    }
    p = p->next;
  }
  return tmp;
}

void scan_str(char * buffer, char * field[], int max) {
    char * buf = buffer;
    int i;
    char * token = strtok(buf, "\t");

    for(i=0; i < max; i++) {
        token = strtok(NULL, " ");
	if (token)
	    field[i] = strdup(token);
	else
	    field[i] = "";
    }
}


void scan_int(char * buffer, int (*field)[], int max) {
    char * buf = buffer;
    int i;
    char * token = strtok(buf, "\t");

    for(i=0; i < max; i++) {
        token = strtok(NULL, " ");
        if (token)
	    (*field)[i] = atoi(token);
	else
	    (*field)[i] = -1;
    }
}

int main(int argc, char **argv) {

    FILE * isdninfo;
    char buf[IM_BUFSIZE];

    char * idmap[ISDN_MAX_CHANNELS];
    int chmap[ISDN_MAX_CHANNELS];
    int drmap[ISDN_MAX_CHANNELS];
    int usage[ISDN_MAX_CHANNELS];
    int flags[ISDN_MAX_DRIVERS];
    char * phone[ISDN_MAX_CHANNELS];

    int i, lines;

    isdninfo = fopen("/dev/isdn/isdninfo", "r");
    if (!isdninfo)
        isdninfo = fopen("/dev/isdninfo", "r");
    if (!isdninfo) {
	perror("imontty: can't open /dev/isdninfo");
        exit(1);
    }

    if (argc == 2)
       readphonebook(argv[1]);
    /* if too many args, OR phonebookarg and no phonenumbers found, give error*/
    if (argc > 2 || argc == 2 && phones == NULL) {
	fprintf(stderr, "imontty: usage:\n\timontty [phonebookfilename]\n\t\tdisplay ISDN channel usage\n");
	exit(2);
    }

    fgets(buf, IM_BUFSIZE, isdninfo);
    scan_str(buf, idmap, ISDN_MAX_CHANNELS);

    fgets(buf, IM_BUFSIZE, isdninfo);
    scan_int(buf, &chmap, ISDN_MAX_CHANNELS);

    fgets(buf, IM_BUFSIZE, isdninfo);
    scan_int(buf, &drmap, ISDN_MAX_CHANNELS);

    fgets(buf, IM_BUFSIZE, isdninfo);
    scan_int(buf, &usage, ISDN_MAX_CHANNELS);

    fgets(buf, IM_BUFSIZE, isdninfo);
    scan_int(buf, &flags, ISDN_MAX_DRIVERS);

    fgets(buf, IM_BUFSIZE, isdninfo);
    scan_str(buf, phone, ISDN_MAX_CHANNELS);

    fclose(isdninfo);

    printf("\n%s\n\n", "ISDN channel status:");
    printf("%-20.20s\t%-6.6s%-6.6s%s\n", "Channel", "Usage", "Type", "Number");
    printf("----------------------------------------------------------------------\n");

    lines = 0;
    for(i=0; i < ISDN_MAX_CHANNELS; i++)
        if (chmap[i] >= 0 && drmap[i] >= 0) {

	    /* printf("%-20.20s/%i\t", idmap[i], chmap[i]); */
	    printf("%-20.20s\t", idmap[i]);

            if (usage[i] & ISDN_USAGE_OUTGOING)
		printf("%-6.6s", "Out");
            else if (usage[i] == ISDN_USAGE_EXCLUSIVE)
		printf("%-6.6s", "Excl.");
            else if (usage[i])
		printf("%-6.6s", "In");
            else
		printf("%-6.6s", "Off");

            switch(usage[i] & ISDN_USAGE_MASK) {
		case ISDN_USAGE_RAW:
		    printf("%-6.6s", "raw");
		    break;
		case ISDN_USAGE_MODEM:
		    printf("%-6.6s", "Modem");
		    break;
		case ISDN_USAGE_NET:
		    printf("%-6.6s", "Net");
		    break;
		case ISDN_USAGE_VOICE:
		    printf("%-6.6s", "Voice");
		    break;
		case ISDN_USAGE_FAX:
		    printf("%-6.6s", "Fax");
		    break;
		default:
		    printf("%-6.6s", "");
		    break;
	    }

	    if(usage[i] & ISDN_USAGE_MASK)
		printf("%s\n", find_name(phone[i]));
            else
		printf("\n");

	    if( !(++lines % 2) )
		printf("\n");
	}
	return 0;
}
