#include <exec/types.h>
#include <exec/io.h>
#include <proto/exec.h>
#include <libraries/dosextens.h>
#include <proto/dos.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>

#include <dlg/dlg.h>
#include <dlg/conference.h>

#include <link/io.h>

#include <proto/dlg.h>

#include <pragmas/dlg.h>

#include <private/Version.h>
#define  ObjRev "1"
const UBYTE version[]="\0$VER: TPTConf " BUILDVER "." ObjRev " ©" COPYRIGHT " by Digerati Dreams "__AMIGADATE__;

void    HandleMsg(struct ConfMessage *);
struct  ConfMessage *GetNewMsg(void);
void    RecycleMsg(struct ConfMessage *);
struct  Conference *CopyConf(struct Conference *);
struct  UserList *CopyUsers(struct UserList *);
void    FreeConf(struct Conference *);
void    CleanUp(char *);
void   _CXBRK(void);


long   __stack        =  4000;
long   __priority     =   0;
long   __BackGroundIO =   1;
char  *__procname     = "TPTConf";
extern  BPTR _Backstdout;

struct Library *DLGBase = NULL;

struct MsgPort      *confctl;
struct Conference   *confhead = NULL;
struct ConfMessage  *freehead = NULL;
struct ConfMessage  *freetail = NULL;


void main(int argc, char **argv)

{struct ConfMessage *mymsg;
 long   confsig;

 if (!(DLGBase = OpenLibrary(DLGNAME, DLGVERSION)))  exit(5);

 Forbid();
 confctl = FindPort(CONFCONTROL);
 Permit();
 if (confctl)  CleanUp("TPTConf is already active");

 if (!(confctl = (struct MsgPort *)CreateMsgPort()))
       CleanUp("Unable to open control port");
 confctl->mp_Node.ln_Name =  CONFCONTROL;
 confsig                  = (1 << confctl->mp_SigBit);
 AddPort(confctl);

 AFPrintf(NULL, _Backstdout, "\n TPTConf installed successfully\n\n");
 for(;;)
    {Wait(confsig);

     while(mymsg = (struct ConfMessage *)GetMsg(confctl))
           HandleMsg(mymsg);
     Chk_Abort();
    }
}


void HandleMsg(struct ConfMessage *message)

{struct ConfMessage *tempmess;
 struct Conference  *conf, **confptr;
 struct UserList    *user, **userptr;
 struct MsgData     *mdata;
 UBYTE  exitflag;

 switch(message->type)
       {case CONFEXIT:    message->type = FNOERR;
                          ReplyMsg((struct Message *)message);
                          CleanUp(NULL);
                          break;

        case CREATECONF:  exitflag =   FALSE;
                          confptr  = &(confhead);

                          while(*confptr)
                               {if (strcmp((*confptr)->name,(char *)message->dataptr))
                                   {confptr = &((*confptr)->nextconf);
                                   }
                                 else
                                   {message->type=CONFEXISTS;
                                    ReplyMsg((struct Message *)message);
                                    exitflag = TRUE;
                                    break;
                                   }
                               }

                          if (exitflag) break;

                          conf = (struct Conference *)malloc(sizeof(struct Conference));
                          strcpy(conf->name, (char *)message->dataptr);
                          conf->user_level =  message->user_level;
                          conf->minbaud    =  message->baud;
                          conf->nextconf   =  NULL;
                          conf->users      = (struct UserList *)malloc(sizeof(struct UserList));
                          user             =  conf->users;
                          strcpy(user->name,message->username);
                          user->port     = message->mess.mn_ReplyPort;
                          user->nextuser = NULL;
                          message->conf  = conf;

                        (*confptr)      = conf;
                          message->type = FNOERR;
                          ReplyMsg((struct Message *)message);
                          break;

           case JOINCONF: conf = confhead;
                          while(conf)
                               {if (!strcmp(conf->name,(char *)message->dataptr)) break;
                                conf=conf->nextconf;
                               }

                          if (!conf)
                             {message->type=BADCONF;
                              ReplyMsg((struct Message *)message);
                              break;
                             }

                          if (message->user_level<conf->user_level)
                             {message->type=NOACCESS;
                              ReplyMsg((struct Message *)message);
                              break;
                             }

                          if (message->baud<conf->minbaud)
                             {message->type=TOOSLOW;
                              ReplyMsg((struct Message *)message);
                              break;
                             }

                          user = conf->users;
                          while(user->nextuser)
                                user = user->nextuser;

                         (user->nextuser) =  malloc(sizeof(struct UserList));
                          user            =  user->nextuser;
                          strcpy(user->name, message->username);
                          user->port      = (struct MsgPort *)message->mess.mn_ReplyPort;
                          user->nextuser  =  NULL;

                          message->conf = conf;
                          message->type = FNOERR;
                          ReplyMsg((struct Message *)message);
                          break;

          case LEAVECONF: conf    =   message->conf;
                          userptr = &(conf->users);

                          while((*userptr)&&(strcmp((*userptr)->name,message->username)))
                                  userptr=&((*userptr)->nextuser);

                          if (!(*userptr))
                             {message->type=NOACCESS;
                             }
                           else
                             {user=*userptr;
                            (*userptr)=(*userptr)->nextuser;
                              free(user);
                             }

                          if (!conf->users)
                             {confptr = &(confhead);
                              while((*confptr)&&((*confptr)!=conf))
                                      confptr=&((*confptr)->nextconf);

      if(!(*confptr)) {
   AFPrintf(NULL, _Backstdout, "Wierdness error - Conference dissipated into thin air!\n");
      }
      else {
   (*confptr)=(*confptr)->nextconf;
   free(conf);
      }
    }

    message->type=FNOERR;
    ReplyMsg((struct Message *)message);
    break;

  case LISTCONF:
    message->dataptr=(struct Conference *)CopyConf(confhead);
    message->type=FNOERR;
    ReplyMsg((struct Message *)message);
    break;

  case FREECONF:
    FreeConf(message->dataptr);
    message->type=FNOERR;
    ReplyMsg((struct Message *)message);
    break;

  case CONFMSG:
    conf=message->conf;

    message->type=CONFREPLY;
    mdata=(struct MsgData *)message->dataptr;
    mdata->outcount=0;
    mdata->origmess=message;

    user=conf->users;

    while(user) {
      if(Stricmp(user->name,message->username) &&
    ((message->topvt==NULL)||(!Stricmp(user->name,message->topvt)))) {
   (mdata->outcount)++;

   tempmess=(struct ConfMessage *)GetNewMsg();
   tempmess->type=CONFMSG;
   tempmess->username=message->username;
   tempmess->topvt=message->topvt;
   tempmess->mess.mn_ReplyPort=confctl;
   tempmess->dataptr=(struct MsgData *)mdata;

   PutMsg(user->port,(struct Message *)tempmess);
      }

      user=user->nextuser;
    }

    if(!(mdata->outcount)) {
      message->type=FNOERR;
      ReplyMsg((struct Message *)message);
    }

    break;

  case CONFREPLY:
    mdata=(struct MsgData *)message->dataptr;
    (mdata->outcount)--;

    if(!(mdata->outcount)) {
      tempmess=mdata->origmess;
      tempmess->type=FNOERR;
      ReplyMsg((struct Message *)tempmess);
    }

    RecycleMsg(message);
    break;

  case KILLCONF:
    ReplyMsg((struct Message *)message);
    break;

  default:
    message->type=BADTYPE;
    ReplyMsg((struct Message *)message);
    break;
  }
}

struct ConfMessage *GetNewMsg(void)
{
  struct ConfMessage *msgptr;

  if(freehead) {
    msgptr=freehead;
    freehead=(struct ConfMessage *)freehead->mess.mn_Node.ln_Succ;
    if(!freehead) freetail=NULL;
    return(msgptr);
  }
  else {
    msgptr=(struct ConfMessage *)malloc(sizeof(struct ConfMessage));
    return(msgptr);
  }
}

void RecycleMsg(struct ConfMessage *message)
{
  message->mess.mn_Node.ln_Succ=NULL;

  if(!freetail) freehead=freetail=message;
  else freetail->mess.mn_Node.ln_Succ=(struct Node *)message;
}

struct Conference *CopyConf(struct Conference *head)
{
  struct Conference *confptr, *newhead, **newptr;

  newhead=NULL;
  confptr=head;
  newptr=&newhead;

  while(confptr) {
    (*newptr)=(struct Conference *)malloc(sizeof(struct Conference));
    movmem(confptr,*newptr,sizeof(struct Conference));

    (*newptr)->users=(struct UserList *)CopyUsers(confptr->users);

    newptr=&((*newptr)->nextconf);
    confptr=confptr->nextconf;
  }

  return(newhead);
}


struct UserList *CopyUsers(struct UserList *userlist)

{struct UserList *uptr, *newhead, **newptr;

 newhead =  NULL;
 uptr    =  userlist;
 newptr  = &newhead;

 while(uptr)
      {(*newptr)=(struct UserList *)malloc(sizeof(struct UserList));
        movmem(uptr,*newptr,sizeof(struct UserList));

       newptr = &((*newptr)->nextuser);
       uptr   = uptr->nextuser;
      }

 return(newhead);
}


void FreeConf(struct Conference *head)

{struct Conference *conf;
 struct UserList   *user;
 struct UserList   *tempuser;

 while(head)
      {user = head->users;

       while(user)
            {tempuser = user;
             user     = user->nextuser;
             free(tempuser);
            }

       conf = head;
       head = head->nextconf;
       free(conf);
      }
}


void CleanUp(char *s)

{if (s)
    {Write(_Backstdout, "\n Error: ", 9);
     Write(_Backstdout,  s,    strlen(s));
     Write(_Backstdout, "\n\n",       2);
    }
  else
     Write(_Backstdout, "\n TPTConf exiting...\n\n", 22);

 while(freehead)
      {freetail=freehead;
       freehead=(struct ConfMessage *)freehead->mess.mn_Node.ln_Succ;
       free(freetail);
      }

 FreeConf(confhead);

 if (confctl)
    {RemPort(confctl);
     DeleteMsgPort(confctl);
    }

 CloseLibrary(DLGBase);
 Close(_Backstdout);

 exit(s?5:0);
}


void _CXBRK(void)

{CleanUp(NULL);
}
