Comp 272 Programming assignment 2 Dordal February 9, 2004 Due: Wed, Feb 18 Take the mail system program, and make the following changes. The program, mail.cpp, is available on my web page. 1. In the original version, when you enter the wrong password, you don't get prompted for a new one. Change this so you do. The user should be allowed MAX_TRIES = 3 attempts in all, including the first attempt. If a user fails to enter a correct password after that many tries, the system should hang up on them. 2. Add an option to the administrative mailbox to change the passcode and greeting of any other mailbox. Press 5 to change the passcode of another mailbox 3. Fix the message ordering: messages in Mailbox::_kept should always be stored in the order received. That is, when retrieve_messages() reviews messages in _new and _kept, then: * saved messages in _new should go to the end of _kept * when reviewing _kept, saved messages should remain in original order. 4. Separate out the command-and-menu-processing and mail-data parts of class Maibox into two separate classes. The mail-related data -- the MessageQueues _new and _kept, the greeting, and the passcode -- might be in a class named MailData, and the user-interface parts might be in a class named MailAccount (although it might be simpler to let the MailAccount class retain the old Mailbox name). The hardest part of part 4 is having MailAccount::retrieve_messages manipulate MailData::_new and MailData::_kept appropriately. I will allow you to keep retrieve_messages in MailData, and will treat moving that to MailAccount as extra credit. MailAccount (or Mailbox, if you retain that name) will now: Play the greeting Get messages from the user Put them into the Mailbox On receipt of "#" instead of a message, prompt for the passcode and verify that it is correct. Execute the prompt_command/do_command loop to carry out functions, with retrieve_messages possibly remaining as a call to MailData. In some sense the essential data of MailAccount will now be the menu presented by prompt_command. The main point of part 4 is that this redesign changes the class interfaces involved, because the class responsibilities are different. For example, you will now need a way for MailAccount to print the greeting, to add a new message to the MailData, and to verify that the passcode supplied is correct when login is attempted. The first can be handled by an accessor: string MailData::greeting() To add new messages, we will use bool MailData::addnewmessage(Message m); This returns true if the append succeeds, and false if not (which happens when the mailbox is already full). MailAccount::prompt_menu() will also need a way to check if there are any messages, because if there are not then the first menu item (listen to the messages) is skipped. To check the passcode, either of the following would work: int Mailbox::passcode(); // get original passcode bool Mailbox::checkpasscode(int passcode); // check if supplied passcode is good The second approach is more in keeping with how real passcode systems work (which generally do *not* keep unencrypted or even unencryptable copies of the original passcodes anywhere around), but you may choose either. The second option also allows for multiple passcodes. As for parts 1 and 2, note that #1 (prompting for the passcode) will now be handled within MailAccount. Item #2, letting admin mailboxes change other mailboxes, is more interesting in that it will require a significant interface tweak. Specifically, from within AdminMailbox, how do we even find another mailbox? The mailboxes are stored within a private vector Mailsystem._mailboxes Any other mailbox is *invisible* to AdminMailbox! Making "_mailboxes" public would be dastardly. The slickest way to fix this is to have an accessor in MailSystem that returns a *reference* to any Mailbox, or, for those so inclined, a pointer. We've covered neither technique so far. We can (and will!) have AdminMailbox call Mailsystem::locate_mailbox(int extn); this gets us the index of the other mailbox in the array "_mailboxes". But we now need a member function in *MailSystem* to take the mailbox index (or the original extension, if you prefer), and the new passcode, and make the appropriate call to Mailbox::setpasscode(). In the mail2004.cpp file on my web page, I renamed the original Mailbox class "MailData". I then created a new Mailbox class that contains a MailData member object, _mbox. Every Mailbox member function then just calls the corresponding MailData function, for example: void retrieve_messages() {_mbox.retrieve_messages();} void change_greeting() {_mbox.change_greeting();} void change_passcode() {_mbox.change_passcode();} The easiest way to proceed is to change the implementation of all of these (except maybe retrieve_messages(), as discussed above) so that the user interaction moves back to Mailbox/MailAccount and out of MailData. Note that the mail2004.cpp file compiles, but it does not run properly, as AdminMailbox hasn't been appropriately modified. You will have to rewrite AdminMailbox, so that its do_command(), etc functions behave appropriately. An AdminMailbox will contain a MailData, just like everyone else's; the difference is entirely within the MailAccount/Mailbox part.