#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <dos.h>
#include <exec/types.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <libraries/dosextens.h>

#include <devices/tpt.h>

#include <dlg/dlg.h>
#include <dlg/resman.h>
#include <dlg/cron.h>
#include <dlg/conference.h>
#include <dlg/user.h>
#include <dlg/portconfig.h>
#include <dlg/menu.h>
#include <dlg/input.h>
#include <dlg/log.h>

#include <link/io.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/dlg.h>

#include <pragmas/dlg.h>

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

#define READPORT_SIG  (1 << readport->mp_SigBit)
#define CONFPORT_SIG  (1 << confport->mp_SigBit)

#define STK RStruct.Command_Stack
#define HOT UserDat.Hot_Keys

int   HandleBuiltIn(UBYTE);
void  AsyncRead(void);
void  OpenConf(void);
void  PurgeMessages(void);
void  WaitForReply(void);
void  CleanUp(char *);
void  LetsGetOutOfHere(void);
void _CXBRK(void);


UBYTE                  Ext[4];
struct USER_DATA       UserDat;
struct Ram_File        RStruct;
struct UserInfo        ui      = {&UserDat, &RStruct};
struct Query           q       = {NULL, NULL, NULL, NULL, NULL, 0, 0, 0};

struct MsgPort        *readport;
struct MsgPort        *confctl;
struct MsgPort        *confport;
struct ConfMessage    *mymsg;
struct ConfMessage    *inmsg;
struct MsgData        *mydata;
struct MsgData        *indata;
struct FileHandle     *fh;
struct StandardPacket *mypacket;
struct Conference     *conf;
struct UserList       *user;

struct NewShortMenu Menu[6] = {{"Abort",1},
                               {"CONFU_CreateRoom",1},
                               {"CONFU_EnterRoom",1},
                               {"CONFU_Exit",1},
                               {"CONFU_ListRooms",1},
                               {"CONFU_ListUsers",1}
                              };


char  Overlay      =  FALSE;
char  MenuName[13] = "Conf_Main";
UBYTE InConf       =  FALSE;
UBYTE exitflag     =  FALSE;
UBYTE Enable_Abort =  FALSE;

UBYTE buf[256];
char  confname[21];

struct Library    *DLGBase = NULL;
BPTR               infh;
BPTR               sout;
struct LangStruct *ls;
char             **SA;


void main(int argc,char **argv)

{long   signals;
 long   charsread;
 char  *s;
 char  *stack = NULL;
 USHORT pos   =  1;

 sout =  Output();
 infh =  Input();
 fh   = (struct FileHandle *)BADDR(infh);
 if (!(DLGBase = OpenLibrary(DLGNAME, DLGVERSION)))  exit(5);

 while(--argc > 0)
      {s = *++argv;
       if (*s++=='-')
          {while(*s)
                {switch(toupper(*s))
                       {case 'O':  Overlay=TRUE;
                                   break;

                        case 'S':  if (!--argc)  break;
                                   stack = *++argv;
                                   break;

                        case 'M':  if (!--argc)  break;
                                   strncpy(MenuName,*++argv,12);
                                   MenuName[12] = '\0';
                                   break;
                       }

                 s++;
                }
          }
      }


 if (GetDevName(Ext)==-1)   CleanUp("Unable to find Handler Port");
 if (!(ls = GetLang(Ext)))  CleanUp("Unable to read language file");
 SA = ls->strings;

 if (!ReadUser(&RStruct,&UserDat,Ext))  CleanUp("Unable to read user data");
 if (stack)                            InsertStack(STK, stack);

 WriteLog(CONF, RStruct.Name, Ext, "");

 mypacket = malloc(sizeof(struct StandardPacket));
 if (!mypacket) CleanUp("Unable to allocate memory");

 mypacket->sp_Msg.mn_Node.ln_Name = (char *)&(mypacket->sp_Pkt);
 mypacket->sp_Pkt.dp_Link         = (struct Message *)&(mypacket->sp_Msg);
 mypacket->sp_Pkt.dp_Type         =  ACTION_READ;
 mypacket->sp_Pkt.dp_Arg1         =  fh->fh_Arg1;
 mypacket->sp_Pkt.dp_Arg2         = (long)buf;
 mypacket->sp_Pkt.dp_Arg3         =  255;

 readport = (struct MsgPort *)CreateMsgPort();
 if (!readport)  CleanUp("Unable to open message port");

 confport = (struct MsgPort *)CreateMsgPort();
 if (!confport)  CleanUp("Unable to open message port");

 mymsg = malloc(sizeof(struct ConfMessage));
 if (!mymsg)  CleanUp("Unable to allocate memory");
 mymsg->mess.mn_Node.ln_Type = NT_MESSAGE;
 mymsg->mess.mn_ReplyPort    = confport;
 mymsg->mess.mn_Length       = sizeof(struct ConfMessage);

 mydata = malloc(sizeof(struct MsgData));
 if (!mydata)  CleanUp("Unable to allocate memory");

 for(;;)
    {mymsg->username   = RStruct.Name;
     mymsg->baud       = RStruct.Baud_Rate;
     mymsg->user_level = UserDat.User_Level;

     exitflag     = FALSE;
     Enable_Abort = TRUE;

     do{chkabort();

        if (MenuInput(MenuName,Ext,"CONFU",Menu,6,HandleBuiltIn,&UserDat,&RStruct,UserDat.Help_Level,NULL)==MENUNOTFOUND)
            CleanUp("Unable to get menu");
       } while(!exitflag);

     InConf = TRUE;
     ASPrintf(NULL, RStruct.Action, SA[2637], confname);
     WriteRam(&RStruct, Ext);

     AFPrintf(NULL, sout, SA[2638], confname);

     if (!strncmp(Ext,"TL",2))
        {ASPrintf(NULL, buf, SA[2639], Ext);
         CronEvent(ADDEVENT,0L,buf);
        }

     TUnSetFlags(T_RAW | T_LINEFREEZE,Ext);

     mymsg->dataptr = (struct MsgData *)mydata;

     exitflag = FALSE;
     AsyncRead();

     do{signals = Wait(READPORT_SIG | CONFPORT_SIG);

        if (signals & READPORT_SIG)
           {WaitPort(readport);
            GetMsg(readport);

            Enable_Abort = TRUE;
            chkabort();
            Enable_Abort = FALSE;

            charsread = (int)mypacket->sp_Pkt.dp_Res1;
            buf[charsread] = '\0';

            if (*buf=='%')
               {switch(*(buf+1))
                      {case 'p':
                       case 'P':  for(s=(char *)(buf+2);(*s)&&(*s!='%');s++);
                                      if (*s)
                                         {*s='\0';
                                           mymsg->type      =  CONFMSG;
                                           mymsg->topvt     = (char *)(buf+2);
                                           mydata->outcount =  0;
                                           mydata->buffer   =  s+1;
                                           PutMsg(confctl,(struct Message *)mymsg);

                                           AFPrintf(NULL, sout, SA[2640],RStruct.Name);
                                           DisplayBuffer(Output(),s+1,UserDat.Screen_Width,UserDat.Screen_Len,0,UserDat.Ansi_Flag,&pos,strlen(RStruct.Name)+3,NULL,1,NULL);
                                          }
                                        else
                                          {AFPrintf(NULL, sout, SA[2641]);
                                           AsyncRead();
                                          }
                                  break;

                        default:  AFPrintf(NULL, sout, SA[2642]);
                                  AsyncRead();
                 }
               }
             else
               if (!Stricmp(buf,SA[2643]))
                    exitflag = TRUE;
                  else
                   {mymsg->type=CONFMSG;
                    mymsg->topvt=NULL;
                    mydata->outcount=0;
                    mydata->buffer=(char *)buf;
                    PutMsg(confctl,(struct Message *)mymsg);

                    AFPrintf(NULL, sout, SA[2640],RStruct.Name);
                    DisplayBuffer(Output(),buf,UserDat.Screen_Width,UserDat.Screen_Len,0,UserDat.Ansi_Flag,&pos,strlen(RStruct.Name)+3,NULL,1,NULL);
                   }
           }

        if (signals & CONFPORT_SIG)
           {while(inmsg = (struct ConfMessage *)GetMsg(confport))
                 {if (inmsg->type==CONFMSG)
                     {indata = (struct MsgData *)inmsg->dataptr;
                      AFPrintf(NULL, sout, SA[2640],inmsg->username);

                      if (inmsg->topvt)
                         {AFPrintf(NULL, sout, SA[2644]);
                          DisplayBuffer(Output(),indata->buffer,UserDat.Screen_Width,UserDat.Screen_Len,0,UserDat.Ansi_Flag,&pos,strlen(inmsg->username)+9,NULL,1,NULL);
                    }
                  else
                         {DisplayBuffer(Output(),indata->buffer,UserDat.Screen_Width,UserDat.Screen_Len,0,UserDat.Ansi_Flag,&pos,strlen(inmsg->username)+3,NULL,1,NULL);
                         }

                      inmsg->type=CONFREPLY;
                      ReplyMsg((struct Message *)inmsg);
                }
              else
                      AsyncRead();
                 }
           }
       } while(!exitflag);


     LetsGetOutOfHere();
    }
}


int HandleBuiltIn(UBYTE cmd)

{char bcstring[256];
 char comment [61];

 switch(cmd)
       {case 0:         /* Abort */
                WriteRam(&RStruct,Ext);
                CleanUp(NULL);
                break;

        case 1:         /* CONFU_CreateRoom */
                Chk_Abort();
                q.prompt     = SA[2645];
                q.string     = confname;
                q.defstring  = NULL;
                q.length     = 20;
                q.typelength = 20;
                q.flags      = QUERY_CAPITAL;
                if (!DLGQuery(&q, &ui))
                   {AFPrintf(NULL, sout, "\n\n");
                    break;
                   }

                StripSpaces(confname);
                mymsg->baud       = IntQuery(SA[2646], 300, 9600, 300, &ui);
                mymsg->user_level = IntQuery(SA[2647],   0, UserDat.User_Level, 1, &ui);

                ASPrintf(NULL, bcstring, SA[2648], confname, RStruct.Name);
                Chk_Abort();
                q.prompt     = SA[2649];
                q.string     = comment;
                q.defstring  = NULL;
                q.length     = 59;
                q.typelength = 59;
                q.flags      = 0;
                if (DLGQuery(&q, &ui))
                   {Inform("ALL", bcstring, Ext, 0);
                    ASPrintf(NULL,bcstring,SA[2650],comment);
                    Inform("ALL",bcstring,Ext,0);
                   }
                 else
                    Inform("ALL",bcstring,Ext,0);

                mymsg->type    =  CREATECONF;
                mymsg->dataptr = (char *)confname;
                AFPrintf(NULL, sout, "\n\n");
                OpenConf();
                PutMsg(confctl, (struct Message *)mymsg);
                WaitPort(confport);
                GetMsg(confport);

                if (mymsg->type==FNOERR)
                    exitflag = TRUE;
                  else
                    if (mymsg->type==CONFEXISTS)
                        AFPrintf(NULL, sout, SA[2651]);
                break;

        case 2:         /* CONFU_EnterRoom */
                Chk_Abort();
                q.prompt     = SA[2652];
                q.string     = confname;
                q.defstring  = NULL;
                q.length     = 20;
                q.typelength = 20;
                q.flags      = QUERY_CAPITAL;
                DLGQuery(&q, &ui);
                AFPrintf(NULL, sout, "\n\n");
                StripSpaces(confname);

                mymsg->type    =  JOINCONF;
                mymsg->dataptr = (char *)confname;
                OpenConf();
                PutMsg(confctl,(struct Message *)mymsg);
                WaitPort(confport);
                GetMsg(confport);

                if (mymsg->type==FNOERR)
                   {exitflag = TRUE;
                    mymsg->dataptr=(struct MsgData *)mydata;
                    strcpy(buf,SA[2653]);
                    mydata->buffer=(char *)buf;
                    mymsg->type=CONFMSG;
                    mymsg->topvt=NULL;
                    mydata->outcount=0;
                    PutMsg(confctl,(struct Message *)mymsg);
                    WaitPort(confport);
                    GetMsg(confport);
                   }
                 else
                   if (mymsg->type==TOOSLOW)
                       AFPrintf(NULL, sout, SA[2654]);
                     else
                       AFPrintf(NULL, sout, SA[2655]);
                break;

        case 3:         /* CONFU_Exit */
                CleanUp(NULL);
                break;

        case 4:         /* CONFU_ListRooms */
                mymsg->type=LISTCONF;
                OpenConf();
                PutMsg(confctl,(struct Message *)mymsg);
                WaitPort(confport);
                GetMsg(confport);

                conf=(struct Conference *)mymsg->dataptr;
                if (conf)
                   {AFPrintf(NULL, sout, SA[2656]);
                    Draw_Line(UserDat.Screen_Width);

                    while(conf)
                         {if (UserDat.User_Level>=conf->user_level)
                             {AFPrintf(NULL, sout, SA[2657],conf->name);
                              AFPrintf(NULL, sout, SA[2658],conf->minbaud);
                             }

                          conf = conf->nextconf;
                         }

                    Draw_Line(UserDat.Screen_Width);
                    AFPrintf(NULL, sout, "\n");
                   }
                 else
                    AFPrintf(NULL, sout, "No rooms currently active\n\n");

                mymsg->type=FREECONF;
                OpenConf();
                PutMsg(confctl,(struct Message *)mymsg);
                WaitPort(confport);
                GetMsg(confport);
                break;

        case 5:         /* CONFU_LiUserDats */
                Chk_Abort();
                q.prompt     = SA[2659];
                q.string     = confname;
                q.defstring  = NULL;
                q.length     = 20;
                q.typelength = 20;
                q.flags      = QUERY_CAPITAL;
                DLGQuery(&q, &ui);
                StripSpaces(confname);

                mymsg->type = LISTCONF;
                AFPrintf(NULL, sout, "\n\n");
                OpenConf();
                PutMsg(confctl,(struct Message *)mymsg);
                WaitPort(confport);
                GetMsg(confport);

                conf=(struct Conference *)mymsg->dataptr;
                while(conf)
                     {if ((UserDat.User_Level>=conf->user_level)&&(!strcmp(conf->name,confname)))
                           break;
                         else
                           conf=conf->nextconf;
                     }

                if (!conf)
                    AFPrintf(NULL, sout, SA[2660]);
                  else
                   {AFPrintf(NULL, sout, SA[2661],confname);
                    Draw_Line(UserDat.Screen_Width);

                    user=conf->users;
                    while(user)
                         {AFPrintf(NULL, sout, "%s\n",user->name);
                          user=user->nextuser;
                         }

                    Draw_Line(UserDat.Screen_Width);
                    AFPrintf(NULL, sout, "\n");
                   }

                mymsg->type=FREECONF;
                OpenConf();
                PutMsg(confctl,(struct Message *)mymsg);
                WaitPort(confport);
                GetMsg(confport);
                break;


       default: break;
       }

 return(0);
}


void AsyncRead(void)

{mypacket->sp_Pkt.dp_Port = (struct MsgPort *)readport;
 PutMsg(fh->fh_Type,(struct Message *)mypacket);
}


void OpenConf(void)

{UBYTE loopcnt = 0;

 while(loopcnt < 10)
      {Forbid();
       confctl = FindPort(CONFCONTROL);
       Permit();

       if (confctl)  return;

       if (!loopcnt)
          {if (CronEvent(ADDEVENT, 0, "DLG:TPTConf >Nil:"))
               CleanUp("Unable to launch TPTConf");
          }

       Delay(50);
       loopcnt++;
      }

 CleanUp("Unable to get connect to TPTConf");
 return;
}


void PurgeMessages(void)

{while(inmsg = (struct ConfMessage *)GetMsg(confport))
      {if (inmsg->type==CONFMSG)
          {inmsg->type = CONFREPLY;
           ReplyMsg((struct Message *)inmsg);
          }
      }
}


void WaitForReply(void)

{UBYTE rep;

 do{rep = FALSE;

    WaitPort(confport);
    while(inmsg=(struct ConfMessage *)GetMsg(confport))
         {if (inmsg->type==CONFMSG)
             {inmsg->type=CONFREPLY;
              ReplyMsg((struct Message *)inmsg);
             }
           else
              rep=TRUE;
         }
   } while(!rep);
}


void CleanUp(char *s)

{if (mydata) free(mydata);
 if (mymsg)  free(mymsg);

 if (readport)  DeleteMsgPort(readport);
 if (confport)  DeleteMsgPort(confport);

 if (mypacket)  free(mypacket);

 if (DLGBase)
    {WriteRam(&RStruct,Ext);
     AFPrintf(NULL, sout, SA[2662]);
     Clr(UserDat.Ansi_Flag);

     if (!Overlay)  ChainProgram("DLG:Menu", Ext);
     CloseLibrary(DLGBase);
    }

 if (s)
    {Write(sout, "\n Error: ", 9);
     Write(sout,  s,    strlen(s));
     Write(sout, "\n\n",       2);
    }

 exit(s?5:0);
}


void LetsGetOutOfHere(void)

{AFPrintf(NULL, sout, "\n");

 strcpy(buf,SA[2663]);
 mymsg->type=CONFMSG;
 mymsg->topvt=NULL;
 mydata->outcount=0;
 mydata->buffer=(char *)buf;
 PutMsg(confctl,(struct Message *)mymsg);
 WaitForReply();

 mymsg->type=LEAVECONF;
 PutMsg(confctl,(struct Message *)mymsg);
 WaitForReply();

 PurgeMessages();

 TSetFlags(T_RAW | T_LINEFREEZE, Ext);
 InConf = FALSE;
}


void _CXBRK(void)

{if (Enable_Abort)
    {if (InConf)  LetsGetOutOfHere();

     LogOut(&RStruct,&UserDat,Ext,"ConfUser");
     AFPrintf(NULL, sout, SA[2665]);

     CleanUp(NULL);
    }
}
