Note #1 on the voicemail program, Feb 11 2004 The MailData class keeps two MessageQueue objects, for new and saved messages, which we will call _new and _kept. Here is an outline of an algorithm to process message-review correctly, and an indication of an interface that would allow clients external to MailData (such as MailSystem or MailAccount) to implement retrieve_messages in a sensible fashion. The existing interface treats the concatenation of _new+_kept as a single unit. This leads to awkwardness in message ordering. Our goal here is to guarantee that messages in _kept always appear in the order received. We initialize by setting the current message to the head of the two lists; an interface function head() might do this. head() should return the number of messages; it may be zero. After each message (possibly returned by a next() interface function), a "disposition" needs to be supplied; it is one of {DELETE, SAVE, QUIT} (QUIT is hangup, or end-of-file, etc). Possibly the disposition of the previous message would be a parameter to next(). The next() function should also return an indication of no more messages. To process NEW messages: display each message in turn. if the disposition is DELETE, remove the message from the queue if the disposition is KEEP, remove the message from _new append the message to _keep these two steps should be done "atomically", without the possibility of a QUIT between them if the disposition is QUIT, leave the last message in _new, and return. Postcondition: messages in _new are in same relative order as at beginning. All messages in _new are newer than any messages in _kept We are done with this phase when _new is empty or we've received a QUIT disposition. To process KEPT messages: create a copy MessageQueue, _copy display each message in _kept in turn. If the disposition is DELETE, remove the message from _kept if the disposition is KEEP, remove the message from _kept append the message to _copy, atomically as before if the disposition is QUIT copy the remaining messages in _kept to _copy replace _kept by _copy (eg via assignment) Postcondition: kept messages are in same relative order as at beginning We are done with the KEPT phase when _kept is empty or we've received a QUIT. Note that the client doing the message processing doesn't need to know which messages are from _new and which are from _kept (although it might be nice to make that information available to the user, it doesn't affect how the client proceeds). The _new/_kept distinction is part of the internals. The algorithm here hints at an iterator interface: int head() // reset internal cursor to head of _new // any previous _copy is cleared bool atEnd() // returns true when there are no more messages Message next(Disposition d) // If d=QUIT, just wrap up any loose ends // Otherwise return the next message, after handling the // disposition of DELETE or KEEP for the prev message. // if there was no previous message, ignore d // if there is no next message, we return an empty message // (note we do this to provide a disposition for // the final message) // if desired, next can also return one of NEW, KEPT The existing program doesn't use this algorithm. Instead, it processes _new and _kept as a single queue, putting the saved messages from either into _copy which is created at the beginning. Watch what happens in the following use case: * message 1 is left * message 2 is left * user listens to message 1, saves it, and hangs up. _new=[2], _kept=[1] * message 3 is left * user listens to and keeps all messages The message order is now [2, 3, 1]. The algorithm processes _new and _kept as a single queue, but in the order first-new-then-kept. Messages to be kept are put into _copy. Thus, we put into _copy the messages in the following order: 2 & 3 (from _new) 1 (from _kept) Thus, the central issue in the algorithm above is that when next() notices that we've moved from _new to _kept, it creates _copy at the point when the first message from _kept is returned. =========== The voicemail program contains a call to "itoa", that converts an integer to an alphanumeric string (a C string). This is defined in the windows , but *not* in the gnu stdlib.h. So, I've added it, to allow gnudists to run this program as well.