#include "rolodex.h" #ifdef HAVE_XCURSES char *XCursesProgramName="rolodex"; #endif /* * This is the main part of the loop. */ int main(int argc, char **argv) { /* Declare variables. */ CDKSCREEN *cdkscreen; CDKMENU *rolodexMenu; CDKLABEL *rolodexTitle; SRolodex groupList[MAXGROUPS]; WINDOW *cursesWin; char *menulist[MAX_MENU_ITEMS][MAX_SUB_ITEMS], *title[5]; char *home, temp[256], *mesg[15]; int subMenuSize[10], menuLocations[10], selection; int group, ret, x; int groupCount = 0; /* Set up CDK */ cursesWin = initscr(); cdkscreen = initCDKScreen (cursesWin); /* Start CDK color. */ initCDKColor(); /* Create the menu lists. */ menulist[0][0] = "File";menulist[1][0] = "Groups"; menulist[0][1] = "Open ";menulist[1][1] = "New "; menulist[0][2] = "Save ";menulist[1][2] = "Open "; menulist[0][3] = "Save As";menulist[1][3] = "Delete"; menulist[0][4] = "Quit "; menulist[2][0] = "Print";menulist[3][0] = "Help"; menulist[2][1] = "Print Groups";menulist[3][1] = "About Rolodex "; menulist[3][2] = "Rolodex Statistics"; /* Set up the sub-menu sizes and their locations. */ subMenuSize[0] = 5;menuLocations[0] = LEFT; subMenuSize[1] = 4;menuLocations[1] = LEFT; subMenuSize[2] = 2;menuLocations[2] = LEFT; subMenuSize[3] = 3;menuLocations[3] = RIGHT; /* Create the menu. */ rolodexMenu = newCDKMenu (cdkscreen, menulist, 4, subMenuSize, menuLocations, TOP, A_BOLD|A_UNDERLINE, A_REVERSE); /* Create the title. */ title[0]= "Cdk Rolodex"; title[1]= "Written by Mike Glover"; rolodexTitle = newCDKLabel (cdkscreen, CENTER, CENTER, title, 2, FALSE, FALSE); /* Define the help key binding. */ bindCDKObject (vMENU, rolodexMenu, '?', helpCB, NULL); /* Draw the CDK screen. */ refreshCDKScreen (cdkscreen); /* Check the value of the HOME env var. */ home = getenv ("HOME"); if (home != (char *)NULL) { /* Make sure the $HOME/.rolodex directory exists. */ sprintf (temp, "%s/.rolodex", home); /* Set the value of the global rolodex DBM directory. */ GDBMDir = copyChar (temp); /* Set the value of the global RC filename. */ sprintf (temp, "%s/.rolorc", home); GRCFile = copyChar (temp); } else { /* Set the value of the global rolodex DBM directory. */ GDBMDir = copyChar (".rolodex"); /* Set the value of the global RC filename. */ GRCFile = copyChar (".rolorc"); } /* Make the rolodex directory. */ mkdir (GDBMDir, 0755); /* Open the rolodex RC file. */ groupCount = readRCFile (GRCFile, groupList); /* Check the value of groupCount. */ if (groupCount < 0) { /* The RC file seems to be corrupt. */ sprintf (temp, "The RC file (%s) seems to be corrupt.", GRCFile); mesg[0] = copyChar (temp); mesg[1] = "No rolodex groups were loaded."; mesg[2] = "Press any key to continue."; popupLabel (cdkscreen, mesg, 3); freeChar (mesg[0]); groupCount = 0; } else if (groupCount == 0) { mesg[0] = "Empty rolodex RC file. No groups loaded."; mesg[1] = "Press any key to continue."; popupLabel (cdkscreen, mesg, 2); } else { if (groupCount == 1) { sprintf (temp, "There was 1 group loaded from the RC file."); } else { sprintf (temp, "There were %d groups loaded from the RC file.", groupCount); } mesg[0] = copyChar (temp); mesg[1] = "Press any key to continue."; popupLabel (cdkscreen, mesg, 2); freeChar (mesg[0]); } /* Loop until we are done. */ for (;;) { /* Activate the menu */ selection= activateCDKMenu (rolodexMenu, (chtype *)NULL); /* Check the return value of the selection. */ if (selection == 0) { /* Open the rolodex RC file. */ groupCount = openNewRCFile (cdkscreen, groupList, groupCount); } else if (selection == 1) { /* Write out the RC file. */ ret = writeRCFile (cdkscreen, GRCFile, groupList, groupCount); /* Reset the saved flag if the rc file saved ok. */ if (ret != 0) { GGroupModified = 0; } } else if (selection == 2) { /* Save as. */ ret = writeRCFileAs (cdkscreen, groupList, groupCount); /* Reset the saved flag if the rc file saved ok. */ if (ret != 0) { GGroupModified = 0; } } else if (selection == 3) { /* Has anything changed??? */ if (GGroupModified != 0) { /* Write out the RC file. */ writeRCFile (cdkscreen, GRCFile, groupList, groupCount); } /* Remove the CDK widget pointers. */ destroyCDKMenu (rolodexMenu); destroyCDKLabel (rolodexTitle); destroyCDKScreen (cdkscreen); delwin (cursesWin); /* Free up other pointers. */ freeChar (GCurrentGroup); freeChar (GRCFile); freeChar (GDBMDir); /* Clean up the group information. */ for (x=0; x < groupCount; x++) { freeChar (groupList[x].name); freeChar (groupList[x].desc); freeChar (groupList[x].dbm); } /* Shutdown CDK. */ endCDK(); /* Exit cleanly. */ exit (0); } else if (selection == 100) { /* Add a new group to the list. */ groupCount = addRolodexGroup (cdkscreen, groupList, groupCount); } else if (selection == 101) { /* If there are no groups, ask them if they want to create a new one. */ if (groupCount == 0) { char *buttons[] = {"", ""}; mesg[0] = "There are no groups defined."; mesg[1] = "Do you want to define a new group?"; /* Add the group if they said yes. */ if (popupDialog (cdkscreen, mesg, 2, buttons, 2) == 0) { groupCount = addRolodexGroup (cdkscreen, groupList, groupCount); } } else { /* Get the number of the group to open. */ group = pickRolodexGroup (cdkscreen, "Open Rolodex Group", groupList, groupCount); /* Make sure a group was picked. */ if (group >= 0) { /* Set the global variable GCurrentGroup */ freeChar (GCurrentGroup); GCurrentGroup = copyChar (groupList[group].name); /* Try to open the DBM file and read the contents. */ useRolodexGroup (cdkscreen, groupList[group].name, groupList[group].desc, groupList[group].dbm); } } } else if (selection == 102) { /* Delete the group chosen. */ groupCount = deleteRolodexGroup (cdkscreen, groupList, groupCount); } else if (selection == 200) { /* Print Phone Number Group. */ printGroupNumbers (cdkscreen, groupList, groupCount); } else if (selection == 300) { /* About Rolodex. */ aboutCdkRolodex(cdkscreen); } else if (selection == 301) { displayRolodexStats (rolodexMenu->screen, groupCount); } } } /* * This writes out the new RC file. */ int writeRCFile (CDKSCREEN *screen, char *filename, SRolodex *groupList, int groupCount) { /* Declare local variables. */ char *mesg[5], temp[256]; time_t clck; FILE *fd; int x; /* Can we open the file? */ if ((fd = fopen (filename, "w")) == NULL) { /* Pop up a message. */ sprintf (temp, "The file <%s> could not be opened.", filename); mesg[0] = copyChar (temp); #ifdef NOSTRERR sprintf (temp, "Unknown reason."); #else sprintf (temp, "%s", strerror(errno)); #endif mesg[1] = copyChar (temp); mesg[2] = "Press any key to continue."; popupLabel (screen, mesg, 3); freeChar (mesg[0]); freeChar (mesg[1]); return (0); } /* Get the current time. */ time(&clck); /* Put some comments at the top of the header. */ fprintf (fd, "#\n"); fprintf (fd, "# This file was automatically generated on %s", ctime(&clck)); fprintf (fd, "#\n"); /* Start writing the RC file. */ for (x=0; x < groupCount; x++) { fprintf (fd, "%s%s%s\n", groupList[x].name, groupList[x].desc, groupList[x].dbm); } fclose (fd); /* Pop up a message stating that it has been saved. */ if (groupCount == 1) { sprintf (temp, "There was 1 group saved to file"); mesg[0] = copyChar (temp); } else { sprintf (temp, "There were %d groups saved to file", groupCount); mesg[0] = copyChar (temp); } sprintf (temp, "%s", filename); mesg[1] = copyChar (temp); mesg[2] = "Press any key to continue."; popupLabel (screen, mesg, 3); freeChar (mesg[0]); freeChar (mesg[1]); return (1); } /* * This allows the user to pick a DBM file to open. */ int pickRolodexGroup (CDKSCREEN *screen, char *title, SRolodex *groupList, int groupCount) { /* Declare local variables. */ CDKSCROLL *roloList = (CDKSCROLL *)NULL; int height = groupCount; char *mesg[MAXGROUPS], temp[256]; int selection, x; /* Determine the height of the scrolling list. */ if (groupCount > 5) { height = 5; } height += 3; /* Copy the names of the scrolling list into an array. */ for (x=0; x < groupCount; x++) { sprintf (temp, "%s", groupList[x].name); mesg[x] = copyChar (temp); } /* Create the scrolling list. */ roloList = newCDKScroll (screen, CENTER, CENTER, NONE, height, 50, title, mesg, groupCount, NONUMBERS, A_REVERSE, TRUE, FALSE); /* Create a callback to the scrolling list. */ bindCDKObject (vSCROLL, roloList, '?', groupInfoCB, groupList); /* Activate the scrolling list. */ selection = activateCDKScroll (roloList, (chtype *)NULL); /* Destroy the scrolling list. */ destroyCDKScroll (roloList); for (x=0; x < groupCount; x++) { freeChar (mesg[x]); } /* Return the item selected. */ return selection; } /* * This allows the user to add a rolo group to the list. */ int addRolodexGroup (CDKSCREEN *screen, SRolodex *groupList, int groupCount) { /* Declare local variables. */ CDKENTRY *newName= (CDKENTRY *)NULL; CDKENTRY *newDesc= (CDKENTRY *)NULL; char *mesg[4], *desc, *newGroupName, temp[256]; int x; /* Create the name widget. */ newName = newCDKEntry (screen, CENTER, 8, "New Group Name", " Name: ", A_NORMAL, '_', vMIXED, 20, 2, 256, TRUE, FALSE); /* Get the name. */ newGroupName = activateCDKEntry (newName, (chtype *)NULL); /* Make sure they didn't hit escape. */ if (newName->exitType == vESCAPE_HIT) { mesg[0] = "Add Group Canceled."; destroyCDKEntry (newName); popupLabel (screen, mesg, 1); return groupCount; } /* Make sure that group name does not already exist. */ for (x=0; x < groupCount; x++) { if (strcmp (newGroupName, groupList[x].name) == 0) { sprintf (temp, "Sorry the group (%s) already exists.", newGroupName); mesg[0] = copyChar (temp); popupLabel (screen, mesg, 1); freeChar (mesg[0]); destroyCDKEntry (newName); return groupCount; } } /* Keep the name. */ groupList[groupCount].name = copyChar (newGroupName); /* Create the description widget. */ newDesc = newCDKEntry (screen, CENTER, 13, "Group Description", "Descriprion: ", A_NORMAL, '_', vMIXED, 20, 2, 256, TRUE, FALSE); /* Get the description. */ desc = activateCDKEntry (newDesc, (chtype *)NULL); /* Check if they hit escape or not. */ if (newDesc->exitType == vESCAPE_HIT) { groupList[groupCount].desc = copyChar ("No Description Provided."); } else { groupList[groupCount].desc = copyChar (desc); } /* Create the DBM filename. */ sprintf (temp, "%s/%s.phl", GDBMDir, groupList[groupCount].name); groupList[groupCount].dbm = copyChar (temp); /* Inrement the group count. */ groupCount++; GGroupModified = 1; /* Destroy the widgets. */ destroyCDKEntry (newName); destroyCDKEntry (newDesc); return groupCount; } /* * This displays rolodex information. */ void displayRolodexStats (CDKSCREEN *screen, int groupCount) { /* Declare local variables. */ char *mesg[6], temp[256]; /* Create the information to display. */ sprintf (temp, "Rolodex Statistics"); mesg[0] = copyChar (temp); sprintf (temp, "Read Command Filename %s", GRCFile); mesg[1] = copyChar (temp); sprintf (temp, "Group Count %d", groupCount); mesg[2] = copyChar (temp); /* Display the message. */ popupLabel (screen, mesg, 3); /* Clean up. */ freeChar (mesg[0]); freeChar (mesg[1]); freeChar (mesg[2]); } /* * This function gets a new rc filename and saves the contents of the * groups under that name. */ int writeRCFileAs (CDKSCREEN *screen, SRolodex *groupList, int groupCount) { /* Declare local variables. */ CDKENTRY *newRCFile; char *newFilename; int ret; /* Create the entry field. */ newRCFile = newCDKEntry (screen, CENTER, CENTER, "Save As", "Filename: ", A_NORMAL, '_', vMIXED, 20, 2, 256, TRUE, FALSE); /* Add a pre-process function so no spaces are introduced. */ setCDKEntryPreProcess (newRCFile, entryPreProcessCB, NULL); /* Get the filename. */ newFilename = activateCDKEntry (newRCFile, NULL); /* Check if they hit escape or not. */ if (newRCFile->exitType == vESCAPE_HIT) { destroyCDKEntry (newRCFile); return 1; } /* Call the function to save the RC file. */ ret = writeRCFile (screen, newFilename, groupList, groupCount); /* Reset the saved flag if the rc file saved ok. */ if (ret != 0) { /* Change the default filename. */ freeChar (GRCFile); GRCFile = copyChar (newFilename); GGroupModified = 0; } /* Clean up. */ destroyCDKEntry (newRCFile); return 1; } /* * This opens a new RC file. */ int openNewRCFile (CDKSCREEN *screen, SRolodex *groupList, int groupCount) { /* Declare local variables. */ CDKFSELECT *fileSelector; char *filename, *mesg[10], temp[256]; int x; /* Get the filename. */ fileSelector = newCDKFselect (screen, CENTER, CENTER, 20, 55, "Open RC File", "Filename: ", A_NORMAL, '.', A_REVERSE, "", "", "", "", TRUE, FALSE); /* Activate the file selector. */ filename = activateCDKFselect (fileSelector, NULL); /* Check if the file selector left early. */ if (fileSelector->exitType == vESCAPE_HIT) { destroyCDKFselect (fileSelector); mesg[0] = "Open New RC File Aborted."; popupLabel (screen, mesg, 1); return groupCount; } /* Clean out the old information. */ for (x=0; x < groupCount; x++) { freeChar (groupList[x].name); freeChar (groupList[x].desc); freeChar (groupList[x].dbm); } /* Open the RC file. */ groupCount = readRCFile (filename, groupList); /* Check the return value. */ if (groupCount < 0) { /* This file does not appear to be a rolodex file. */ mesg[0] = "The file"; sprintf (temp, "(%s)", filename); mesg[1] = copyChar (temp); mesg[2] = "does not seem to be a rolodex RC file."; mesg[3] = "Press any key to continue."; popupLabel (screen, mesg, 4); freeChar (mesg[1]); groupCount = 0; } /* Clean up. */ destroyCDKFselect (fileSelector); return groupCount; } /* * This reads the users rc file. */ int readRCFile (char *filename, SRolodex *groupList) { /* Declare variables. */ int groupsFound= 0; int errorsFound= 0; char *lines[MAX_LINES], *items[100]; int linesRead, chunks, x, y; /* Open the file and start reading. */ linesRead = readFile (filename, lines, MAX_LINES); /* Check the number of lines read. */ if (linesRead == 0) { return (0); } /* * Cycle through what was given to us and save it. */ for (x=0; x < linesRead; x++) { /* Strip white space from the line. */ stripWhiteSpace (vBOTH, lines[x]); /* Only split lines which do not start with a # */ if (strlen (lines[x]) != 0 && lines[x][0] != '#') { /* Split the line on the = sign. */ chunks = splitString (lines[x], items, ''); /* Only take the ones which fit the format. */ if (chunks == 3) { /* Clean off the name and DB name. */ stripWhiteSpace (vBOTH, items[0]); stripWhiteSpace (vBOTH, items[1]); stripWhiteSpace (vBOTH, items[2]); /* Set the group name and DB name. */ groupList[groupsFound].name = items[0]; groupList[groupsFound].desc = items[1]; groupList[groupsFound].dbm = items[2]; groupsFound++; } else { /* Don't forget the clean up the memory. */ for (y=0; y < chunks; y++) { freeChar (items[y]); } errorsFound++; } } } /* Clean up. */ for (x=0; x < linesRead; x++) { freeChar (lines[x]); } /* Check the number of groups to the number of errors. */ if (errorsFound > 0 && groupsFound == 0) { /* This does NOT look like the rolodex RC file. */ return -1; } return groupsFound; } /* * This function allows the user to add/delete/modify/save the * contents of a rolodex group. */ void useRolodexGroup (CDKSCREEN *screen, char *groupName, char *groupDesc, char *groupDBM) { /* Declare local variables. */ CDKSCROLL *nameList= (CDKSCROLL *)NULL; CDKLABEL *helpWindow = (CDKLABEL *)NULL; SPhoneData phoneData; SPhoneRecord *phoneRecord; char *index[MAX_ITEMS], *title[3], *mesg[3], temp[256]; int phoneCount, selection, height, x; /* Set up the help window at the bottom of the screen. */ title[0] = "<#HL(30)>"; title[1] = "Press ? to get detailed help."; title[2] = "<#HL(30)>"; helpWindow= newCDKLabel (screen, CENTER, BOTTOM, title, 3, FALSE, FALSE); drawCDKLabel (helpWindow, FALSE); /* Open the DBM file and read in the contents of the file */ phoneCount = readPhoneDataFile (groupDBM, &phoneData); phoneData.recordCount = phoneCount; /* Check the number of entries returned. */ if (phoneCount == 0) { /* * They tried to open an empty group, maybe they want to * add a new entry to this number. */ char *buttons[] = {"", ""}; mesg[0] = "There were no entries in this group."; mesg[1] = "Do you want to add a new listng?"; if (popupDialog (screen, mesg, 2, buttons, 2) == 1) { destroyCDKLabel (helpWindow); return; } /* Get the information for a new number. */ if (addPhoneRecord (screen, &phoneData) != 0) { return; } } else if (phoneCount < 0) { mesg[0] = "Could not open the database for this group."; popupLabel (screen, mesg, 1); destroyCDKLabel (helpWindow); return; } /* Set up the data needed for the scrolling list. */ for (x=0; x < phoneData.recordCount; x++) { phoneRecord = &phoneData.record[x]; sprintf (temp, "%s (%s)", phoneRecord->name, GLineType[phoneRecord->lineType]); index[x] = copyChar (temp); } sprintf (temp, "Listing of Group %s", groupName); height = (phoneData.recordCount > 5 ? 8 : phoneData.recordCount+3); /* Create the scrolling list. */ nameList = newCDKScroll (screen, CENTER, CENTER, RIGHT, height, 50, temp, index, phoneData.recordCount, NUMBERS, A_REVERSE, TRUE, FALSE); /* Clean up. */ for (x=0; x < phoneData.recordCount; x++) { freeChar (index[x]); } /* Create key bindings. */ bindCDKObject (vSCROLL, nameList, 'i', insertPhoneEntryCB, &phoneData); bindCDKObject (vSCROLL, nameList, 'd', deletePhoneEntryCB, &phoneData); bindCDKObject (vSCROLL, nameList, DELETE, deletePhoneEntryCB, &phoneData); bindCDKObject (vSCROLL, nameList, '?', phoneEntryHelpCB, NULL); /* Let them play. */ selection = 0; while (selection >= 0) { /* Get the information they want to view. */ selection = activateCDKScroll (nameList, (chtype *)NULL); /* Display the information. */ if (selection >= 0) { /* Display the information. */ displayPhoneInfo (screen, phoneData.record[selection]); } } /* Save the rolodex information to file. */ if (savePhoneDataFile (groupDBM, &phoneData) == 0) { /* Something happened. */ mesg[0] = "Could not save phone data to data file."; mesg[1] = "All changes have been lost."; popupLabel (screen, mesg, 2); } /* Clean up. */ for (x=0; x < phoneData.recordCount; x++) { freeChar (phoneData.record[x].name); freeChar (phoneData.record[x].phoneNumber); freeChar (phoneData.record[x].address); freeChar (phoneData.record[x].city); freeChar (phoneData.record[x].province); freeChar (phoneData.record[x].postalCode); freeChar (phoneData.record[x].desc); } destroyCDKScroll (nameList); destroyCDKLabel (helpWindow); } /* * This opens a phone data file and returns the number of elements read. */ int readPhoneDataFile (char *dataFile, SPhoneData *phoneData) { /* Declare variables. */ char *lines[MAX_LINES], *items[30]; int linesRead= 0; int chunks= 0; int linesFound= 0; int x, y; /* Open the file and start reading. */ linesRead = readFile (dataFile, lines, MAX_LINES); /* Check the number of lines read. */ if ((linesRead == 0) || (linesRead == -1)) { return (0); } /* * Cycle through what was given to us and save it. */ for (x=0; x < linesRead; x++) { if (lines[x][0] != '#') { /* Split the string. */ chunks = 0; chunks = splitString (lines[x], items, ''); /* Copy the chunks. */ if (chunks == 8) { phoneData->record[linesFound].name = items[0]; phoneData->record[linesFound].lineType = atoi (items[1]); phoneData->record[linesFound].phoneNumber = items[2]; phoneData->record[linesFound].address = items[3]; phoneData->record[linesFound].city = items[4]; phoneData->record[linesFound].province = items[5]; phoneData->record[linesFound].postalCode = items[6]; phoneData->record[linesFound].desc = items[7]; freeChar (items[1]); linesFound++; } else { /* Bad line in the file; recover the memory. */ for (y=0; y <= chunks; y++) { freeChar (items[y]); } } } } /* Clean up. */ for (x=0; x < linesRead; x++) { freeChar (lines[x]); } /* Keep the record count and return. */ phoneData->recordCount = linesFound; return linesFound; } /* * This opens a phone data file and returns the number of elements read. */ int savePhoneDataFile (char *filename, SPhoneData *phoneData) { /* Declare variables. */ SPhoneRecord *phoneRecord; time_t clck; FILE *fd; int x; /* Can we open the file? */ if ((fd = fopen (filename, "w")) == NULL) { return 0; } /* Get the current time. */ time(&clck); /* Add the header to the file. */ fprintf (fd, "#\n"); fprintf (fd, "# This file was automatically saved on %s", ctime(&clck)); fprintf (fd, "# There should be %d phone numbers in this file.\n", phoneData->recordCount); fprintf (fd, "#\n"); /* Cycle through the data and start writing it to the file. */ for (x=0; x < phoneData->recordCount; x++) { /* Get a pointer to the object. */ phoneRecord = &phoneData->record[x]; /* Check the phone type. */ if (phoneRecord->lineType == vCell || phoneRecord->lineType == vPager) { fprintf (fd, "%s%d%s----%s\n", phoneRecord->name, phoneRecord->lineType, phoneRecord->phoneNumber, phoneRecord->desc); } else { fprintf (fd, "%s%d%s%s%s%s%s%s\n", phoneRecord->name, phoneRecord->lineType, phoneRecord->phoneNumber, phoneRecord->address, phoneRecord->city, phoneRecord->province, phoneRecord->postalCode, phoneRecord->desc); } } fclose (fd); return 1; } /* * This displays the information about the phone record. */ void displayPhoneInfo (CDKSCREEN *screen, SPhoneRecord record) { /* Declare local variables. */ char *mesg[10], temp[256]; /* Check the type of line it is. */ if (record.lineType == vVoice || \ record.lineType == vData1 || \ record.lineType == vData2 || \ record.lineType == vData3 || \ record.lineType == vFAX1 || \ record.lineType == vFAX2 || \ record.lineType == vFAX3) { /* Create the information to display. */ sprintf (temp, "%s Phone Record", GLineType[record.lineType]); mesg[0] = copyChar (temp); sprintf (temp, "Name %s", record.name); mesg[1] = copyChar (temp); sprintf (temp, "Phone Number%s", record.phoneNumber); mesg[2] = copyChar (temp); sprintf (temp, "Address %s", record.address); mesg[3] = copyChar (temp); sprintf (temp, "City %s", record.city); mesg[4] = copyChar (temp); sprintf (temp, "Province %s", record.province); mesg[5] = copyChar (temp); sprintf (temp, "Postal Code %s", record.postalCode); mesg[6] = copyChar (temp); sprintf (temp, "Comment %s", record.desc); mesg[7] = copyChar (temp); /* Pop the information up on the screen. */ popupLabel (screen, mesg, 8); /* Clean up. */ freeChar (mesg[0]); freeChar (mesg[1]); freeChar (mesg[2]); freeChar (mesg[3]); freeChar (mesg[4]); freeChar (mesg[5]); freeChar (mesg[6]); freeChar (mesg[7]); } else if (record.lineType == vPager || record.lineType == vCell) { /* Create the information to display. */ sprintf (temp, "%s Phone Record", GLineType[record.lineType]); mesg[0] = copyChar (temp); sprintf (temp, "Name %s", record.name); mesg[1] = copyChar (temp); sprintf (temp, "Phone Number%s", record.phoneNumber); mesg[2] = copyChar (temp); sprintf (temp, "Comment %s", record.desc); mesg[3] = copyChar (temp); /* Pop the information up on the screen. */ popupLabel (screen, mesg, 4); /* Clean up. */ freeChar (mesg[0]); freeChar (mesg[1]); freeChar (mesg[2]); freeChar (mesg[3]); } else { mesg[0] = "Error Unknown Phone Line Type"; mesg[1] = "Can not display information."; popupLabel (screen, mesg, 2); } } /* * This function displays a little pop up window discussing this demo. */ void aboutCdkRolodex (CDKSCREEN *screen) { char *mesg[15]; mesg[0] = "About Cdk Rolodex"; mesg[1] = " "; mesg[2] = "This demo was written to demonstrate the widgets"; mesg[3] = "available with the Cdk library. Not all of the"; mesg[4] = "Cdk widgets are used, but most of them have been."; mesg[5] = "I hope this little demonstration helps give you an"; mesg[6] = "understanding of what the Cdk library offers."; mesg[7] = " "; mesg[8] = "Have fun with it."; mesg[9] = " "; mesg[10] = "ttfn,"; mesg[11] = "Mike"; mesg[12] = "<#HL(35)>"; mesg[13] = "March 1996"; popupLabel (screen, mesg, 14); } /* * This deletes a rolodex group. */ int deleteRolodexGroup (CDKSCREEN *screen, SRolodex *groupList, int groupCount) { /* Declare local variables. */ char *mesg[10], *buttons[5], temp[256]; int selection, choice, x; /* If there are no groups, pop up a message telling them. */ if (groupCount == 0) { mesg[0] = "Error"; mesg[1] = "There as no groups defined."; popupLabel (screen, mesg, 2); /* Return the current group count. */ return groupCount; } /* Get the number of the group to delete. */ selection = pickRolodexGroup (screen, "Delete Which Rolodex Group?", groupList, groupCount); /* Check the results. */ if (selection < 0) { mesg[0] = " Delete Canceled "; mesg[1] = "No Group Deleted"; popupLabel (screen, mesg, 2); return groupCount; } /* Let's make sure they want to delete the group. */ mesg[0] = "Confirm Delete"; mesg[1] = "Are you sure you want to delete the group"; sprintf (temp, "%s?", groupList[selection].name); mesg[2] = copyChar (temp); buttons[0] = ""; buttons[1] = ""; choice = popupDialog (screen, mesg, 3, buttons, 2); freeChar (mesg[2]); /* Check the results of the confirmation. */ if (choice == 0) { mesg[0] = " Delete Canceled "; mesg[1] = "No Group Deleted"; popupLabel (screen, mesg, 2); return groupCount; } /* We need to delete the group file first. */ unlink (groupList[selection].dbm); /* OK, lets delete the group. */ freeChar (groupList[selection].name); freeChar (groupList[selection].desc); freeChar (groupList[selection].dbm); for (x=selection; x < groupCount-1; x++) { groupList[x].name = groupList[x+1].name; groupList[x].desc = groupList[x+1].desc; groupList[x].dbm = groupList[x+1].dbm; } groupCount--; GGroupModified = 1; /* Clean up. */ return groupCount; } /* * This function gets information about a new phone number. */ int addPhoneRecord (CDKSCREEN *screen, SPhoneData *phoneData) { /* Declare local variables. */ CDKLABEL *title; CDKITEMLIST *itemList; SPhoneRecord *phoneRecord; char *titleMesg[3], *types[GLINETYPECOUNT], temp[256]; int ret, x; /* Get the phone record pointer. */ phoneRecord = &phoneData->record[phoneData->recordCount]; /* Create a title label to display. */ titleMesg[0] = "Add New Phone Record"; title = newCDKLabel (screen, CENTER, TOP, titleMesg, 1, FALSE, FALSE); drawCDKLabel (title, FALSE); /* Create the phone line type list. */ for (x=0; x < GLINETYPECOUNT; x++) { sprintf (temp, "%s", GLineType[x]); types[x] = copyChar (temp); } /* Get the phone line type. */ itemList = newCDKItemlist (screen, CENTER, CENTER, "What Type Of Line Is It?", "Type: ", types, GLINETYPECOUNT, 0, TRUE, FALSE); phoneRecord->lineType = activateCDKItemlist (itemList, NULL); destroyCDKItemlist (itemList); /* Clean up. */ for (x=0; x < GLINETYPECOUNT; x++) { freeChar (types[x]); } /* Check the return code of the line type question. */ if (phoneRecord->lineType == -1) { phoneRecord->lineType = 0; return 1; } else if (phoneRecord->lineType == vPager || phoneRecord->lineType == vCell) { ret = getSmallPhoneRecord (screen, phoneRecord); } else { ret = getLargePhoneRecord (screen, phoneRecord); } /* Check the return value from the getXXXPhoneRecord function.*/ if (ret == 0) { phoneData->recordCount++; } /* Clean up. */ destroyCDKLabel (title); /* Return the new phone list count. */ return ret; } /* * This gets a phone record with all of the details. */ int getLargePhoneRecord (CDKSCREEN *screen, SPhoneRecord *phoneRecord) { /* Declare local variables. */ CDKENTRY *nameEntry, *addressEntry, *cityEntry; CDKENTRY *provEntry, *postalEntry, *descEntry; CDKTEMPLATE *phoneTemplate; char *buttons[5], *mesg[15]; int ret; /* Define the widgets. */ nameEntry = newCDKEntry (screen, LEFT, 5, NULL, "Name: ", A_NORMAL, '_', vMIXED, 20, 2, 256, TRUE, FALSE); addressEntry = newCDKEntry (screen, RIGHT, 5, NULL, "Address: ", A_NORMAL, '_', vMIXED, 40, 2, 256, TRUE, FALSE); cityEntry = newCDKEntry (screen, LEFT, 8, NULL, "City: ", A_NORMAL, '_', vMIXED, 20, 2, 256, TRUE, FALSE); provEntry = newCDKEntry (screen, 29, 8, NULL, "Province: ", A_NORMAL, '_', vMIXED, 15, 2, 256, TRUE, FALSE); postalEntry = newCDKEntry (screen, RIGHT, 8, NULL, "Postal Code: ", A_NORMAL, '_', vUMIXED, 8, 2, 256, TRUE, FALSE); phoneTemplate = newCDKTemplate (screen, LEFT, 11, NULL, "Number: ", "(###) ###-####", "(___) ___-____", TRUE, FALSE); descEntry = newCDKEntry (screen, RIGHT, 11, NULL, "Description: ", A_NORMAL, '_', vMIXED, 20, 2, 256, TRUE, FALSE); /* Get the phone information. */ for (;;) { /* Draw the widgets on the screen. */ drawCDKEntry (nameEntry, nameEntry->box); drawCDKEntry (addressEntry, addressEntry->box); drawCDKEntry (cityEntry, cityEntry->box); drawCDKEntry (provEntry, provEntry->box); drawCDKEntry (postalEntry, postalEntry->box); drawCDKTemplate (phoneTemplate, phoneTemplate->box); drawCDKEntry (descEntry, descEntry->box); /* Activate the entries to get the information. */ phoneRecord->name = copyChar (activateCDKEntry (nameEntry, NULL)); phoneRecord->address = copyChar (activateCDKEntry (addressEntry, NULL)); phoneRecord->city = copyChar (activateCDKEntry (cityEntry, NULL)); phoneRecord->province = copyChar (activateCDKEntry (provEntry, NULL)); phoneRecord->postalCode = copyChar (activateCDKEntry (postalEntry, NULL)); activateCDKTemplate (phoneTemplate, NULL); phoneRecord->phoneNumber = mixCDKTemplate (phoneTemplate); phoneRecord->desc = copyChar (activateCDKEntry (descEntry, NULL)); /* Determine if the user wants to submit the info. */ mesg[0] = "Confirm New Phone Entry"; mesg[1] = "Do you want to add this phone number?"; buttons[0] = ""; buttons[1] = ""; buttons[2] = ""; ret = popupDialog (screen, mesg, 2, buttons, 3); /* Check the response of the popup dialog box. */ if (ret == 0) { /* The user wants to submit the information. */ destroyCDKEntry (nameEntry); destroyCDKEntry (addressEntry); destroyCDKEntry (cityEntry); destroyCDKEntry (provEntry); destroyCDKEntry (postalEntry); destroyCDKEntry (descEntry); destroyCDKTemplate (phoneTemplate); return ret; } else if (ret == 1) { /* The user does not want to submit the information. */ freeChar (phoneRecord->name); freeChar (phoneRecord->address); freeChar (phoneRecord->city); freeChar (phoneRecord->province); freeChar (phoneRecord->postalCode); freeChar (phoneRecord->phoneNumber); freeChar (phoneRecord->desc); destroyCDKEntry (nameEntry); destroyCDKEntry (addressEntry); destroyCDKEntry (cityEntry); destroyCDKEntry (provEntry); destroyCDKEntry (postalEntry); destroyCDKEntry (descEntry); destroyCDKTemplate (phoneTemplate); return ret; } else { /* The user wants to edit the information again. */ freeChar (phoneRecord->name); freeChar (phoneRecord->address); freeChar (phoneRecord->city); freeChar (phoneRecord->province); freeChar (phoneRecord->postalCode); freeChar (phoneRecord->phoneNumber); freeChar (phoneRecord->desc); } } } /* * This gets a small phone record. */ int getSmallPhoneRecord (CDKSCREEN *screen, SPhoneRecord *phoneRecord) { /* Declare local variables. */ CDKENTRY *nameEntry, *descEntry; CDKTEMPLATE *phoneTemplate; char *buttons[5], *mesg[15]; int ret; /* Define the widgets. */ nameEntry = newCDKEntry (screen, CENTER, 8, NULL, "Name: ", A_NORMAL, '_', vMIXED, 20, 2, 256, TRUE, FALSE); phoneTemplate = newCDKTemplate (screen, CENTER, 11, NULL, "Number: ", "(###) ###-####", "(___) ___-____", TRUE, FALSE); descEntry = newCDKEntry (screen, CENTER, 14, NULL, "Description: ", A_NORMAL, '_', vMIXED, 20, 2, 256, TRUE, FALSE); /* Get the phone information. */ for (;;) { /* Draw the widgets on the screen. */ drawCDKEntry (nameEntry, nameEntry->box); drawCDKTemplate (phoneTemplate, phoneTemplate->box); drawCDKEntry (descEntry, descEntry->box); /* Activate the entries to get the information. */ phoneRecord->name = copyChar (activateCDKEntry (nameEntry, NULL)); activateCDKTemplate (phoneTemplate, NULL); phoneRecord->phoneNumber = mixCDKTemplate (phoneTemplate); phoneRecord->desc = copyChar (activateCDKEntry (descEntry, NULL)); phoneRecord->address = copyChar ("-"); phoneRecord->city = copyChar ("-"); phoneRecord->province = copyChar ("-"); phoneRecord->postalCode = copyChar ("-"); /* Determine if the user wants to submit the info. */ mesg[0] = "Confirm New Phone Entry"; mesg[1] = "Do you want to add this phone number?"; buttons[0] = ""; buttons[1] = ""; buttons[2] = ""; ret = popupDialog (screen, mesg, 2, buttons, 3); /* Check the response of the popup dialog box. */ if (ret == 0) { /* The user wants to submit the information. */ destroyCDKEntry (nameEntry); destroyCDKEntry (descEntry); destroyCDKTemplate (phoneTemplate); return ret; } else if (ret == 1) { /* The user does not want to submit the information. */ freeChar (phoneRecord->name); freeChar (phoneRecord->phoneNumber); freeChar (phoneRecord->desc); freeChar (phoneRecord->address); freeChar (phoneRecord->city); freeChar (phoneRecord->province); freeChar (phoneRecord->postalCode); destroyCDKEntry (nameEntry); destroyCDKEntry (descEntry); destroyCDKTemplate (phoneTemplate); return ret; } else { /* The user wants to edit the information again. */ freeChar (phoneRecord->name); freeChar (phoneRecord->phoneNumber); freeChar (phoneRecord->desc); freeChar (phoneRecord->address); freeChar (phoneRecord->city); freeChar (phoneRecord->province); freeChar (phoneRecord->postalCode); } } } /* * This prints a groups phone numbers. */ void printGroupNumbers (CDKSCREEN *screen, SRolodex *groupList, int groupCount) { /* Declare local variables. */ CDKSELECTION *selectionList; CDKENTRY *entry; CDKLABEL *title; char *itemList[MAX_ITEMS], *mesg[10], temp[256]; char *choices[] = {"Print to Printer ", "Print to File", "Don't Print"}; char *filename = (char *)NULL; char *printer = (char *)NULL; char *defaultPrinter = (char *)NULL; int height = groupCount; int x; /* Create the group list. */ for (x=0; x < groupCount; x++) { itemList[x] = copyChar (groupList[x].name); } /* Set the height of the selection list. */ if (groupCount > 5) { height = 5; } height += 3; /* Create the selection list. */ selectionList = newCDKSelection (screen, CENTER, CENTER, RIGHT, height, 40, "Select Which Groups To Print", itemList, groupCount, choices, 3, A_REVERSE, TRUE, FALSE); /* Activate the selection list. */ if (activateCDKSelection (selectionList, NULL) == -1) { /* Tell the user they exited early. */ destroyCDKSelection (selectionList); mesg[0] = "Print Canceled."; popupLabel (screen, mesg, 1); /* Clean up. */ for (x=0; x < groupCount; x++) { freeChar (itemList[x]); } return; } eraseCDKSelection (selectionList); /* Determine which groups we want to print. */ for (x=0; x < groupCount; x++) { if (selectionList->selections[x] == 0) { /* Create a title. */ sprintf (temp, "Printing Group [%s] to Printer", groupList[x].name); mesg[0] = copyChar (temp); title = newCDKLabel (screen, CENTER, TOP, mesg, 1, FALSE, FALSE); drawCDKLabel (title, FALSE); freeChar (mesg[0]); /* Get the printer name to print to. */ entry = newCDKEntry (screen, CENTER, 8, NULL, "Printer Name: ", A_NORMAL, '_', vMIXED, 20, 2, 256, TRUE, FALSE); /* Set the printer name to the default printer. */ defaultPrinter = getenv("PRINTER"); setCDKEntry (entry, defaultPrinter, 2, 256, TRUE); printer = copyChar (activateCDKEntry (entry, NULL)); destroyCDKEntry (entry); /* Print the group. */ if (printGroup (groupList[x], "/tmp/rolodex.tmp", printer) == 0) { /* The group could not be printed. */ sprintf (temp, "Sorry the group '%s' could not be printed.", groupList[x].name); mesg[0] = strdup (temp); popupLabel (screen, mesg, 1); freeChar (mesg[0]); } /* Clean up. */ destroyCDKLabel (title); freeChar (printer); unlink ("/tmp/rolodex.tmp"); } else if (selectionList->selections[x] == 1) { /* Create a title. */ sprintf (temp, "Printing Group [%s] to File", groupList[x].name); mesg[0] = copyChar (temp); title = newCDKLabel (screen, CENTER, TOP, mesg, 1, FALSE, FALSE); drawCDKLabel (title, FALSE); freeChar (mesg[0]); /* Get the filename to print to. */ entry = newCDKEntry (screen, CENTER, 8, NULL, "Filename: ", A_NORMAL, '_', vMIXED, 20, 2, 256, TRUE, FALSE); filename = copyChar (activateCDKEntry (entry, NULL)); destroyCDKEntry (entry); /* Print the group. */ if (printGroup (groupList[x], filename, printer) == 0) { /* The group could not be printed. */ sprintf (temp, "Sorry the group '%s' could not be printed.", groupList[x].name); mesg[0] = strdup (temp); popupLabel (screen, mesg, 1); freeChar (mesg[0]); } /* Clean up. */ destroyCDKLabel (title); freeChar (filename); } } /* Clean up. */ destroyCDKSelection (selectionList); for (x=0; x < groupCount; x++) { freeChar (itemList[x]); } } /* * This actually prints the phone record. */ int printGroup (SRolodex groupRecord, char *filename, char *printer) { /* Declare local variables. */ uid_t uid = getuid(); char tempFilename[256], command[256]; SPhoneData phoneData; SPhoneRecord *phoneRecord; int phoneCount, x; FILE *fd; /* Read the data file. */ phoneCount = readPhoneDataFile (groupRecord.dbm, &phoneData); /* Create the temporary filename. */ if (filename != (char *)NULL) { sprintf (tempFilename, "%s", filename); } else { sprintf (tempFilename, "/tmp/rolodex.%d", (int)uid); } /* Open the file. */ if ((fd = fopen (tempFilename, "a+")) == NULL) { /* Clean up. */ for (x=0; x < phoneCount; x++) { freeChar (phoneData.record[x].name); freeChar (phoneData.record[x].phoneNumber); freeChar (phoneData.record[x].address); freeChar (phoneData.record[x].city); freeChar (phoneData.record[x].province); freeChar (phoneData.record[x].postalCode); freeChar (phoneData.record[x].desc); } return 0; } /* Start writing the group information to the temp file. */ fprintf (fd, "Group Name: %40s\n", groupRecord.name); fprintf (fd, "==============================================================================\n"); for (x=0; x < phoneCount; x++) { phoneRecord = &phoneData.record[x]; fprintf (fd, "Name : %s\n", phoneRecord->name); fprintf (fd, "Phone Number: %s (%s)\n", phoneRecord->phoneNumber, GLineType[phoneRecord->lineType]); if (phoneRecord->lineType != vPager && phoneRecord->lineType != vCell) { fprintf (fd, "Address : %-20s, %-20s\n", phoneRecord->address, phoneRecord->city); fprintf (fd, " : %-10s, %-10s\n", phoneRecord->province, phoneRecord->postalCode); } fprintf (fd, "Description : %-30s\n", phoneRecord->desc); fprintf (fd, "------------------------------------------------------------------------------\n"); } /* Determine if the information is going to a file or printer. */ if (printer != (char *)NULL) { /* Print the file to the given printer. */ sprintf (command, "lpr -P%s %s", printer, tempFilename); system (command); /* We have to unlkink the temp file. */ unlink (tempFilename); } /* Clean up some memory. */ for (x=0; x < phoneCount; x++) { freeChar (phoneData.record[x].name); freeChar (phoneData.record[x].phoneNumber); freeChar (phoneData.record[x].address); freeChar (phoneData.record[x].city); freeChar (phoneData.record[x].province); freeChar (phoneData.record[x].postalCode); freeChar (phoneData.record[x].desc); } /* Close the filename. */ fclose (fd); return 1; } /* **************************************************************** * Start of callback functions. **************************************************************** */ int entryPreProcessCB (EObjectType cdkType, void *object, void *clientData, chtype input) { if (input == ' ') { Beep(); return 0; } return 1; } /* * This allows the user to insert a new phone entry into the database. */ int insertPhoneEntryCB (EObjectType cdkType, void *object, void *clientData, chtype key) { /* Declare local variables. */ CDKSCROLL *scroll= (CDKSCROLL *)object; SPhoneData *phoneData= (SPhoneData *)clientData; SPhoneRecord *phoneRecord= &phoneData->record[phoneData->recordCount]; char temp[256]; /* Make the scrolling list disappear. */ eraseCDKScroll (scroll); /* Call the function which gets phone record information. */ if (addPhoneRecord (scroll->screen, phoneData) == 0) { sprintf (temp, "%s (%s)", phoneRecord->name, GLineType[phoneRecord->lineType]); addCDKScrollItem (scroll, temp); } /* Redraw the scrolling list. */ drawCDKScroll (scroll, scroll->box); return 0; } /* * This allows the user to delete a phone entry from the database. */ int deletePhoneEntryCB (EObjectType cdkType, void *object, void *clientData, chtype key) { /* Declare local variables. */ CDKSCROLL *scroll = (CDKSCROLL *)object; SPhoneData *phoneData = (SPhoneData *)clientData; char *mesg[3], temp[256], *hold; char *buttons[] = {"", ""}; int position = scroll->currentItem; int x; /* Make the scrolling list disappear. */ eraseCDKScroll (scroll); /* Check the number of entries left in the list. */ if (scroll->listSize == 0) { mesg[0] = "There are no more numbers to delete."; popupLabel (scroll->screen, mesg, 1); return 0; } /* Ask the user if they really want to delete the listing. */ mesg[0] = "Do you really want to delete the phone entry"; hold = chtype2Char (scroll->item[scroll->currentItem]); sprintf (temp, "%s", hold); freeChar (hold); mesg[1] = copyChar (temp); if (popupDialog (scroll->screen, mesg, 2, buttons, 2) == 1) { /* Remove the item from the phone data record. */ for (x=position; x < phoneData->recordCount-1; x++) { phoneData->record[x].name = phoneData->record[x+1].name; phoneData->record[x].lineType = phoneData->record[x+1].lineType; phoneData->record[x].phoneNumber = phoneData->record[x+1].phoneNumber; phoneData->record[x].address = phoneData->record[x+1].address; phoneData->record[x].city = phoneData->record[x+1].city; phoneData->record[x].province = phoneData->record[x+1].province; phoneData->record[x].postalCode = phoneData->record[x+1].postalCode; phoneData->record[x].desc = phoneData->record[x+1].desc; } phoneData->recordCount--; /* Nuke the entry. */ deleteCDKScrollItem (scroll, position); } freeChar (mesg[1]); /* Redraw the scrolling list. */ drawCDKScroll (scroll, scroll->box); return 0; } /* * This function provices help for the phone list editor. */ int phoneEntryHelpCB (EObjectType cdkType, void *object, void *clientData, chtype key) { /* Declare local variables. */ CDKSCROLL *scroll = (CDKSCROLL *)object; char *mesg[10], temp[100]; /* Create the help title. */ sprintf (temp, "Rolodex Phone Editor"); mesg[0] = copyChar (temp); sprintf (temp, " Inserts a new phone entry."); mesg[1] = copyChar (temp); sprintf (temp, " Deletes the currently selected phone entry."); mesg[2] = copyChar (temp); sprintf (temp, " Exits the scrolling list."); mesg[3] = copyChar (temp); sprintf (temp, " Pops up this help window."); mesg[4] = copyChar (temp); /* Pop up the message. */ popupLabel (scroll->screen, mesg, 5); /* Clean up. */ freeChar (mesg[0]); freeChar (mesg[1]); freeChar (mesg[2]); freeChar (mesg[3]); freeChar (mesg[4]); return 0; } /* * This is a callback to the menu widget. It allows the user to * ask for help about any sub-menu item. */ int helpCB (EObjectType cdkType, void *object, void *clientData, chtype key) { /* Declare local variables. */ CDKMENU *menu= (CDKMENU *)object; int menuList= menu->currentTitle; int submenuList= menu->currentSubtitle; int selection= ((menuList * 100) + submenuList); char *mesg[20], *name, temp[100]; /* Create the help title. */ name = chtype2Char (menu->sublist[menuList][submenuList]); stripWhiteSpace (vBOTH, name); sprintf (temp, "Help %s", name); mesg[0] = copyChar (temp); freeChar (name); /* Set the default value for the message. */ mesg[1] = "No help defined for this menu."; /* Given the current menu item, create a message. */ if (selection == 0) { mesg[1] = "This reads a new rolodex RC file."; } else if (selection == 1) { mesg[1] = "This saves the current group information in the default RC file."; } else if (selection == 2) { mesg[1] = "This saves the current group information in a new RC file."; } else if (selection == 3) { mesg[1] = "This exits this program."; } else if (selection == 100) { mesg[1] = "This creates a new rolodex group."; } else if (selection == 101) { mesg[1] = "This opens a rolodex group."; } else if (selection == 102) { mesg[1] = "This deletes a rolodex group."; } else if (selection == 200) { mesg[1] = "This prints out selected groups phone numbers."; } else if (selection == 300) { mesg[1] = "This gives a little history on this program."; } else if (selection == 301) { mesg[1] = "This provides information about the rolodex."; } /* Pop up the message. */ popupLabel (menu->screen, mesg, 2); freeChar (mesg[0]); /* Redraw the submenu window. */ drawCDKMenuSubwin (menu); return 0; } /* * This is a callback to the group list scrolling list. */ int groupInfoCB (EObjectType cdkType, void *object, void *clientData, chtype key) { /* Declare local variables. */ CDKSCROLL *scroll= (CDKSCROLL *)object; SRolodex *groupList= (SRolodex *)clientData; int selection= scroll->currentItem; char *mesg[5], temp[100]; /* Create the message to be displayed. */ mesg[0] = "Detailed Group Information."; sprintf (temp, "Group Name %s", groupList[selection].name); mesg[1] = copyChar (temp); sprintf (temp, "Group Description %s", groupList[selection].desc); mesg[2] = copyChar (temp); sprintf (temp, "Group Database File %s", groupList[selection].dbm); mesg[3] = copyChar (temp); /* Displaye the message. */ popupLabel (scroll->screen, mesg, 4); freeChar (mesg[1]); freeChar (mesg[2]); freeChar (mesg[3]); /* Redraw the scrolling list. */ drawCDKScroll (scroll, scroll->box); return 0; }