/*
 * umspasswd.c V0.10
 *
 * C source code
 *
 * umspasswd: Change UMS passwords
 *
 * (c) 1993 Stefan Becker
 */

#include "umspasswd.h"

/* Constant strings */
static const char ChangeError[] = "Couldn't change password!";
static const char NotChanged[]  = "Password not changed!";
static const char NoUMS[]       = "No UMS installed!";
static const char ProgID[]   = "$VER: UMSPasswd 0.10 (" __COMMODORE_DATE__ ")";
static const char SysopName[]   = "sysop";
static const char Template[]    = "USER,SERVER,SYSOP/S";
static const char UMSName[]     = "ums.library";
static const char WrongPass[]   = "Wrong password!";

#ifdef USE_MUI
static const char OKText[]      = "OK";
static const char ProgName[]    = "UMSPasswd";

/* MUI class names (Note: Ignore the warnings) */
static const char MUIC_Application[] = "Application.mui";
static const char MUIC_Group[]       = "Group.mui";
static const char MUIC_String[]      = "String.mui";
static const char MUIC_Text[]        = "Text.mui";
static const char MUIC_Window[]      = "Window.mui";

/* Misc. data */
struct Library *IconBase, *IntuitionBase, *MUIMasterBase;
static const struct EasyStruct NoMUINoGUI = {
 sizeof(struct EasyStruct), 0, ProgName, "No MUI - No GUI :-)", OKText
};
#endif /* USE_MUI */

struct Library *UMSBase;
#define BUFLEN 100
static char buffer[BUFLEN];

/* Change password for account, returns FALSE for error */
static BOOL ChangePassword(UMSUserAccount acc, char *user, char *pass)
{
 return(WriteUMSConfigTags(acc,
                           (user ? UMSTAG_CfgUser : TAG_IGNORE), user,
                           UMSTAG_CfgName,                       "password",
                           UMSTAG_CfgData,                       pass,
                           TAG_DONE));
}

#ifdef USE_MUI
/* Gadget IDs */
#define ID_OK  1
#define ID_SYS 2

/* Macro for password string gadgets */
#define PasswdString StringObject,\
                      StringFrame,\
                      MUIA_String_Secret, TRUE,\
                     End

/* Open error requester */
static void ErrorRequester(APTR app, APTR win, char *text)
{
 MUI_Request(app, win, 0, ProgName, OKText, text);
}

/* Handle GUI */
static void DoGUI(BOOL sysop) {
 /* Open Intuition library */
 if (IntuitionBase = OpenLibrary("intuition.library", 37)) {

  /* Open MUI master library */
  if (MUIMasterBase = OpenLibrary("muimaster.library", 4)) {

   /* Open UMS library V10 */
   if (UMSBase = OpenLibrary(UMSName, 10)) {
    APTR app;                                      /* Application    */
    APTR mainwin, sysopwin;                        /* Windows        */
    APTR usergad, oldgad, newgad, servgad, sysgad; /* String gadgets */
    APTR okgad, cancelgad;                         /* Button gadgets */

    /* Get "UMSSERVER" variable */
    if (GetVar("UMSSERVER", buffer, BUFLEN, 0) < 0)
     strcpy(buffer, "default");

    /* Create GUI data */
    app = ApplicationObject,

           /* Application data */
           MUIA_Application_Title,       ProgName,
           MUIA_Application_Version,     ProgID,
           MUIA_Application_Copyright,   "© 1993 Stefan Becker",
           MUIA_Application_Author,      "Stefan Becker",
           MUIA_Application_Description, "Change UMS passwords",
           MUIA_Application_Base,        "UMSPASSWD",
           MUIA_Application_SingleTask,  FALSE,

           /* Main window */
           SubWindow, mainwin = WindowObject,
            MUIA_Window_Title,    ProgName,
            MUIA_Window_LeftEdge, MUIV_Window_LeftEdge_Moused,
            MUIA_Window_TopEdge,  MUIV_Window_TopEdge_Moused,
            WindowContents, VGroup,
             Child, ColGroup(2),
              Child, Label2("User name"),
               Child, usergad = String("", 20),
              Child, Label2("Old password"),
               Child, oldgad  = PasswdString,
              Child, Label2("New password"),
               Child, newgad  = PasswdString,
              Child, Label2("Server"),
               Child, servgad = String(buffer, 20),
             End,
             Child, HGroup,
              MUIA_Group_SameSize, TRUE,
              Child, okgad     = KeyButton(OKText, 'o'),
              Child, cancelgad = KeyButton("Cancel", 'c'),
             End,
            End,
           End,

           /* Sysop window */
           SubWindow, sysopwin = WindowObject,
            MUIA_Window_CloseGadget, FALSE,
            MUIA_Window_DepthGadget, FALSE,
            MUIA_Window_DragBar,     FALSE,
            MUIA_Window_SizeGadget,  FALSE,
            WindowContents, HGroup,
             Child, Label2("Sysop password"),
             Child, sysgad = PasswdString,
            End,
           End,
          End;

    /* GUI data created? */
    if (app) {
     /* Yes, set connections */
     ULONG running;

     /* TAB cycle chains */
     DoMethod(mainwin, MUIM_Window_SetCycleChain,
               usergad, oldgad, newgad, servgad, okgad, cancelgad, NULL);
     DoMethod(sysopwin, MUIM_Window_SetCycleChain,
               sysgad, NULL);

     /* RETURN cycle chain */
     DoMethod(usergad, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
               mainwin, 3,
                MUIM_Set, MUIA_Window_ActiveObject, (sysop ? newgad : oldgad));
     if (sysop)
      set(oldgad, MUIA_Disabled, TRUE);
     else
      DoMethod(oldgad, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
                mainwin, 3,
                 MUIM_Set, MUIA_Window_ActiveObject, newgad);
     DoMethod(newgad, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
               mainwin, 3,
                MUIM_Set, MUIA_Window_ActiveObject, servgad);
     DoMethod(servgad, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
               mainwin, 3,
                MUIM_Set, MUIA_Window_ActiveObject, okgad);

     /* Close & Cancel gadget */
     DoMethod(mainwin, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
               app, 2,
                MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
     DoMethod(cancelgad, MUIM_Notify, MUIA_Pressed, FALSE,
               app, 2,
                MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

     /* OK gadget */
     DoMethod(okgad, MUIM_Notify, MUIA_Pressed, FALSE,
               app, 2,
                MUIM_Application_ReturnID, ID_OK);

     /* Sysop password gadget */
     DoMethod(sysgad, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
               app, 2,
                MUIM_Application_ReturnID, ID_SYS);

     /* Open window & activate user gadget */
     set(mainwin, MUIA_Window_Open, TRUE);
     set(mainwin, MUIA_Window_ActiveObject, usergad);

     /* Check if window is open */
     get(mainwin, MUIA_Window_Open, &running);

     /* Sysop? */
     if (running && sysop) {
      /* Put main window to sleep and open sysop window */
      set(mainwin,  MUIA_Window_Sleep, TRUE);
      set(sysopwin, MUIA_Window_RefWindow, mainwin);
      set(sysopwin, MUIA_Window_Open, TRUE);
      set(sysopwin, MUIA_Window_ActiveObject, sysgad);

      /* Check if window is open */
      get(sysopwin, MUIA_Window_Open, &running);
     }

     /* Check if window is open */
     if (!running) ErrorRequester(app, mainwin, "Couldn't open window!");

     /* Input event loop */
     while (running) {
      ULONG signal;

      /* Get next MUI event */
      switch(DoMethod(app, MUIM_Application_Input, &signal)) {
       case MUIV_Application_ReturnID_Quit:
        running = FALSE;
        break;

       case ID_OK: { /* User pressed OK gadget -> change password */
         char *user, *oldpass, *newpass, *server;

         /* Get strings */
         get(usergad, MUIA_String_Contents, &user);
         get((sysop ? sysgad : oldgad), MUIA_String_Contents, &oldpass);
         get(newgad,  MUIA_String_Contents, &newpass);
         get(servgad, MUIA_String_Contents, &server);

         /* If not sysop -> compare old and new password */
         if (sysop || strcmp(oldpass, newpass)) {
          UMSUserAccount account;

          /* Login */
          if (account = UMSRLogin(server, (sysop ? (char *) SysopName : user),
                                  oldpass)) {

           /* Change password */
           if (ChangePassword(account, (sysop ? user : NULL), newpass))
            running = FALSE; /* Password changed */
           else
            ErrorRequester(app, mainwin, ChangeError);

           /* Logout */
           UMSLogout(account);
          } else
          ErrorRequester(app, mainwin, WrongPass);
         } else
          ErrorRequester(app, mainwin, NotChanged);
        }
        break;

       case ID_SYS: { /* User entered sysop password */
         /* Close sysop window */
         set(sysopwin, MUIA_Window_Open, FALSE);

         /* Activate main window */
         set(mainwin, MUIA_Window_Sleep, FALSE);
         set(mainwin, MUIA_Window_ActiveObject, usergad);
        }
        break;
      }

      /* Wait on signal */
      if (signal) Wait(signal);
     }

     /* Free GUI data */
     MUI_DisposeObject(app);
    } else
     ErrorRequester(NULL, NULL, "Couldn't create MUI Application!");

    /* Close UMS library */
    CloseLibrary(UMSBase);
   } else
    ErrorRequester(NULL, NULL, NoUMS);

   /* Close MUI library */
   CloseLibrary(MUIMasterBase);
  } else
   EasyRequestArgs(NULL, &NoMUINoGUI, NULL, NULL);

  /* Close Intuition library */
  CloseLibrary(IntuitionBase);
 }
}
#endif /* USE_MUI */

/* Switch console mode */
static void ConsoleMode(struct MessagePort *mp, LONG mode)
{
 DoPkt(mp, ACTION_SCREEN_MODE, mode, 0, 0, 0, 0);
}

/* Print text and read raw text */
static void GetInputLine(BPTR ifh, BPTR ofh, char *out, char *buf)
{
 LONG c;

 /* Print text */
 PutStr(out);
 Flush(ofh);

 while (((c = FGetC(ifh)) != ENDSTREAMCH) && (c != '\x0d')) *buf++ = c;
 *buf = '\0';

 /* Next output line */
 FPutC(ofh,'\n');
}

/* Data from ReadArgs() */
static struct {
 char *user;
 char *server;
 long  sysop;
} args = {NULL, NULL, FALSE};

/* Main entry point */
int _main(void)
{
 /* Started from WB? */
 if (_WBMsg) {
#ifdef USE_MUI
  /* WB startup */
  BOOL sysop = FALSE;

  /* Open Icon library */
  if (IconBase = OpenLibrary("icon.library", 37)) {
   BPTR               olddir;
   struct WBArg      *wa;
   struct DiskObject *dobj;

   /* Get last WBArg */
   wa = &_WBMsg->sm_ArgList[_WBMsg->sm_NumArgs-1];

   /* Go to icon directory */
   olddir = CurrentDir(wa->wa_Lock);

   /* Get icon */
   if (dobj = GetDiskObjectNew(wa->wa_Name)) {

    /* SYSOP tooltype? */
    if (FindToolType(dobj->do_ToolTypes, SysopName)) sysop = TRUE;

    /* Free icon */
    FreeDiskObject(dobj);
   }

   /* Go back to old directory */
   CurrentDir(olddir);

   /* Close Icon library */
   CloseLibrary(IconBase);
  }

  /* Open GUI */
  DoGUI(sysop);
#endif /* USE_MUI */
 } else {
  /* CLI startup */
  struct RDArgs *rda;

  /* Parse command line */
  rda = ReadArgs(Template, (LONG *) &args, NULL);

  /* User name set? */
  if (args.user) {
   /* Yes, use CLI interface */
   BPTR ifh = Input(), ofh, efh;

   /* Use error stream as output stream if available */
   if (efh = ((struct Process *) FindTask(NULL))->pr_CES)
    efh = SelectOutput(efh); /* Save old output stream in efh */
   ofh  = Output();

   /* Check if input & output is a console */
   if (IsInteractive(ifh) && IsInteractive(ofh)) {

    /* Open UMS library V10 */
    if (UMSBase = OpenLibrary(UMSName, 10)) {
     struct MessagePort *mp = ((struct FileHandle *) BADDR(ifh))->fh_Type;
     char newpass[BUFLEN];
     char newpass2[BUFLEN];

     /* Switch console input to raw mode (no echo) */
     ConsoleMode(mp, 1);

     /* Read passwords */
     GetInputLine(ifh, ofh, (args.sysop ? "Enter sysop password:"
                                        : "Enter old password  :"), buffer);
     GetInputLine(ifh, ofh, "Enter new password  :", newpass);
     GetInputLine(ifh, ofh, "Reenter new password:", newpass2);

     /* Switch console input to cooked mode (echo) */
     ConsoleMode(mp, 0);

     /* Compare new passwords */
     if (!strcmp(newpass, newpass2)) {

      /* Passwords are equal. If not sysop, compare old and new password */
      if (args.sysop || strcmp(newpass, buffer)) {
       UMSUserAccount account;

       /* New password, UMS login */
       if (account = UMSRLogin(args.server,
                               (args.sysop ? (char *) SysopName: args.user),
                               buffer)) {
        /* Change password */
        if (ChangePassword(account, (args.sysop ? args.user : NULL), newpass))
         PutStr("Password changed.");
        else
         PutStr(ChangeError);

        /* Logout */
        UMSLogout(account);
       } else
        PutStr(WrongPass);
      } else
       PutStr(NotChanged);
     } else
      PutStr("Passwords differ!");

     /* Close UMS library */
     CloseLibrary(UMSBase);
    } else
     PutStr(NoUMS);
   } else
    PutStr("Need console!");

   /* Finish output line */
   FPutC(ofh,'\n');

   /* Reset output stream */
   if (efh) SelectOutput(efh);
  }
#ifdef USE_MUI
  else
   /* No user name given, use GUI */
   DoGUI(args.sysop);
#endif /* USE_MUI */

  /* Free ReadArgs resources */
  if (rda) FreeArgs(rda);
 }

 /* This is the end... */
 return(0);

 /* !!!NOT REACHED!!! */
 _waitwbmsg();
}
