/*
 * This is Ping-Pong convers/conversd derived from the wampes
 * convers package written by Dieter Deyke <deyke@mdddhd.fc.hp.com>
 *
 * Modifications by Fred Baumgarten <dc6iq@insu1.etec.uni-karlsruhe.de>
 * $Revision: 2.99 $$Date: 1994/10/02 10:33:12 $
 */

#define REV "$Revision: 2.99 $"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "conversd.h"
#include "host.h"
#include "user.h"

/*---------------------------------------------------------------------------*/

void h_away_command(cp)
struct connection *cp;
{
  char *fromname, *hostname, *text;
  int channel;
  long time;
  struct connection *p;
  struct clist *cl;
  int found = 0;

  fromname = getarg(0, 0);
  hostname = getargcs(0, 0);
  channel = atoi(getarg(0, 0));
  time = atol(getarg(0, 0));
  text = getarg(0, 1);
  cp->locked = 1;
  for (p = connections; p; p = p->next) {
    if (p->type == CT_USER) {
      if (p->channel == channel) found++;
      for (cl = p->chan_list; cl; cl = cl->next) {
	if (cl->channel == channel) {
	  found++;
	  break;
	}
      }
      if (!strcmp(p->name, fromname) && !strcmp(p->host, hostname) && found) {
	strcpy(p->away, text);
	p->atime = time;
      }
    }
  }
  send_awaymsg(fromname, hostname, channel, time, text);
}

/*---------------------------------------------------------------------------*/

void h_cmsg_command(cp)
struct connection *cp;
{

  char *text;
  char *name;
  int channel;

  name = getarg(0, 0);
  channel = atoi(getarg(0, 0));
  text = getarg(0, 1);
  if (*text) send_msg_to_channel(name, channel, text);
}

/*---------------------------------------------------------------------------*/

void h_dest_command(cp)
struct connection *cp;
{
  char *name, *rev;
  int pl, rtt;
  struct permlink *l;

  name = getargcs(0, 0);
  rtt = atoi(getarg(0, 0));
  rev = getarg(0, 0);
  for (pl = 0; pl < NR_PERMLINKS; pl++) {
    l = permarray[pl];
    if (l && l->connection && (l->connection == cp)) break;
  }
  if (l) update_destinations(l, name, rtt, rev);
}

/*---------------------------------------------------------------------------*/

void h_host_command(cp)
struct connection *cp;
{
  char *name;
  char *rev;
  char *features;
  char buffer[2048];
  struct connection *p;
  struct destination *d;
  struct permlink *pp;
  struct channel *ch;
  struct clist *cl;
  int pl;
  char flags[16];

  name = getargcs(0, 0);
  rev = getarg(0, 0);
  features = getarg(0, 0);
  if (!*name) return;
  
  for (pl = 0; pl < NR_PERMLINKS; pl++) {
    pp = permarray[pl];
    if (pp && pp->connection && (pp->connection != cp) && !strcmp(pp->name, name)) {
      bye_command2(pp->connection, "link reorg");
    }
    update_destinations(pp, name, 0, rev);
  }
  if (cp->type != CT_UNKNOWN) return;
  cp->type = CT_HOST;
  strcpy(cp->rev, rev);
  strcpy(cp->name, name);
  if (strchr(features,'u')) cp->amprnet = 1;
  update_permlinks(name, cp, 0);
  sprintf(buffer, "/\377\200HOST %s %s %s\n", myhostname, myrev, myfeatures);
  appendstring(cp, buffer);
  for (p = connections; p; p = p->next) {
    if (p->type == CT_USER) {
      if (!p->via) {
	for (cl = p->chan_list; cl; cl = cl->next) {
	  if (cp->amprnet) {
	    sprintf(buffer, "/\377\200USER %s %s %ld -1 %d %s\n", p->name, p->host, cl->time, cl->channel, p->pers);
	    appendstring(cp, buffer);
	  } else {
	    sprintf(buffer, "/\377\200USER %s %s %ld -1 %d\n", p->name, p->host, cl->time, cl->channel);
	    appendstring(cp, buffer);
	    if (strcmp(p->name, "@")) {
	      sprintf(buffer, "/\377\200UDAT %s %s %s\n", p->name, p->host, p->pers);
	      appendstring(cp, buffer);
	    }
	  }
	  if (*p->away) {
	    sprintf(buffer, "/\377\200AWAY %s %s %d %ld %s\n", p->name, p->host, cl->channel, p->atime, p->away);
	    appendstring(cp, buffer);
	  }
	  if (cl->channelop) {
	    sprintf(buffer, "/\377\200OPER conversd %d %s\n", cl->channel, p->name);
	    appendstring(cp, buffer);
	  }
	  if (p->operator) {
	    sprintf(buffer, "/\377\200OPER conversd -1 %s\n", p->name);
	    appendstring(cp, buffer);
	  }
	}
      } else {
	if (cp->amprnet) {
	  sprintf(buffer, "/\377\200USER %s %s %ld -1 %d %s\n", p->name, p->host, p->time, p->channel, p->pers);
	  appendstring(cp, buffer);
	} else {
	  sprintf(buffer, "/\377\200USER %s %s %ld -1 %d\n", p->name, p->host, p->time, p->channel);
	  appendstring(cp, buffer);
	  sprintf(buffer, "/\377\200UDAT %s %s %s\n", p->name, p->host, p->pers);
	  appendstring(cp, buffer);
	}
	if (*p->away) {
	  sprintf(buffer, "/\377\200AWAY %s %s %d %ld %s\n", p->name, p->host, p->channel, p->atime, p->away);
	  appendstring(cp, buffer);
	}
	if (p->channelop) {
	  sprintf(buffer, "/\377\200OPER conversd %d %s\n", p->channel, p->name);
	  appendstring(cp, buffer);
	}
	if (p->operator) {
	  sprintf(buffer, "/\377\200OPER conversd -1 %s\n", p->name);
	  appendstring(cp, buffer);
	}
      }
    }
  }
  for (ch = channels; ch; ch = ch->next) {
    if (*ch->topic) {
      sprintf(buffer, "/\377\200TOPI conversd %s %ld %d %s\n", myhostname, ch->time, ch->chan, ch->topic);
      appendstring(cp, buffer);
      flags[0] = '\0';
      if (ch->flags & M_CHAN_S) {
	strcat(flags, "s");
      }
      if (ch->flags & M_CHAN_P) {
	strcat(flags, "p");
      }
      if (ch->flags & M_CHAN_T) {
	strcat(flags, "t");
      }
      if (ch->flags & M_CHAN_I) {
	strcat(flags, "i");
      }
      if (ch->flags & M_CHAN_M) {
	strcat(flags, "m");
      }
      if (ch->flags & M_CHAN_L) {
	strcat(flags, "l");
      }
      sprintf(buffer, "/\377\200MODE %d -sptiml+%s\n", ch->chan, flags);
      appendstring(cp, buffer);
    }
  }
  for (d = destinations; d; d = d->next) {
    if (d->rtt) {
      sprintf(buffer, "/\377\200DEST %s %ld %s\n", d->name, d->rtt + 99, d->rev);
      appendstring(cp, buffer);
    }
  }
}

/*---------------------------------------------------------------------------*/

void h_invi_command(cp)
struct connection *cp;
{

  char *fromname, *toname;
  int channel;

  fromname = getarg(0, 0);
  toname = getarg(0, 0);
  channel = atoi(getarg(0, 0));
  send_invite_msg(fromname, toname, channel);
}

/*---------------------------------------------------------------------------*/

void h_oper_command(cp)
struct connection *cp;
{
  char *toname, *fromname;
  int channel;
  struct connection *p;
  struct clist *cl;

  fromname = getarg(0, 0);
  channel = atoi(getarg(0, 0));
  toname = getarg(0, 0);
  cp->locked = 1;

  for (p = connections; p; p = p->next) {
    if (channel == -1) {
      if ((!strcmp(p->name, toname)) && (p->type == CT_USER)) {
        p->operator = 1;
        send_opermsg(toname, p->host, fromname, -1);
      }
    } else {
      if (!strcmp(p->name, toname)) {
        if (p->channel == channel) {
          p->channelop = 1;
        }
        for (cl = p->chan_list; cl; cl = cl->next) {
          if (cl->channel == p->channel) cl->channelop = 1;
        }
        send_opermsg(toname, p->host, cp->name, p->channel);
      }
    }
  }
}

/*---------------------------------------------------------------------------*/

void h_ping_command(cp)
struct connection *cp;
{
  char buffer[2048];
  int pl;

  for (pl = 0; pl < NR_PERMLINKS; pl++) {
    if (permarray[pl] && (permarray[pl]->connection == cp)) {
      sprintf(buffer, "/\377\200PONG %ld\n", permarray[pl]->txtime);
      appendstring(cp, buffer);
    }
  }
}

/*---------------------------------------------------------------------------*/

void h_pong_command(cp)
struct connection *cp;
{
  struct permlink *l;
  int pl;

  l = NULLPERMLINK;
  for (pl = 0; pl < NR_PERMLINKS; pl++) {
    if (permarray[pl] && (permarray[pl]->connection == cp)) {
      l = permarray[pl];
      l->rxtime = atol(getarg(0,0));
      l->txtime = max(currtime - l->testwaittime, 1);
      if (l->rxtime == 0) l->rxtime = l->txtime;
      if ((abs(l->rxtime) > 20001) || (abs(l->txtime) > 20001)) {
	l->rxtime = 0;
	l->txtime = 0;
      }
      l->testnexttime = l->testwaittime + max(min(60 * (l->txtime), 7200), 120);
      /* I hacked this because of it's nasty behave - rewrite of the whole stuff is in progress */
      update_destinations(l, l->name,
			  (l->rxtime == -1) ? l->txtime : (l->rxtime + l->txtime) / 2L,
			  cp->rev);
      break;
    }
  }
}

/*---------------------------------------------------------------------------*/

void h_rout_command(cp)
struct connection *cp;
{
  char *dest, *user;
  struct destination *d;
  char buffer[2048];
  int ttl;

  dest = getargcs(0, 0);
  user = getarg(0, 0);
  ttl = atoi(getarg(0, 0));
  clear_locks();
  for (d = destinations; d; d = d->next) {
    if (!strcmp(d->name, dest)) {
      sprintf(buffer, "*** route: %s -> %s -> %s (%ld)", myhostname, d->link->name, dest, d->rtt);
      send_msg_to_user("conversd", user, buffer);
      if (ttl && strcmp(d->link->name, dest)) {
	ttl--;
	sprintf(buffer, "/\377\200ROUT %s %s %d\n", dest, user, ttl);
	appendstring(d->link->connection, buffer);
      }
    }
  }
}

/*---------------------------------------------------------------------------*/

void h_topi_command(cp)
struct connection *cp;
{
  char *fromname, *hostname, *text;
  int channel;
  long time;

  fromname = getarg(0, 0);
  hostname = getargcs(0, 0);
  time = atol(getarg(0, 0));
  channel = atoi(getarg(0, 0));
  text = getarg(0, 1);
  cp->locked = 1;
  send_topic(fromname, hostname, time, channel, text);
}

/*---------------------------------------------------------------------------*/

void h_udat_command(cp)
struct connection *cp;
{
  char *fromname, *hostname, *text;
  struct connection *p;

  fromname = getarg(0, 0);
  hostname = getargcs(0, 0);
  text = getarg(0, 1);
  cp->locked = 1;
  for (p = connections; p; p = p->next) {
    if (p->type == CT_USER && !strcmp(p->name, fromname) &&
        !strcmp(p->host, hostname) && strcmp(p->pers, text)) {
      if (p) {
	strcpy(p->pers, text);
      }
      send_persmsg(fromname, hostname, p->channel, text, currtime);
    }
  }
}

/*---------------------------------------------------------------------------*/

void h_umsg_command(cp)
struct connection *cp;
{
  char *fromname, *toname, *text;

  fromname = getarg(0, 0);
  toname = getarg(0, 0);
  text = getarg(0, 1);
  if (*text) send_msg_to_user(fromname, toname, text);
}

/*---------------------------------------------------------------------------*/

void h_user_command(cp)
struct connection *cp;
{
  char *host;
  char *name;
  char *pers;
  int newchannel;
  int oldchannel;
  struct connection *p;
  struct channel *ch;
  int users_left;
  long time;

  name = getarg(0, 0);
  host = getargcs(0, 0);
  time = atol(getarg(0, 0));
  if (time == 0) time = currtime;
  oldchannel = atoi(getarg(0, 0));
  newchannel = atoi(getarg(0, 0));
  pers = getarg(0, 1);

  for (p = connections; p; p = p->next) {
    if (p->type == CT_USER) {
      if ((p->via == cp) &&
	  !strcmp(p->name, name) && 
	  !strcmp(p->host, host) && 
	  p->channel == oldchannel) break;
    }
  }
  if (!p) {
    p = (struct connection *) calloc(1, sizeof(*p));
    p->type = CT_USER;
    strcpy(p->name, name);
    strcpy(p->host, host);
    p->via = cp;
    p->channel = oldchannel;
    p->fd = -1;
    p->query[0] = '\0';
    p->notify[0] = '\0';
    p->next = connections;
    connections = p;
  }
  p->time = time;
  p->mtime = time;
  if (pers && *pers) strcpy(p->pers, pers);
  if ((p->channel = newchannel) < 0) {
    p->type = CT_CLOSED;
  }
  users_left = count_user(oldchannel);
  if (!users_left) destroy_channel(oldchannel);
  for (ch = channels; ch; ch=ch->next) {
    if (ch->chan == newchannel) break;
  }
  if (!ch && (newchannel != -1)) {
    ch = (struct channel *) malloc(sizeof(struct channel));
    ch->next = channels;
    ch->topic[0] = '\0';
    ch->chan = newchannel;
    ch->time = 0;
    ch->name[0] = '\0';
    ch->flags = 0;
    channels = ch;
  }
  send_user_change_msg(name, host, oldchannel, newchannel, pers, time);
}
