TinyMAZE/
TinyMAZE/config/
TinyMAZE/doc/
TinyMAZE/run/msgs/
TinyMAZE/src/
TinyMAZE/src/db/
TinyMAZE/src/ident/
TinyMAZE/src/io/
TinyMAZE/src/prog/
TinyMAZE/src/softcode/
TinyMAZE/src/util/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "db.h"
#include "externs.h"
#include "paste.h"
#include "powers.h"

PASTE *paste_stack = NULL;

PASTE *find_paste(DDATA *des)
{
  PASTE *p;

  for(p = paste_stack;p;p = p->next)
    if(p->des == des)
      return(p);

  return(NULL);
}

bool is_pasting(DDATA *des)
{
  return((des->mode == MODE_PASTE));
}

static void add_to_stack(DDATA *des, OBJ *who, ATTR *attr,
                         COM *channel, PROG *program)
{
  PASTE *new;

  new = (PASTE *)stack_alloc(sizeof(PASTE), 1, 0);

  new->next = paste_stack;
  paste_stack = new;

  new->des = des;
  new->who = who;
  new->paste = NULL;
  new->attr = attr;
  new->channel = channel;
  new->program = program;
}

void remove_paste(DDATA *des)
{
  PASTE *p, *pprev = NULL;
  struct pastey *q, *qnext;

  for(p = paste_stack;p;p = p->next)
  {
    if(p->des == des)
      break;
    pprev = p;
  }

  if(!p)
    return;

  for(q = p->paste;q;q = qnext)
  {
    qnext = q->next;
    stack_free(q->str);
    stack_free(q);
  }

  if(!pprev)
    paste_stack = p->next;
  else
    pprev->next = p->next;

  if(p == paste_stack)
    paste_stack = NULL;

  stack_free(p);
  des->mode = MODE_NORMAL;
}

void do_paste(DDATA *des, char *arg1, char *arg2)
{
  OBJ *who = NULL;
  ATTR *attr = NULL;
  COM *channel = NULL;
  PROG *program = NULL;
  char *p;

  if(is_pasting(des))
  {
    notify(des->player, "Clearing old paste, starting fresh.");
    remove_paste(des);
  }

  if(*arg1)
  {
/* See if they're pasting to a channel or program */
    if(*arg2)
    {
      if(string_prefix("channel", arg1))
      {
        channel = find_channel(des->player, arg2);

        if(!channel || !is_on_channel(des->player, channel, 1))
        {
          notify(des->player, tprintf("You're not on channel \"%s\"!",
            arg2));
          return;
        } 
      }
      else if(string_prefix("program", arg1))
      {
        if(!(p = strchr(arg2, ',')))
        {
          notify(des->player, "Illegal syntax!");
          return;
        }

        *p++ = '\0';

        if(!(who = match_object(des->player, arg2, NOTYPE)))
        {
          notify(des->player, no_match(arg2));
          return;
        }

        if(!(program = find_prog(who, p)))
        {
          add_new_prog(des->player, who, p);
          if(!(program = find_prog(who, p)))
            return;
        }
      }
      else 
      {
        notify(des->player, "Illegal syntax!");
        return;
      }
    }
    else
    {
/* Check if they're pasting to an attribute */
      if((p = strchr(arg1, '/')))
        *p++ = '\0';

      if(!(who = match_object(des->player, arg1, NOTYPE)))
      {
        notify(des->player, no_match(arg1));
        return;
      }

      if(!could_doit(des->player, who, "LPAGE"))
      {
        notify(des->player,
          "Sorry, that player is page-locked against you.");
        return;
      }

      if(p)
      {
        if(!controls(des->player, who, POW_MODIFY) && p)
        {
          notify(des->player, perm_denied());
          return;
        }

        if(!(attr = find_attr(p)))
        {
          notify(des->player, "No match.");
          return;
        }
      }
    }
  }

  add_to_stack(des, who, attr, channel, program);

  notify(des->player,
    "Enter lines to be pasted. End input with a period (.) or type '@pasteabort'.");

/* Process their output now or they'll never know they're in paste mode */
/* because their output is held in paste mode */
  process_output(des);
  des->mode = MODE_PASTE;
}

static void do_end_paste(DDATA *des)
{
  PASTE *p;
  char *s;
  struct pastey *q;
  char buf[1024];
  int linenum;

  if(!(p = find_paste(des)))
    return;

  des->mode = MODE_NORMAL;

  if(p->attr)
  {
    if(!p->paste)
      atr_clr_a(p->who, p->attr);
    else
      atr_add_a(p->who, p->attr, p->paste->str);

    notify(des->player, tprintf("%s - Set.", name(p->who)));
    return;
  }

  if(p->channel)
  {
    com_send(p->channel->name, NULL,
      tprintf("|+W|----- |+B|Begin @paste text from %s |+W|-----",
      name(des->player)));
    for(q = p->paste;q;q = q->next)
      com_send(p->channel->name, NULL, q->str);
    com_send(p->channel->name, NULL,
      tprintf("|+W|----- |+B|End @paste text from %s |+W|-----",
      name(des->player)));
    return;
  }

  if(p->program)
  {
    for(q = p->paste;q;q = q->next)
    {
      if(is_running(p->program))
      {
        notify(des->player,
          "You may not modify a program while it is running.");
        return;
      }

      for(s = q->str;isdigit(*s);s++);    /* Whole loop */

      if(!(s-q->str))
      {
        if(!(linenum = next_line_num(p->program)))
        {
          notify(des->player, "Error! Next line number would exceed 65535.");
          return;
        }
      }
      else
      {
        strncpy(buf, q->str, s-q->str);
        *(buf+(s-q->str)) = '\0';
        linenum = atoi(buf);
        if(linenum < 1 || linenum > 65535)
        {
          notify(des->player, "Valid line numbers are 1 through 65535.");
          return;
        }
        if(*s)
          s++;
      }

      if(!*s)
        del_prog_line(p->program, linenum);
      else
        add_prog_line(p->program, linenum, s);
    }
    notify(des->player, "Program modified.");
    return;
  }

  sprintf(buf, "|+W|----- |+B|Begin @paste text from %s |+W|-----",
    name(des->player));

  if(!(p->who))
    notify_in(des->player->location, NULL, buf);
  else
    notify(p->who, buf);

  for(q = p->paste;q;q = q->next)
  {
    if(!(p->who))
      notify_in(des->player->location, NULL, q->str);
    else
      notify(p->who, q->str);
  }

  sprintf(buf, "|+W|----- |+B|End @paste text from %s |+W|-----",
    name(des->player));

  if(!(p->who))
    notify_in(des->player->location, NULL, buf);
  else
  {
    notify(p->who, buf);
    notify(des->player, tprintf("@paste text sent to %s.",
      unparse_object(des->player, p->who)));
  }
}

void add_more_paste(DDATA *des, char *str)
{
  PASTE *p;
  struct pastey *q, *qnew, *qprev = NULL;

  if(!strcmp(str, "."))
  {
    do_end_paste(des);
    remove_paste(des);
    return;
  }

  if(!string_compare("@pasteabort", str))
  {
    remove_paste(des);
    notify(des->player, "@paste aborted.");
    return;
  }

  if(!(p = find_paste(des)))
    return;

  if(p->attr)
  {
    if(!p->paste)
    {
      p->paste = (struct pastey *)stack_alloc(sizeof(struct pastey), 1, 0);
      SET(p->paste->str, str);
      p->paste->next = NULL;
    }
    else
    {
      p->paste->str = (char *)stack_realloc(p->paste->str,
        strlen(p->paste->str)+strlen(str)+1);
      strcpy(p->paste->str+strlen(p->paste->str), str);
    }

    return;
  }

  qnew = (struct pastey *)stack_alloc(sizeof(struct pastey), 1, 0);
  SET(qnew->str, str);
  qnew->next = NULL;

  for(q = p->paste;q;q = q->next)
    qprev = q;

  if(!qprev)
    p->paste = qnew;
  else
    qprev->next = qnew;
}

void do_pastestats(OBJ *player, char *arg)
{
  PASTE *p;
  struct pastey *q;
  int i, size;
  char buf[1024];
  int num_pastes = 0;

  if(!power(player, POW_MISC))
  {
    notify(player, perm_denied());
    return;
  }

  if(!paste_stack)
  {
    notify(player, "There are no @paste texts being created.");
    return;
  }

  if(!*arg)
  {
    for(p = paste_stack;p;p = p->next)
    {
      size = 0;

      for(q = p->paste;q;q = q->next)
        size += strlen(q->str)+1;

      if(!(p->who))
        strcpy(buf, "NOBODY");
      else
      {
        strcpy(buf, name(p->who));

        if(p->attr)
          sprintf(buf+strlen(buf), "/%s", p->attr->name);
        if(p->channel)
          sprintf(buf+strlen(buf), "CHANNEL %s", p->channel->name);
        if(p->program)
          sprintf(buf+strlen(buf), "PROGRAM %s", p->program->name);
      }

      notify(player, tprintf("%d: %s -> %s: %d bytes",
        ++num_pastes, name(p->des->player), buf, size));
    }
    return;
  }

  for(p = paste_stack;p;p = p->next)
    num_pastes++;

  if(atoi(arg) < 1 || atoi(arg) > num_pastes)
  {
    notify(player, tprintf("Valid @pastes: 1 - %d", num_pastes));
    return;
  }

  i = 0;

  for(p = paste_stack;p;p = p->next)
  {
    if(++i == atoi(arg))
      break;
  }

  if(!p)       /* Shouldn't happen */
    return;

  size = 0;

  for(q = p->paste;q;q = q->next)
    size += strlen(q->str)+1;

  if(!(p->who))
    strcpy(buf, "NOBODY");
  else
  {
    strcpy(buf, name(p->who));

    if(p->attr)
      sprintf(buf+strlen(buf), "/%s", p->attr->name);
    if(p->channel)
      sprintf(buf+strlen(buf), "CHANNEL %s", p->channel->name);
    if(p->program)
      sprintf(buf+strlen(buf), "PROGRAM %s", p->program->name);
  }

  notify(player, buf);
  notify(player, "|+B|------ |+W|BEGIN |+B|------");

  for(q = p->paste;q;q = q->next)
    notify(player, q->str);

  notify(player, "|+B|------  |+W|END  |+B|------");
}