/****h* SysPorts/SysPorts.c [1.1] ***********************************
*
* NAME
*    SysPorts.c
*
* DESCRIPTION
*
*********************************************************************
*
*/

#include <string.h>

#include <exec/types.h>
#include <exec/execbase.h>

#include <AmigaDOSErrs.h>

#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/gadgetclass.h>

#include <libraries/gadtools.h>

#include <graphics/displayinfo.h>
#include <graphics/gfxbase.h>

#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/graphics_protos.h>
#include <clib/utility_protos.h>
#include <clib/diskfont_protos.h>

#include "CPGM:GlobalObjects/CommonFuncs.h"

#include "SysLists.h"

#define PLV       0
#define Update    1
#define RemoveBt  2
#define Priority  3
#define Cancel    4

#define Po_CNT    5

#define PORTLVGAD PoGadgets[ PLV ]

PRIVATE char ver[] = "\0$VER: SysPorts 1.1 (25-Apr-2001) by J.T. Steichen\0";

PRIVATE struct TextFont     *PoFont  = NULL;
PRIVATE struct Window       *PoWnd   = NULL;
PRIVATE struct Gadget       *PoGList = NULL;
PRIVATE struct IntuiMessage  PoMsg;
PRIVATE struct Gadget       *PoGadgets[ Po_CNT ];

PRIVATE UWORD  PoLeft   = 0;
PRIVATE UWORD  PoTop    = 16;
PRIVATE UWORD  PoWidth  = 635;
PRIVATE UWORD  PoHeight = 230;
PRIVATE UBYTE *PoWdt    = (UBYTE *) "System Info (Ports):";

PRIVATE char *ltitle = "Address   Pri  PortName            Type     SigBit   Flags TaskName";
PRIVATE char *fmt    = "%08LX %4d  %-19.19s %-7.7s  %08LX  %4LX %-24.24s";

PRIVATE ULONG PortAddress = 0L;

PRIVATE char  pn[80], *PortName = &pn[0];

PRIVATE struct List *DevListPtr = NULL;

// -------------------------------------------------------------------

#define MAXNODES   50
#define NODELENGTH 80

PRIVATE struct List PLVList;

PRIVATE struct Node PLVNode;
PRIVATE struct Node PLVNodes[ MAXNODES ] = { NULL, };

PRIVATE UBYTE       NodeStrs[ MAXNODES * NODELENGTH ] = "";

PRIVATE struct ListViewMem lvm = { 0, };
    
// -------------------------------------------------------------------

PRIVATE UWORD PoGTypes[] = {

   LISTVIEW_KIND, BUTTON_KIND, BUTTON_KIND,
   BUTTON_KIND,   BUTTON_KIND
};

PRIVATE int PLVClicked(      int whichitem );
PRIVATE int UpdateClicked(   int dummy     );
PRIVATE int RemoveClicked(   int dummy     );
PRIVATE int PriorityClicked( int dummy     );
PRIVATE int CancelClicked(   int dummy     );

PRIVATE struct NewGadget PoNGad[] = {

     2,   3, 627, 200,                 NULL, NULL, PLV, 
   0, NULL, (APTR) PLVClicked,

     6, 205,  72,  17, (UBYTE *) "_Update",  NULL, Update, 
   PLACETEXT_IN, NULL, (APTR) UpdateClicked,

   192, 205,  72,  17, (UBYTE *) "Remove",   NULL, RemoveBt, 
   PLACETEXT_IN, NULL, (APTR) RemoveClicked,

   379, 205,  72,  17, (UBYTE *) "Priority", NULL, Priority, 
   PLACETEXT_IN, NULL, (APTR) PriorityClicked,

   552, 205,  72,  17, (UBYTE *) "_Cancel",  NULL, Cancel, 
   PLACETEXT_IN, NULL, (APTR) CancelClicked
};

PRIVATE ULONG PoGTags[] = {

   LAYOUTA_Spacing,      2, 
   GTLV_ShowSelected, NULL, 
   GTLV_Selected,     TRUE, TAG_DONE,

   GT_Underscore,  '_', TAG_DONE,
   TAG_DONE,
   TAG_DONE,
   GT_Underscore,  '_', TAG_DONE
};

// ----------------------------------------------------------------------

PRIVATE char PortType[20] = "";
PRIVATE char PortTask[32] = "";

PRIVATE ULONG PortSigBit = 0L;
PRIVATE UBYTE PortFlags  = 0L;

PRIVATE char *GetPortType( struct Node *port )
{
   switch (port->ln_Type)
      {
      case NT_MSGPORT:
         strcpy( &PortType[0], "MsgPort" );
         break;
         
      case NT_UNKNOWN:
      default:
         strcpy( &PortType[0], "Unknown" );
         break;
      }
      
   return( &PortType[0] );
}

PRIVATE ULONG GetPortSigBit( struct Node *port )
{
   struct MsgPort *mp = (struct MsgPort *) port;

   return( mp->mp_SigBit = PortSigBit );
}

PRIVATE UBYTE GetPortFlags( struct Node *port )
{
   struct MsgPort *mp = (struct MsgPort *) port;
   
   return( mp->mp_Flags = PortFlags );
}

PRIVATE char *GetPortTaskName( struct Node *port )
{
   struct MsgPort *mp    = (struct MsgPort *) port;
   struct Task    *ptask = NULL;
   
   if (mp != NULL)
      ptask = (struct Task *) mp->mp_SigTask;

   if (ptask != NULL)
      { 
      if (ptask->tc_Node.ln_Type == NT_TASK ||
          ptask->tc_Node.ln_Type == NT_PROCESS)
         {
         if (strlen( ptask->tc_Node.ln_Name ) > 1)   
            strcpy( &PortTask[0], ptask->tc_Node.ln_Name );
         else
            strcpy( &PortTask[0], "No Task Name!" );  
         } 
      else
         strcpy( &PortTask[0], "No Task Node!" );   
      }
   else
      strcpy( &PortTask[0], "No Task Ptr!" );   

   return( &PortTask[0] );
}

PRIVATE BOOL ValidName( char *name )
{
   BOOL rval = TRUE;
   int  len  = strlen( name ), i = 0;

   if (len < 1)
      {
      rval = FALSE;
      return( rval );
      }

   while (i < len)
      {
      if ((*(name + i) > 0x7E) || (*(name + i) < 0x20))
         {
         rval = FALSE;
         break;
         }

      i++;
      }   

   return( rval );
}

PRIVATE int MakePortList( void )
{
   IMPORT struct ExecBase *SysBase;

   struct List    *portslist;
   struct Node    *ptr;   
   struct MsgPort *mport;
   
   char *nm = NULL;
   int   i  = 1; // Don't overwrite the Column headers.
   
   // First node is column heads:   
   strncpy( &NodeStrs[0], ltitle, NODELENGTH - 1 );
   
   HideListFromView( PORTLVGAD, PoWnd );

   Forbid();

     portslist = &SysBase->PortList;
     ptr       = portslist->lh_Head;
     mport     = (struct MsgPort *) ptr;

     while ((i < MAXNODES) && (mport != NULL))
        {
        nm = mport->mp_Node.ln_Name;

        if (strlen( nm ) < 1)
           goto SkipBlankPortName;

        // "Address  Pri  PortName  Type  SigBit  Flags TaskName";
        sprintf( &NodeStrs[ NODELENGTH * i++ ], fmt,
                 mport, 
                 mport->mp_Node.ln_Pri,
                 (nm == NULL ? "** NO NAME **" : nm),
                 GetPortType(     (struct Node *) mport ),
                 mport->mp_SigBit,
                 mport->mp_Flags,
                 GetPortTaskName( (struct Node *) mport )
               );

SkipBlankPortName:
         
        mport = ((struct MsgPort *) mport)->mp_Node.ln_Succ;
        } 

   Permit();

   GT_SetGadgetAttrs( PORTLVGAD, PoWnd, NULL,
                      GTLV_Labels,       &PLVList,
                      GTLV_Selected,     1,
                      TAG_END
                    );

   DisplayTitle( PoWnd, PoWdt );

   return( i );
}


PRIVATE void ClosePoWindow( void )
{
   if (PoWnd != NULL)
      {
      CloseWindow( PoWnd );
      PoWnd = NULL;
      }

   if (PoGList != NULL)
      {
      FreeGadgets( PoGList );
      PoGList = NULL;
      }

   if (PoFont != NULL)
      {
      CloseFont( PoFont );
      PoFont = NULL;
      }

   return;
}

PRIVATE int PoCloseWindow( void )
{
   ClosePoWindow();
   return( (int) FALSE );
}

PRIVATE int PLVClicked( int itemnum )
{
   ULONG addr = 0L;
   
//#  ifdef DEBUG
//   fprintf( stderr, "%-80.80s\n", PLVNodes[ itemnum ].ln_Name );
//#  endif

   if (itemnum == 0)   
      {
      GT_SetGadgetAttrs( PoGadgets[ RemoveBt ], PoWnd, NULL,
                         GA_Disabled, TRUE, TAG_DONE 
                       );

      GT_SetGadgetAttrs( PoGadgets[ Priority ], PoWnd, NULL,
                         GA_Disabled, TRUE, TAG_DONE 
                       );

      return( (int) TRUE );
      }
   else
      {
      GT_SetGadgetAttrs( PoGadgets[ RemoveBt ], PoWnd, NULL,
                         GA_Disabled, FALSE, TAG_DONE 
                       );

      GT_SetGadgetAttrs( PoGadgets[ Priority ], PoWnd, NULL,
                         GA_Disabled, FALSE, TAG_DONE 
                       );

      // Now get address from the item:
      (void) stch_l( PLVNodes[ itemnum ].ln_Name, (long *) &addr );

      PortAddress = addr;
      }

   return( (int) TRUE );
}

PRIVATE int UpdateClicked( int dummy )
{
   int i;

   DisplayTitle( PoWnd, "Updating Port List..." );

   HideListFromView( PORTLVGAD, PoWnd );   

   for (i = 1; i < MAXNODES; i++)         // 0 = Title string in ListView
       NodeStrs[ i * NODELENGTH ] = '\0'; // Kill old ListView strings.

   // Make the list:
   (void) MakePortList();

   ModifyListView( PORTLVGAD, PoWnd, &PLVList, NULL );

   DisplayTitle( PoWnd, PoWdt );

   GT_RefreshWindow( PoWnd, NULL );

   return( (int) TRUE );
}

// ---------------------------------------------------------------------

PRIVATE BOOL IsMsgPort_Empty( struct MsgPort *p )
{
   BOOL rval = FALSE;

   if (p == NULL)
      return( TRUE );

   if (p->mp_MsgList.lh_TailPred == (struct Node *) &(p->mp_MsgList))
      rval = TRUE;
   
   return( rval );
}
     
PRIVATE void RemovePortSafely( struct MsgPort *port )
{
   struct Node *MsgNode = NULL;

   if (port == NULL)
      return;

   Forbid();

     if (IsMsgPort_Empty( port ) == FALSE)
        {
        MsgNode = port->mp_MsgList.lh_Head;

        while ((MsgNode = MsgNode->ln_Succ) != NULL)
           Remove( (struct Node *) MsgNode );
        }

     if (port->mp_Node.ln_Name != NULL)
        RemPort( port );

     port->mp_SigTask         = (struct Task *) -1;
     port->mp_MsgList.lh_Head = (struct Node *) -1;

     DeletePort( port );

  Permit();

  return;
}

PRIVATE int RemoveClicked( int dummy )
{
   int   answer = -1;

   if (PortAddress == NULL)
      {
      UserInfo( "Select a valid Port first!", "User ERROR:" );

      return( (int) TRUE );
      }

   sprintf( ErrMsg, "Are you SURE you want to Remove %08x?", PortAddress );

   answer = SanityCheck( ErrMsg );

   if (answer == TRUE)
      RemovePortSafely( (struct MsgPort *) PortAddress );

   return( (int) TRUE );
}

// ---------------------------------------------------------------------

PRIVATE int PriorityClicked( int dummy )
{
   int  answer = -1;
   
   if (PortAddress == NULL)
      {
      UserInfo( "Select a valid Port first!", "User ERROR:" );      

      return( (int) TRUE );
      }

   sprintf( ErrMsg, "Are you SURE you want to Re-Prioritize %08x?", 
            PortAddress 
          );

   answer = SanityCheck( ErrMsg );

   if (answer == TRUE)
      {
      ULONG  OldPri = ((struct Node *) PortAddress)->ln_Pri;
      char  *name   = ((struct Node *) PortAddress)->ln_Name;

      if (ChangePriorityHandler( name, NT_MSGPORT, OldPri ) < 0)
         {
         // Error condition:
         sprintf( ErrMsg, "Couldn't open Priority Requester!" );

         UserInfo( ErrMsg, "System Problem:" );
         }
      }

   return( (int) TRUE );
}

PRIVATE int CancelClicked( int dummy )
{
   return( PoCloseWindow() );
}

// -----------------------------------------------------------------

PRIVATE int OpenPoWindow( void )
{
   struct NewGadget  ng;
   struct Gadget    *g;
   UWORD             lc, tc;
   UWORD             wleft = PoLeft, wtop = PoTop, ww, wh;

   ComputeFont( Scr, Font, &CFont, PoWidth, PoHeight );

   ww = ComputeX( CFont.FontX, PoWidth );
   wh = ComputeY( CFont.FontY, PoHeight );

   if ((wleft + ww + CFont.OffX + Scr->WBorRight) > Scr->Width)
      wleft = Scr->Width - ww;

   if ((wtop + wh + CFont.OffY + Scr->WBorBottom) > Scr->Height)
      wtop = Scr->Height - wh;

   if ((PoFont = OpenDiskFont( Font )) == NULL)
      return( -5 );

   if ((g = CreateContext( &PoGList )) == NULL)
      return( -1 );

   for (lc = 0, tc = 0; lc < Po_CNT; lc++)
      {
      CopyMem( (char *) &PoNGad[lc], (char *) &ng, 
               (long) sizeof( struct NewGadget )
             );

      ng.ng_VisualInfo = VisualInfo;
      ng.ng_TextAttr   = Font;

      ng.ng_LeftEdge   = CFont.OffX + ComputeX( CFont.FontX, 
                                                ng.ng_LeftEdge
                                              );

      ng.ng_TopEdge    = CFont.OffY + ComputeY( CFont.FontY, 
                                                ng.ng_TopEdge
                                              );

      ng.ng_Width      = ComputeX( CFont.FontX, ng.ng_Width );
      ng.ng_Height     = ComputeY( CFont.FontY, ng.ng_Height );

      PoGadgets[lc] = g = CreateGadgetA( (ULONG) PoGTypes[lc], 
                            g, 
                            &ng, 
                            (struct TagItem *) &PoGTags[tc] );

      while ( PoGTags[tc] )
         tc += 2;

      tc++;

      if (g == NULL)
         return( -2 );
      }

   if ((PoWnd = OpenWindowTags( NULL,

                 WA_Left,        wleft,
                 WA_Top,         wtop,
                 WA_Width,       ww + CFont.OffX + Scr->WBorRight,
                 WA_Height,      wh + CFont.OffY + Scr->WBorBottom,
                 
                 WA_IDCMP,       LISTVIEWIDCMP | BUTTONIDCMP 
                   | IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW 
                   | IDCMP_VANILLAKEY,
                 
                 WA_Flags,       WFLG_DRAGBAR | WFLG_DEPTHGADGET 
                   | WFLG_CLOSEGADGET | WFLG_SMART_REFRESH 
                   | WFLG_ACTIVATE | WFLG_RMBTRAP,
                 
                 WA_Gadgets,     PoGList,
                 WA_Title,       PoWdt,
                 WA_ScreenTitle, ScrTitle,
                 TAG_DONE )
      ) == NULL)
      return( -4 );

   GT_RefreshWindow( PoWnd, NULL );

   return( 0 );
}

PRIVATE int PoVanillaKey( int whichkey )
{
   int rval = TRUE;
   
   switch (whichkey)
      {
      case 'u':
      case 'U':
         rval = UpdateClicked( 0 );
         break;
               
      case 'c':
      case 'C':
      case 'x':
      case 'X':
      case 'q':
      case 'Q':
         rval = CancelClicked( 0 );

      default:
         break;
      }

   return( rval );
}

PRIVATE int HandlePoIDCMP( void )
{
   struct IntuiMessage  *m;
   int                 (*func)( int code );
   BOOL                  running = TRUE;

   while (running == TRUE)
      {
      if ((m = GT_GetIMsg( PoWnd->UserPort )) == NULL)
         {
         (void) Wait( 1L << PoWnd->UserPort->mp_SigBit );
         continue;
         }

      CopyMem( (char *) m, (char *) &PoMsg, 
               (long) sizeof( struct IntuiMessage )
             );

      GT_ReplyIMsg( m );

      switch (PoMsg.Class)
         {
         case IDCMP_REFRESHWINDOW:
            GT_BeginRefresh( PoWnd );
            GT_EndRefresh( PoWnd, TRUE );
            break;

         case IDCMP_CLOSEWINDOW:
            running = PoCloseWindow();
            break;

         case IDCMP_VANILLAKEY:
            running = PoVanillaKey( (int) PoMsg.Code ); 
            break;
             
         case IDCMP_GADGETUP:
         case IDCMP_GADGETDOWN:
            func = (void *) ((struct Gadget *) PoMsg.IAddress)->UserData;

            if (func != NULL)
               running = func( (int) PoMsg.Code );

            break;
         }
      }

   return( running );
}

PUBLIC int main( void )
{
   int i = 0;

   if (SetupSystemList( &OpenPoWindow ) < 0)
      {
      fprintf( stderr, "Couldn't open a System ListViewer!\n" );
      return( RETURN_FAIL );
      }
   
   SetNotifyWindow( PoWnd );

   DisplayTitle( PoWnd, "Making Port List..." );

   lvm.lvm_NodeStrs   = &NodeStrs[0];
   lvm.lvm_Nodes      = &PLVNodes[0];
   lvm.lvm_NumItems   = MAXNODES;
   lvm.lvm_NodeLength = NODELENGTH;

   SetupList( &PLVList, &lvm );   

   strcpy( PLVNodes[0].ln_Name, ltitle );

   (void) MakePortList(); // Make the list.

   ModifyListView( PORTLVGAD, PoWnd, (struct List *) &PLVList, NULL );

   GT_RefreshWindow( PoWnd, NULL );

   DisplayTitle( PoWnd, PoWdt );

   (void) HandlePoIDCMP();
   
   ShutdownSystemList();

   return( RETURN_OK );
}

/* ---------------------- END of SysPorts.c file! -------------------- */ 
