1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                PASSWORD.CC                                */
4 /*                                                                           */
5 /* (C) 1994-95  Ullrich von Bassewitz                                        */
6 /*              Zwehrenbuehlstrasse 33                                       */
7 /*              D-72070 Tuebingen                                            */
8 /* EMail:       uz@ibb.schwaben.com                                          */
9 /*                                                                           */
10 /*****************************************************************************/
11 
12 
13 
14 // $Id$
15 //
16 // $Log$
17 //
18 //
19 
20 
21 
22 #include "password.h"
23 #include "streamid.h"
24 #include "msgid.h"
25 #include "listbox.h"
26 #include "menue.h"
27 #include "crcstrm.h"
28 #include "memstrm.h"
29 #include "progutil.h"
30 #include "stdmenue.h"
31 #include "stdmsg.h"
32 #include "strcvt.h"
33 #include "menuedit.h"
34 
35 
36 
37 /*****************************************************************************/
38 /*                             Message constants                             */
39 /*****************************************************************************/
40 
41 
42 
43 static const u16 msCannotOpenPasswordFile       = MSGBASE_PASSWORD + 0;
44 static const u16 msCannotReadPasswordFile       = MSGBASE_PASSWORD + 1;
45 static const u16 msCannotWritePasswordFile      = MSGBASE_PASSWORD + 2;
46 static const u16 msUserIDEmpty                  = MSGBASE_PASSWORD + 3;
47 static const u16 msUserNameEmpty                = MSGBASE_PASSWORD + 4;
48 static const u16 msPasswordEmpty                = MSGBASE_PASSWORD + 5;
49 static const u16 msUserIDExists                 = MSGBASE_PASSWORD + 6;
50 static const u16 msInvalidLogin                 = MSGBASE_PASSWORD + 7;
51 
52 
53 
54 /*****************************************************************************/
55 /*                                Global data                                */
56 /*****************************************************************************/
57 
58 
59 
60 static String _CUN;
61 extern const String& CUN = _CUN;
62 static String _CUID;
63 extern const String& CUID = _CUID;
64 static u32 _CPL;
65 extern const u32& CPL = _CPL;
66 
67 
68 
69 /*****************************************************************************/
70 /*                      Explicit template instantiation                      */
71 /*****************************************************************************/
72 
73 
74 
75 #ifdef EXPLICIT_TEMPLATES
76 template class Collection<class PasswordEntry>;
77 template class SortedCollection<class PasswordEntry, String>;
78 template class ListBox<class PasswordEntry>;
79 #endif
80 
81 
82 
83 /*****************************************************************************/
84 /*                            class PasswordEntry                            */
85 /*****************************************************************************/
86 
87 
88 
89 class PasswordEntry: public Streamable {
90 
91     friend class PasswordColl;
92     friend class PasswordListBox;
93     friend void Login (const String&, const String&);
94     friend inline void EntryEditor (class PasswordEntry*, int&, int&);
95     // EntryEditor is not inline but static, but this way gcc don't displays
96     // a warning
97 
98 protected:
99     String      UserName;
100     String      UserID;
101     String      Password;
102     u32         Level;
103 
104     void Crypt ();
105     void Decrypt ();
106 
107     PasswordEntry (StreamableInit);
108 
109 public:
110     PasswordEntry ();
111     PasswordEntry (const String& Name, const String& ID, const String& PW, u32 aLevel);
112 
113     // Derived from class Streamable
114     virtual void Load (Stream&);
115     virtual void Store (Stream&) const;
116     virtual u16 StreamableID () const;
117     static Streamable* Build ();
118 
119 };
120 
121 
122 
PasswordEntry()123 PasswordEntry::PasswordEntry ():
124     Level (0)
125 {
126 }
127 
128 
129 
PasswordEntry(StreamableInit)130 inline PasswordEntry::PasswordEntry (StreamableInit):
131     UserName (Empty),
132     UserID (Empty),
133     Password (Empty)
134 {
135 }
136 
137 
138 
PasswordEntry(const String & Name,const String & ID,const String & PW,u32 aLevel)139 PasswordEntry::PasswordEntry (const String& Name, const String& ID,
140                               const String& PW, u32 aLevel):
141     UserName (Name),
142     UserID (ID),
143     Password (PW),
144     Level (aLevel)
145 {
146 }
147 
148 
149 
Crypt()150 void PasswordEntry::Crypt ()
151 {
152     UserName.Crypt ();
153     UserID.Crypt ();
154     Password.Crypt ();
155     Level ^= Password.Len ();
156 }
157 
158 
159 
Decrypt()160 void PasswordEntry::Decrypt ()
161 {
162     UserName.Decrypt ();
163     UserID.Decrypt ();
164     Password.Decrypt ();
165     Level ^= Password.Len ();
166 }
167 
168 
169 
Load(Stream & S)170 void PasswordEntry::Load (Stream& S)
171 {
172     S >> UserName >> UserID >> Password >> Level;
173     Decrypt ();
174 }
175 
176 
177 
Store(Stream & S) const178 void PasswordEntry::Store (Stream& S) const
179 {
180     // Because we crypt and later decrypt *this, we cast away constness...
181     ((PasswordEntry*) this)->Crypt ();
182     S << UserName << UserID << Password << Level;
183     ((PasswordEntry*) this)->Decrypt ();
184 }
185 
186 
187 
StreamableID() const188 u16 PasswordEntry::StreamableID () const
189 {
190     return ID_PasswordEntry;
191 }
192 
193 
194 
Build()195 Streamable* PasswordEntry::Build ()
196 {
197     return new PasswordEntry (Empty);
198 }
199 
200 
201 
202 /*****************************************************************************/
203 /*                             class PWLogEntry                              */
204 /*****************************************************************************/
205 
206 
207 
208 class PWLogEntry: public Streamable {
209 
210 public:
211     enum _What { Login, Logout, Fail };
212 
213 protected:
214     String      UserName;
215     String      UserID;
216     u32         Level;
217     Time        Now;
218     _What       What;
219 
220     void Crypt ();
221     void Decrypt ();
222 
223     PWLogEntry (StreamableInit);
224     // Build constructor
225 
226 public:
227     PWLogEntry (const String& Name, const String& ID, u32 aLevel, _What Action);
228 
229     // Derived from class Streamable
230     virtual void Load (Stream&);
231     virtual void Store (Stream&) const;
232     virtual u16 StreamableID () const;
233     static Streamable* Build ();
234 
235 };
236 
237 
238 
PWLogEntry(const String & Name,const String & ID,u32 aLevel,_What Action)239 PWLogEntry::PWLogEntry (const String& Name, const String& ID,
240                         u32 aLevel, _What Action):
241     UserName (Name),
242     UserID (ID),
243     Level (aLevel),
244     What (Action)
245 {
246 }
247 
248 
249 
PWLogEntry(StreamableInit)250 inline PWLogEntry::PWLogEntry (StreamableInit):
251     UserName (Empty),
252     UserID (Empty),
253     Now (Empty)
254 {
255 }
256 
257 
258 
Crypt()259 void PWLogEntry::Crypt ()
260 {
261     UserName.Crypt ();
262     UserID.Crypt ();
263     Level ^= UserID.Len ();
264 }
265 
266 
267 
Decrypt()268 void PWLogEntry::Decrypt ()
269 {
270     UserName.Decrypt ();
271     UserID.Decrypt ();
272     Level ^= UserID.Len ();
273 }
274 
275 
276 
Load(Stream & S)277 void PWLogEntry::Load (Stream& S)
278 {
279     u32 Tmp;
280     S >> UserName >> UserID >> Level >> Now >> Tmp;
281     What = (_What) Tmp;
282     Decrypt ();
283 }
284 
285 
286 
Store(Stream & S) const287 void PWLogEntry::Store (Stream& S) const
288 {
289     // Because we crypt and later decrypt *this, we cast away constness...
290     ((PWLogEntry*) this)->Crypt ();
291     u32 Tmp = What;
292     S << UserName << UserID << Level << Now << Tmp;
293     ((PWLogEntry*) this)->Decrypt ();
294 }
295 
296 
297 
StreamableID() const298 u16 PWLogEntry::StreamableID () const
299 {
300     return ID_PWLogEntry;
301 }
302 
303 
304 
Build()305 Streamable* PWLogEntry::Build ()
306 {
307     return new PWLogEntry (Empty);
308 }
309 
310 
311 
312 /*****************************************************************************/
313 /*                            class PasswordColl                             */
314 /*****************************************************************************/
315 
316 
317 
318 class PasswordColl: public SortedCollection<PasswordEntry, String> {
319 
320 protected:
321     // Derived from class Collection
322     virtual void* GetItem (Stream& S);
323     virtual void PutItem (Stream& S, void* Item) const;
324 
325     // Derived from class SortedCollection
326     virtual int Compare (const String* Key1, const String* Key2);
327     virtual const String* KeyOf (const PasswordEntry* Item);
328 
329     PasswordColl (StreamableInit);
330     // Build constructor
331 
332 
333 public:
334     PasswordColl ();
335 
336     // Derived from class Streamable
337     virtual u16 StreamableID () const;
338     static Streamable* Build ();
339 
340     u32 GetLevel (const String& ID, const String& PW);
341     // Search for ID in the collection and compare the password. Return 0 if
342     // the ID is not found or the password does not match, return the user
343     // level otherwise
344 
345     int UserIDExists (PasswordEntry* Entry);
346     // Check if the user id in Entry exists already in the collection
347 
348     PasswordEntry* Extract (int Index);
349     // Get the entry from the collection and return it. Delete it from the
350     // collection
351 };
352 
353 
354 
PasswordColl()355 PasswordColl::PasswordColl ():
356     SortedCollection<PasswordEntry, String> (50, 10)
357 {
358     ShouldDelete = 1;
359 }
360 
361 
362 
PasswordColl(StreamableInit)363 PasswordColl::PasswordColl (StreamableInit):
364     SortedCollection<PasswordEntry, String> (Empty)
365 // Build constructor
366 {
367 }
368 
369 
370 
Compare(const String * Key1,const String * Key2)371 int PasswordColl::Compare (const String* Key1, const String* Key2)
372 {
373     return ::Compare (*Key1, *Key2);
374 }
375 
376 
377 
KeyOf(const PasswordEntry * Item)378 const String* PasswordColl::KeyOf (const PasswordEntry* Item)
379 {
380     return &Item->UserID;
381 }
382 
383 
384 
StreamableID() const385 u16 PasswordColl::StreamableID () const
386 {
387     return ID_PasswordColl;
388 }
389 
390 
391 
Build()392 Streamable* PasswordColl::Build ()
393 {
394     return new PasswordColl (Empty);
395 }
396 
397 
398 
GetItem(Stream & S)399 void* PasswordColl::GetItem (Stream& S)
400 {
401     return (void*) S.Get ();
402 }
403 
404 
405 
PutItem(Stream & S,void * Item) const406 void PasswordColl::PutItem (Stream& S, void* Item) const
407 {
408     S.Put ((PasswordEntry*) Item);
409 }
410 
411 
412 
GetLevel(const String & ID,const String & PW)413 u32 PasswordColl::GetLevel (const String& ID, const String& PW)
414 {
415     int Index;
416     if (Search (&ID, Index) == 0) {
417         // Not found, level is zero
418         return 0;
419     }
420     PasswordEntry* Entry = At (Index);
421     return (Entry->Password == PW) ? Entry->Level : 0;
422 }
423 
424 
425 
UserIDExists(PasswordEntry * Entry)426 int PasswordColl::UserIDExists (PasswordEntry* Entry)
427 // Check if the user id in Entry exists already in the collection
428 {
429     int Index;
430     return (Search (&Entry->UserID, Index));
431 }
432 
433 
434 
Extract(int Index)435 PasswordEntry* PasswordColl::Extract (int Index)
436 // Get the entry from the collection and return it. Delete it from the
437 // collection
438 {
439     // Remember old ShouldDelete value and reset it
440     int OldShouldDelete = ShouldDelete;
441     ShouldDelete = 0;
442 
443     // Get the entry
444     PasswordEntry* Entry = At (Index);
445 
446     // Delete it from the collection
447     AtDelete (Index);
448 
449     // Reset ShouldDelete value
450     ShouldDelete = OldShouldDelete;
451 
452     // Return the extracted PasswordEntry
453     return Entry;
454 }
455 
456 
457 
458 /*****************************************************************************/
459 /*                           class PasswordListBox                           */
460 /*****************************************************************************/
461 
462 
463 
464 class PasswordListBox: public ListBox<PasswordEntry> {
465 
466 protected:
467     virtual void Print (int Index, int X, int Y, u16 Attr);
468     // Display one of the listbox entries
469 
470 public:
471     PasswordListBox (const String& aItemText, i16 aID, const Point& aSize,
472                      WindowItem* NextItem);
473 };
474 
475 
476 
PasswordListBox(const String & aItemText,i16 aID,const Point & aSize,WindowItem * NextItem)477 inline PasswordListBox::PasswordListBox (const String& aItemText,
478                                          i16 aID,
479                                          const Point& aSize,
480                                          WindowItem* NextItem):
481     ListBox<PasswordEntry> (aItemText, aID, aSize, atEditNormal,
482                             atEditBar, atEditHigh, NextItem)
483 {
484 }
485 
486 
487 
Print(int Index,int X,int Y,u16 Attr)488 void PasswordListBox::Print (int Index, int X, int Y, u16 Attr)
489 // Display one of the listbox entries
490 {
491     // Zeiger auf den Eintrag holen
492     PasswordEntry* E = Coll->At (Index);
493 
494     // Strings bauen
495     String Password = E->Password;
496     String UserID   = E->UserID;
497     String UserName = E->UserName;
498 
499     String Line (" ");
500     Line += UserID.Trunc (14).Pad (String::Right, 17);
501     Line += UserName.Trunc (30).Pad (String::Right, 34);
502     Line += Password.Pad (String::Right, 18);
503     Line += U32Str (E->Level).Pad (String::Left, 4);
504 
505     Owner->Write (X, Y, Line.Pad (String::Right, Size.X), Attr);
506 }
507 
508 
509 
510 /*****************************************************************************/
511 /*                          Registering the classes                          */
512 /*****************************************************************************/
513 
514 
515 
516 LINK (PasswordEntry, ID_PasswordEntry);
517 LINK (PWLogEntry, ID_PWLogEntry);
518 LINK (PasswordColl, ID_PasswordColl);
519 
520 
521 
522 /*****************************************************************************/
523 /*                              PasswordEditor                               */
524 /*****************************************************************************/
525 
526 
527 
EntryEditor(PasswordEntry * E,int & Abort,int & Changed)528 inline void EntryEditor (PasswordEntry* E, int& Abort, int& Changed)
529 // Allow editing of one password entry
530 {
531     // ID's of the menue items
532     const int miUserID      = 1;
533     const int miUserName    = 2;
534     const int miPassword    = 3;
535     const int miLevel       = 4;
536 
537      // Remember the crc of the entry
538     u32 OldCRC = GetCRC (E);
539 
540     // Store the old data in a memory stream
541     MemoryStream MS (256);
542     MS << *E;
543 
544     // Load the editor window and register all accel keys
545     Menue* M = (Menue*) LoadResource ("PASSWORD.EntryEditwindow");
546     M->RegisterItemKeys ();
547 
548     // Set the menue entries
549     M->SetStringValue (miUserID, E->UserID);
550     M->SetStringValue (miUserName, E->UserName);
551     M->SetStringValue (miPassword, E->Password);
552     M->SetLongValue (miLevel, E->Level);
553 
554     // Set a new status line and activate the window
555     PushStatusLine (siAbort | siAccept | siUpDnCR_Select);
556     M->Activate ();
557 
558     // Allow editing
559     int Done = 0;
560     Changed = 0;
561     while (!Done) {
562 
563         switch (M->GetChoice ()) {
564 
565             case 0:
566                 // Accept or abort
567                 if (M->GetAbortKey () == vkAbort) {
568                     // Editing aborted
569                     if (GetCRC (E) != OldCRC) {
570                         // Entry has been changed
571                         if (AskDiscardChanges () == 2) {
572                             MS >> *E;
573                             Changed = 0;
574                             Abort   = 1;
575                             Done    = 1;
576                         }
577                     } else {
578                         Changed = 0;
579                         Abort   = 1;
580                         Done    = 1;
581                     }
582                 } else {
583                     // Accept, check if all entries are valid
584                     if (E->UserID.IsEmpty ()) {
585                         ErrorMsg (msUserIDEmpty);
586                     } else if (E->UserName.IsEmpty ()) {
587                         ErrorMsg (msUserNameEmpty);
588                     } else if (E->Password.IsEmpty ()) {
589                         ErrorMsg (msPasswordEmpty);
590                     } else {
591                         // Entry is valid
592                         Changed = (GetCRC (E) != OldCRC);
593                         Abort   = 0;
594                         Done    = 1;
595                     }
596                 }
597                 break;
598 
599             case miUserID:
600                 E->UserID   = M->GetStringValue (miUserID);
601                 break;
602 
603             case miUserName:
604                 E->UserName = M->GetStringValue (miUserName);
605                 break;
606 
607             case miPassword:
608                 E->Password = M->GetStringValue (miPassword);
609                 break;
610 
611             case miLevel:
612                 E->Level    = M->GetLongValue (miLevel);
613                 break;
614 
615 
616         }
617 
618     }
619 
620     // Delete window and status line
621     M->UnregisterItemKeys ();
622     delete M;
623     PopStatusLine ();
624 
625 }
626 
627 
628 
PasswordEditor(PasswordColl * PC,int & Abort,int & Changed)629 static void PasswordEditor (PasswordColl* PC, int& Abort, int& Changed)
630 // Allow editing of the given password collection
631 {
632     // Create a memory stream and store the old password data
633     MemoryStream MS;
634     MS << *PC;
635 
636     // Store the crc of the collection to determine if any data has changed
637     u32 OldCRC = GetCRC (PC);
638 
639     // Load the editor window and adjust its size to the screen size
640     Menue* M = (Menue*) LoadResource ("PASSWORD.Editorwindow");
641     Rect WindowSize = M->OuterBounds ();
642     WindowSize.A.Y = 2;
643     WindowSize.B.Y = Background->IYSize () - 2;
644     M->Resize (WindowSize);
645 
646     // Create a listbox and place it in the window
647     PasswordListBox* L = new PasswordListBox ("", 2,
648                                               Point (WindowSize.XSize (), WindowSize.YSize () - 1),
649                                               NULL);
650     L->SetColl (PC);
651     L->SetPos (0, 1);
652     M->AddItem (L);
653     L->Select ();
654 
655     // Push a new statusline and activate (show) the window
656     PushStatusLine (siAbort | siAccept | siInsert | siDelete | siChange);
657     M->Activate ();
658 
659     // User loop
660     int Done = 0;
661     Abort = 0;
662     while (!Done) {
663 
664         // Get a key from the user
665         Key K = KbdGet ();
666 
667         // Feed the key to the listbox
668         L->HandleKey (K);
669 
670         // Get the current listbox entry
671         int Current = L->GetSelected ();
672         PasswordEntry* Entry;
673         PasswordEntry* NewEntry;
674         int EAbort;
675         int EChanged;
676 
677         // Look if there's anything left
678         switch (K) {
679 
680             case vkAbort:
681                 // Ask if anything has changed
682                 if (GetCRC (PC) != OldCRC) {
683                     if (AskDiscardChanges () == 2) {
684                         // Discard changes, end editing
685                         PC->DeleteAll ();
686                         MS >> *PC;
687                         Changed = 0;
688                         Abort   = 1;
689                         Done    = 1;
690                     }
691                 } else {
692                     Changed = 0;
693                     Abort   = 1;
694                     Done    = 1;
695                 }
696                 break;
697 
698             case vkAccept:
699                 Changed = (GetCRC (PC) != OldCRC);
700                 Abort = 0;
701                 Done = 1;
702                 break;
703 
704             case kbEnter:
705                 // Change an entry
706                 if (Current != -1) {
707 
708                     // Get the current entry and delete it from the collection
709                     Entry = PC->Extract (Current);
710 
711                     // Create a duplicate of the entry
712                     NewEntry = Duplicate (Entry);
713 
714                     EntryEditor (NewEntry, EAbort, EChanged);
715                     if (!EAbort && EChanged) {
716                         // Check if the user id already exists
717                         if (PC->UserIDExists (NewEntry)) {
718                             // The id exists, delete the entry
719                             ErrorMsg (msUserIDExists);
720                             delete NewEntry;
721                             PC->Insert (Entry);
722                         } else {
723                             delete Entry;
724                             L->Insert (NewEntry);
725                             L->Reset ();
726                         }
727                     } else {
728                         delete NewEntry;
729                         PC->Insert (Entry);
730                     }
731                 }
732                 break;
733 
734             case vkIns:
735                 // Insert a new entry
736                 Entry = new PasswordEntry;
737                 EntryEditor (Entry, EAbort, EChanged);
738                 if (!EAbort && EChanged) {
739                     // Check if the user id already exists
740                     if (PC->UserIDExists (Entry)) {
741                         // The id exists, delete the entry
742                         ErrorMsg (msUserIDExists);
743                         delete Entry;
744                     } else {
745                         // User id is unique, insert it
746                         L->Insert (Entry);
747                     }
748                 } else {
749                     // Editing was aborted, delete the entry
750                     delete Entry;
751                 }
752                 break;
753 
754             case vkDel:
755                 // Delete the current entry
756                 if (Current != -1 && AskAreYouShure () == 2) {
757                     L->Delete (Current);
758                 }
759                 break;
760 
761         }
762 
763     }
764 
765     // The listbox will delete the owned collection if we don't set it to NULL
766     // before deleting the window (including the listbox)
767     L->SetColl (NULL);
768     delete M;
769 
770     // Restore the old status line
771     PopStatusLine ();
772 
773 }
774 
775 
776 
ReadPasswordFile(const String & Filename)777 static PasswordColl* ReadPasswordFile (const String& Filename)
778 // Read the password file and return the password collection. If there is no
779 // password file, return an empty collection
780 {
781     PasswordColl* PC;
782 
783     // Try to open the file
784     FileStream S (Filename, "rb");
785     if (S.GetStatus () != stOk) {
786         // new file, create a collection
787         PC = new PasswordColl;
788     } else {
789         // Load a password collection from the stream and check for errors
790         PC = (PasswordColl*) S.Get ();
791         if (!PC || S.GetStatus () != stOk) {
792             ErrorMsg (msCannotReadPasswordFile, Filename.GetStr ());
793         }
794     }
795 
796     return PC;
797 }
798 
799 
800 
PasswordEditor(const String & Filename)801 void PasswordEditor (const String& Filename)
802 // Loads a password collection from the given file and allows editing users/
803 // passwords
804 {
805     // Load the password collection from the file
806     PasswordColl* PC = ReadPasswordFile (Filename);
807 
808     // Allow editing
809     int Abort;
810     int Changed;
811     PasswordEditor (PC, Abort, Changed);
812 
813     // If the collection has been changed, store it
814     if (!Abort && Changed) {
815         FileStream S (Filename, "wb");
816         if (S.GetStatus () != stOk) {
817             ErrorMsg (msCannotOpenPasswordFile, Filename.GetStr ());
818             return;
819         }
820         S.Truncate ();
821         S.Put (PC);
822         if (S.GetStatus () != stOk) {
823             ErrorMsg (msCannotWritePasswordFile, Filename.GetStr ());
824             return;
825         }
826     }
827 
828 }
829 
830 
831 
832 /*****************************************************************************/
833 /*                               Login/Logout                                */
834 /*****************************************************************************/
835 
836 
837 
ResetLoginData()838 static void ResetLoginData ()
839 // Reset the login data
840 {
841     _CUN  = "";
842     _CUID = "";
843     _CPL  = 0;
844 }
845 
846 
847 
Log(const String & Logname,const String & Name,const String & ID,u32 Level,PWLogEntry::_What What)848 static void Log (const String& Logname, const String& Name, const String& ID,
849                  u32 Level, PWLogEntry::_What What)
850 {
851     if (Logname.IsEmpty ()) {
852         return;
853     }
854     FileStream S (Logname);
855     S.SeekToEnd ();
856     if (S.GetStatus () == stOk) {
857         PWLogEntry LE (Name, ID, Level, What);
858         S.Put (LE);
859     }
860 }
861 
862 
863 
Login(const String & PWName,const String & Logname)864 void Login (const String& PWName, const String& Logname)
865 // Ask for user id and password and set the variables CUN CUID and CPL
866 // according to the users password entry.
867 // If Logname is not empty, a binary log of all login attempts is stored there.
868 {
869     int Abort;
870 
871     // Read in the user id
872     Menue* M = (Menue*) LoadResource ("PASSWORD.UserID-Window");
873     TextEdit* TE = (TextEdit*) M->ForcedItemWithID (1);
874     TE->Edit (Abort);
875     String UserID = TE->GetValue ();
876     delete M;
877     if (Abort) {
878         return;
879     }
880 
881     // Read in the password
882     M = (Menue*) LoadResource ("PASSWORD.Password-Window");
883     PasswordEdit* PE = (PasswordEdit*) M->ForcedItemWithID (1);
884     PE->Edit (Abort);
885     String Password = PE->GetValue ();
886     delete M;
887     if (Abort) {
888         return;
889     }
890 
891     // Load the password collection from the file
892     PasswordColl* PC = ReadPasswordFile (PWName);
893 
894     // Search for the user id
895     int Index;
896     if (PC->Search (&UserID, Index) == 0 || PC->At (Index)->Password != Password) {
897         // Not found, pop up an error message, reset data
898         ErrorMsg (msInvalidLogin);
899         Log (Logname, "", UserID, 0, PWLogEntry::Fail);
900         ResetLoginData ();
901         return;
902     } else {
903         // Found, set the login data, log the login
904         PasswordEntry* PE = PC->At (Index);
905         _CUN  = PE->UserName;
906         _CUID = PE->UserID;
907         _CPL  = PE->Level;
908         Log (Logname, CUN, CUID, CPL, PWLogEntry::Login);
909     }
910 }
911 
912 
913 
Logout(const String & Logname)914 void Logout (const String& Logname)
915 // Reset the user data. If Logname is not empty, a binary log of the
916 // login/logout sequences is kept there.
917 {
918     // First, check if a logout is necessary
919     if (CPL == 0) {
920         return;
921     }
922 
923     // Log the logout
924     if (!Logname.IsEmpty ()) {
925         PWLogEntry LE (CUN, CUID, CPL, PWLogEntry::Logout);
926         FileStream S (Logname);
927         S.Put (LE);
928     }
929 
930     // Reset the data
931     ResetLoginData ();
932 }
933 
934 
935 
936