1c9e2be55Smrg/* $XConsortium: toc.c,v 2.59 95/01/09 16:52:53 swick Exp $ 2c9e2be55Smrg * $XFree86: xc/programs/xmh/toc.c,v 3.4 2001/10/28 03:34:39 tsi Exp $ 3c9e2be55Smrg * 4c9e2be55Smrg * 5c9e2be55Smrg * COPYRIGHT 1987 6c9e2be55Smrg * DIGITAL EQUIPMENT CORPORATION 7c9e2be55Smrg * MAYNARD, MASSACHUSETTS 8c9e2be55Smrg * ALL RIGHTS RESERVED. 9c9e2be55Smrg * 10c9e2be55Smrg * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND 11c9e2be55Smrg * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. 12c9e2be55Smrg * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR 13c9e2be55Smrg * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. 14c9e2be55Smrg * 15c9e2be55Smrg * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT 16c9e2be55Smrg * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN 17c9e2be55Smrg * ADDITION TO THAT SET FORTH ABOVE. 18c9e2be55Smrg * 19c9e2be55Smrg * Permission to use, copy, modify, and distribute this software and its 20c9e2be55Smrg * documentation for any purpose and without fee is hereby granted, provided 21c9e2be55Smrg * that the above copyright notice appear in all copies and that both that 22c9e2be55Smrg * copyright notice and this permission notice appear in supporting 23c9e2be55Smrg * documentation, and that the name of Digital Equipment Corporation not be 24c9e2be55Smrg * used in advertising or publicity pertaining to distribution of the software 25c9e2be55Smrg * without specific, written prior permission. 26c9e2be55Smrg */ 27c9e2be55Smrg 28c9e2be55Smrg/* toc.c -- handle things in the toc widget. */ 29c9e2be55Smrg 30c9e2be55Smrg#include "xmh.h" 31c9e2be55Smrg#include "tocintrnl.h" 32c9e2be55Smrg#include "toc.h" 33c9e2be55Smrg#include "tocutil.h" 34c9e2be55Smrg#include "actions.h" 35c9e2be55Smrg 36c9e2be55Smrg#include <sys/stat.h> 37c9e2be55Smrg 3866d665a3Smrg#ifndef S_ISDIR 3966d665a3Smrg#define S_ISDIR(mode) ((mode & S_IFMT) == S_IFDIR) 4066d665a3Smrg#endif 4166d665a3Smrg 42c9e2be55Smrgstatic int IsDir(char *name) 43c9e2be55Smrg{ 44c9e2be55Smrg char str[500]; 45c9e2be55Smrg struct stat buf; 46c9e2be55Smrg if (*name == '.') 47c9e2be55Smrg return FALSE; 4866d665a3Smrg if (snprintf(str, sizeof(str), "%s/%s", app_resources.mail_path, name) 4966d665a3Smrg >= sizeof(str)) return False; 50c9e2be55Smrg if (stat(str, &buf) /* failed */) return False; 51c9e2be55Smrg return S_ISDIR(buf.st_mode); 52c9e2be55Smrg} 53c9e2be55Smrg 54c9e2be55Smrg 55c9e2be55Smrgstatic void MakeSureFolderExists( 56c9e2be55Smrg char ***namelistptr, 57c9e2be55Smrg int *numfoldersptr, 58c9e2be55Smrg char *name) 59c9e2be55Smrg{ 60c9e2be55Smrg int i; 61c9e2be55Smrg char str[200]; 62c9e2be55Smrg for (i=0 ; i<*numfoldersptr ; i++) 63c9e2be55Smrg if (strcmp((*namelistptr)[i], name) == 0) return; 6466d665a3Smrg if (snprintf(str, sizeof(str), "%s/%s", app_resources.mail_path, name) 6566d665a3Smrg >= sizeof(str)) goto punt; 66c9e2be55Smrg (void) mkdir(str, 0700); 67c9e2be55Smrg *numfoldersptr = ScanDir(app_resources.mail_path, namelistptr, IsDir); 68c9e2be55Smrg for (i=0 ; i<*numfoldersptr ; i++) 69c9e2be55Smrg if (strcmp((*namelistptr)[i], name) == 0) return; 7066d665a3Smrg punt: 71c9e2be55Smrg Punt("Can't create new mail folder!"); 72c9e2be55Smrg} 73c9e2be55Smrg 74c9e2be55Smrg 75c9e2be55Smrgstatic void MakeSureSubfolderExists( 76c9e2be55Smrg char *** namelistptr, 77c9e2be55Smrg int * numfoldersptr, 78c9e2be55Smrg char * name) 79c9e2be55Smrg{ 80c9e2be55Smrg char folder[300]; 81c9e2be55Smrg char subfolder_path[300]; 82c9e2be55Smrg char *subfolder; 83c9e2be55Smrg struct stat buf; 84c9e2be55Smrg 85c9e2be55Smrg /* Make sure that the parent folder exists */ 86c9e2be55Smrg 87c9e2be55Smrg subfolder = strchr( strcpy(folder, name), '/'); 88c9e2be55Smrg *subfolder = '\0'; 89c9e2be55Smrg subfolder++; 90c9e2be55Smrg MakeSureFolderExists(namelistptr, numfoldersptr, folder); 91d859ff80Smrg 92c9e2be55Smrg /* The parent folder exists. Make sure the subfolder exists. */ 93c9e2be55Smrg 9466d665a3Smrg if (snprintf(subfolder_path, sizeof(subfolder_path), "%s/%s", 9566d665a3Smrg app_resources.mail_path, name) >= sizeof(subfolder_path)) 9666d665a3Smrg goto punt; 97c9e2be55Smrg if (stat(subfolder_path, &buf) /* failed */) { 98c9e2be55Smrg (void) mkdir(subfolder_path, 0700); 99c9e2be55Smrg if (stat(subfolder_path, &buf) /* failed */) 100c9e2be55Smrg Punt("Can't create new xmh subfolder!"); 101c9e2be55Smrg } 102c9e2be55Smrg if (!S_ISDIR(buf.st_mode)) 10366d665a3Smrg punt: 104c9e2be55Smrg Punt("Can't create new xmh subfolder!"); 105c9e2be55Smrg} 106c9e2be55Smrg 107c9e2be55Smrgint TocFolderExists(Toc toc) 108c9e2be55Smrg{ 109c9e2be55Smrg struct stat buf; 110c9e2be55Smrg if (! toc->path) { 11166d665a3Smrg XtAsprintf(&toc->path, "%s/%s", 11266d665a3Smrg app_resources.mail_path, toc->foldername); 113c9e2be55Smrg } 114c9e2be55Smrg return ((stat(toc->path, &buf) == 0) && 115c9e2be55Smrg (S_ISDIR(buf.st_mode))); 116c9e2be55Smrg} 117c9e2be55Smrg 118c9e2be55Smrgstatic void LoadCheckFiles(void) 119c9e2be55Smrg{ 120c9e2be55Smrg FILE *fid; 121c9e2be55Smrg char str[1024]; 122c9e2be55Smrg 12366d665a3Smrg snprintf(str, sizeof(str), "%s/.xmhcheck", homeDir); 124c9e2be55Smrg fid = myfopen(str, "r"); 125c9e2be55Smrg if (fid) { 126c9e2be55Smrg int i; 127c9e2be55Smrg char *ptr, *ptr2; 128c9e2be55Smrg 129c9e2be55Smrg while ((ptr = ReadLine(fid))) { 130c9e2be55Smrg while (*ptr == ' ' || *ptr == '\t') ptr++; 131c9e2be55Smrg ptr2 = ptr; 132c9e2be55Smrg while (*ptr2 && *ptr2 != ' ' && *ptr2 != '\t') ptr2++; 133c9e2be55Smrg if (*ptr2 == 0) continue; 134c9e2be55Smrg *ptr2++ = 0; 135c9e2be55Smrg while (*ptr2 == ' ' || *ptr2 == '\t') ptr2++; 136c9e2be55Smrg if (*ptr2 == 0) continue; 137c9e2be55Smrg for (i=0 ; i<numFolders ; i++) { 138c9e2be55Smrg if (strcmp(ptr, folderList[i]->foldername) == 0) { 139c9e2be55Smrg folderList[i]->incfile = XtNewString(ptr2); 140c9e2be55Smrg break; 141c9e2be55Smrg } 142c9e2be55Smrg } 143c9e2be55Smrg } 144c9e2be55Smrg myfclose(fid); 145c9e2be55Smrg } else if ( app_resources.initial_inc_file && 146c9e2be55Smrg *app_resources.initial_inc_file) 147c9e2be55Smrg InitialFolder->incfile = app_resources.initial_inc_file; 148c9e2be55Smrg} 149d859ff80Smrg 150c9e2be55Smrg 151c9e2be55Smrg/* PUBLIC ROUTINES */ 152c9e2be55Smrg 153c9e2be55Smrg 154c9e2be55Smrg/* Read in the list of folders. */ 155c9e2be55Smrg 156c9e2be55Smrgvoid TocInit(void) 157c9e2be55Smrg{ 158c9e2be55Smrg Toc toc; 159c9e2be55Smrg char **namelist; 160c9e2be55Smrg int i; 161c9e2be55Smrg numFolders = ScanDir(app_resources.mail_path, &namelist, IsDir); 162c9e2be55Smrg if (numFolders < 0) { 163c9e2be55Smrg (void) mkdir(app_resources.mail_path, 0700); 164c9e2be55Smrg numFolders = ScanDir(app_resources.mail_path, &namelist, IsDir); 165c9e2be55Smrg if (numFolders < 0) 166c9e2be55Smrg Punt("Can't create or read mail directory!"); 167c9e2be55Smrg } 168c9e2be55Smrg if (IsSubfolder(app_resources.initial_folder_name)) 169c9e2be55Smrg MakeSureSubfolderExists(&namelist, &numFolders, 170c9e2be55Smrg app_resources.initial_folder_name); 171c9e2be55Smrg else 172c9e2be55Smrg MakeSureFolderExists(&namelist, &numFolders, 173c9e2be55Smrg app_resources.initial_folder_name); 174c9e2be55Smrg 175c9e2be55Smrg if (IsSubfolder(app_resources.drafts_folder_name)) 176c9e2be55Smrg MakeSureSubfolderExists(&namelist, &numFolders, 177c9e2be55Smrg app_resources.drafts_folder_name); 178c9e2be55Smrg else 179c9e2be55Smrg MakeSureFolderExists(&namelist, &numFolders, 180c9e2be55Smrg app_resources.drafts_folder_name); 18166d665a3Smrg folderList = XtMallocArray((Cardinal)numFolders, sizeof(Toc)); 182c9e2be55Smrg for (i=0 ; i<numFolders ; i++) { 183c9e2be55Smrg toc = folderList[i] = TUMalloc(); 184c9e2be55Smrg toc->foldername = XtNewString(namelist[i]); 185c9e2be55Smrg free((char *)namelist[i]); 186c9e2be55Smrg } 187c9e2be55Smrg if (! (InitialFolder = TocGetNamed(app_resources.initial_folder_name))) 188c9e2be55Smrg InitialFolder = TocCreate(app_resources.initial_folder_name); 189c9e2be55Smrg 190c9e2be55Smrg if (! (DraftsFolder = TocGetNamed(app_resources.drafts_folder_name))) 191c9e2be55Smrg DraftsFolder = TocCreate(app_resources.drafts_folder_name); 192c9e2be55Smrg free((char *)namelist); 193c9e2be55Smrg LoadCheckFiles(); 194c9e2be55Smrg} 195c9e2be55Smrg 196c9e2be55Smrg 197c9e2be55Smrg 198c9e2be55Smrg/* Create a toc and add a folder to the folderList. */ 199c9e2be55Smrg 20066d665a3SmrgToc TocCreate(const char *foldername) 201c9e2be55Smrg{ 202c9e2be55Smrg Toc toc = TUMalloc(); 203c9e2be55Smrg 204c9e2be55Smrg toc->foldername = XtNewString(foldername); 20566d665a3Smrg folderList = XtReallocArray(folderList, ++numFolders, sizeof(Toc)); 206c9e2be55Smrg folderList[numFolders - 1] = toc; 207c9e2be55Smrg return toc; 208c9e2be55Smrg} 209c9e2be55Smrg 210c9e2be55Smrg 211c9e2be55Smrg/* Create a new folder with the given name. */ 212c9e2be55Smrg 21366d665a3SmrgToc TocCreateFolder(const char *foldername) 214c9e2be55Smrg{ 215c9e2be55Smrg Toc toc; 216c9e2be55Smrg char str[500]; 217c9e2be55Smrg if (TocGetNamed(foldername)) return NULL; 21866d665a3Smrg if (snprintf(str, sizeof(str), "%s/%s", app_resources.mail_path, foldername) 21966d665a3Smrg >= sizeof(str)) return NULL; 220c9e2be55Smrg if (mkdir(str, 0700) < 0) return NULL; 221c9e2be55Smrg toc = TocCreate(foldername); 222c9e2be55Smrg return toc; 223c9e2be55Smrg} 224c9e2be55Smrg 225c9e2be55Smrgint TocHasMail(Toc toc) 226c9e2be55Smrg{ 227c9e2be55Smrg return toc->mailpending; 228c9e2be55Smrg} 229c9e2be55Smrg 230c9e2be55Smrgstatic int CheckForNewMail(Toc toc) 231c9e2be55Smrg{ 232c9e2be55Smrg if (toc->incfile) 233c9e2be55Smrg return (GetFileLength(toc->incfile) > 0); 234c9e2be55Smrg else if (toc == InitialFolder) { 235c9e2be55Smrg char **argv; 236c9e2be55Smrg char *result; 237c9e2be55Smrg int hasmail; 238c9e2be55Smrg 239c9e2be55Smrg argv = MakeArgv(4); 240c9e2be55Smrg argv[0] = "msgchk"; 241c9e2be55Smrg argv[1] = "-nonotify"; 242c9e2be55Smrg argv[2] = "nomail"; 243c9e2be55Smrg argv[3] = "-nodate"; 244c9e2be55Smrg result = DoCommandToString(argv); 245c9e2be55Smrg hasmail = (*result != '\0'); 246c9e2be55Smrg XtFree(result); 247c9e2be55Smrg XtFree((char*)argv); 248c9e2be55Smrg return hasmail; 249c9e2be55Smrg } 250c9e2be55Smrg return False; 251c9e2be55Smrg} 252c9e2be55Smrg 253c9e2be55Smrg/*ARGSUSED*/ 254c9e2be55Smrgvoid TocCheckForNewMail( 255c9e2be55Smrg Boolean update) /* if True, actually make the check */ 256c9e2be55Smrg{ 257c9e2be55Smrg Toc toc; 258c9e2be55Smrg Scrn scrn; 259c9e2be55Smrg int i, j, hasmail; 260c9e2be55Smrg Boolean mail_waiting = False; 261c9e2be55Smrg 262c9e2be55Smrg if (update) { 263c9e2be55Smrg for (i=0 ; i<numFolders ; i++) { 264c9e2be55Smrg toc = folderList[i]; 265c9e2be55Smrg if (TocCanIncorporate(toc)) { 266c9e2be55Smrg toc->mailpending = hasmail = CheckForNewMail(toc); 267c9e2be55Smrg if (hasmail) mail_waiting = True; 268c9e2be55Smrg for (j=0 ; j<numScrns ; j++) { 269c9e2be55Smrg scrn = scrnList[j]; 270c9e2be55Smrg if (scrn->kind == STtocAndView) 271c9e2be55Smrg /* give visual indication of new mail waiting */ 272c9e2be55Smrg BBoxMailFlag(scrn->folderbuttons, TocName(toc), 273c9e2be55Smrg hasmail); 274c9e2be55Smrg } 275c9e2be55Smrg } 276c9e2be55Smrg } 277c9e2be55Smrg } else { 278c9e2be55Smrg for (i=0; i < numFolders; i++) { 279c9e2be55Smrg toc = folderList[i]; 280c9e2be55Smrg if (toc->mailpending) { 281c9e2be55Smrg mail_waiting = True; 282c9e2be55Smrg break; 283c9e2be55Smrg } 284c9e2be55Smrg } 285c9e2be55Smrg } 286c9e2be55Smrg 287c9e2be55Smrg if (app_resources.mail_waiting_flag) { 288c9e2be55Smrg Arg args[1]; 289c9e2be55Smrg static Boolean icon_state = -1; 290c9e2be55Smrg 291c9e2be55Smrg if (icon_state != mail_waiting) { 292c9e2be55Smrg icon_state = mail_waiting; 293c9e2be55Smrg for (i=0; i < numScrns; i++) { 294c9e2be55Smrg scrn = scrnList[i]; 295c9e2be55Smrg if (scrn->kind == STtocAndView) { 296c9e2be55Smrg XtSetArg(args[0], XtNiconPixmap, 297c9e2be55Smrg (mail_waiting ? app_resources.new_mail_icon 298c9e2be55Smrg : app_resources.no_mail_icon)); 299c9e2be55Smrg XtSetValues(scrn->parent, args, (Cardinal)1); 300c9e2be55Smrg } 301c9e2be55Smrg } 302c9e2be55Smrg } 303c9e2be55Smrg } 304c9e2be55Smrg} 305c9e2be55Smrg 306c9e2be55Smrg/* Intended to support mutual exclusion on deleting folders, so that you 307c9e2be55Smrg * cannot have two confirm popups at the same time on the same folder. 308c9e2be55Smrg * 309c9e2be55Smrg * You can have confirm popups on different folders simultaneously. 310c9e2be55Smrg * However, I did not protect the user from popping up a delete confirm 311c9e2be55Smrg * popup on folder A, then popping up a delete confirm popup on folder 312d859ff80Smrg * A/subA, then deleting A, then deleting A/subA -- which of course is 313c9e2be55Smrg * already gone, and will cause xmh to Punt. 314c9e2be55Smrg * 315c9e2be55Smrg * TocClearDeletePending is a callback from the No confirmation button 316c9e2be55Smrg * of the confirm popup. 317c9e2be55Smrg */ 318c9e2be55Smrg 319c9e2be55SmrgBoolean TocTestAndSetDeletePending(Toc toc) 320c9e2be55Smrg{ 321c9e2be55Smrg Boolean flag; 322c9e2be55Smrg 323c9e2be55Smrg flag = toc->delete_pending; 324c9e2be55Smrg toc->delete_pending = True; 325c9e2be55Smrg return flag; 326c9e2be55Smrg} 327c9e2be55Smrg 328c9e2be55Smrgvoid TocClearDeletePending(Toc toc) 329c9e2be55Smrg{ 330c9e2be55Smrg toc->delete_pending = False; 331c9e2be55Smrg} 332c9e2be55Smrg 333c9e2be55Smrg 334c9e2be55Smrg/* Recursively delete an entire directory. Nasty. */ 335c9e2be55Smrg 336c9e2be55Smrgstatic void NukeDirectory(char *path) 337c9e2be55Smrg{ 338c9e2be55Smrg struct stat buf; 339c9e2be55Smrg 340c9e2be55Smrg#ifdef S_IFLNK 341c9e2be55Smrg /* POSIX.1 does not discuss symbolic links. */ 342c9e2be55Smrg if (lstat(path, &buf) /* failed */) 343c9e2be55Smrg return; 344c9e2be55Smrg if ((buf.st_mode & S_IFMT) == S_IFLNK) { 345c9e2be55Smrg (void) unlink(path); 346c9e2be55Smrg return; 347c9e2be55Smrg } 348c9e2be55Smrg#endif 349c9e2be55Smrg if (stat(path, &buf) /* failed */) 350c9e2be55Smrg return; 351c9e2be55Smrg if (buf.st_mode & S_IWRITE) { 352c9e2be55Smrg char **argv = MakeArgv(3); 353c9e2be55Smrg argv[0] = "/bin/rm"; 354c9e2be55Smrg argv[1] = "-rf"; 355c9e2be55Smrg argv[2] = path; 356c9e2be55Smrg (void) DoCommand(argv, (char*)NULL, (char*)NULL); 357c9e2be55Smrg XtFree((char*)argv); 358d859ff80Smrg } 359c9e2be55Smrg} 360c9e2be55Smrg 361c9e2be55Smrg 362c9e2be55Smrg/* Destroy the given folder. */ 363c9e2be55Smrg 364c9e2be55Smrgvoid TocDeleteFolder(Toc toc) 365c9e2be55Smrg{ 366c9e2be55Smrg Toc toc2; 367c9e2be55Smrg int i, j, w; 368c9e2be55Smrg if (toc == NULL) return; 369c9e2be55Smrg TUGetFullFolderInfo(toc); 370c9e2be55Smrg 371c9e2be55Smrg w = -1; 372c9e2be55Smrg for (i=0 ; i<numFolders ; i++) { 373c9e2be55Smrg toc2 = folderList[i]; 374c9e2be55Smrg if (toc2 == toc) 375c9e2be55Smrg w = i; 376c9e2be55Smrg else if (toc2->validity == valid) 377c9e2be55Smrg for (j=0 ; j<toc2->nummsgs ; j++) 378c9e2be55Smrg if (toc2->msgs[j]->desttoc == toc) 379c9e2be55Smrg MsgSetFate(toc2->msgs[j], Fignore, (Toc) NULL); 380c9e2be55Smrg } 381c9e2be55Smrg if (w < 0) Punt("Couldn't find it in TocDeleteFolder!"); 382c9e2be55Smrg NukeDirectory(toc->path); 383c9e2be55Smrg if (toc->validity == valid) { 384c9e2be55Smrg for (i=0 ; i<toc->nummsgs ; i++) { 385c9e2be55Smrg MsgSetScrnForce(toc->msgs[i], (Scrn) NULL); 386c9e2be55Smrg MsgFree(toc->msgs[i]); 387c9e2be55Smrg } 388c9e2be55Smrg XtFree((char *) toc->msgs); 389c9e2be55Smrg } 390c9e2be55Smrg XtFree((char *)toc); 391c9e2be55Smrg numFolders--; 392c9e2be55Smrg for (i=w ; i<numFolders ; i++) folderList[i] = folderList[i+1]; 393c9e2be55Smrg} 394c9e2be55Smrg 395c9e2be55Smrg 396c9e2be55Smrg/* 397c9e2be55Smrg * Display the given toc in the given scrn. If scrn is NULL, then remove the 398c9e2be55Smrg * toc from all scrns displaying it. 399c9e2be55Smrg */ 400c9e2be55Smrg 401c9e2be55Smrgvoid TocSetScrn(Toc toc, Scrn scrn) 402c9e2be55Smrg{ 403c9e2be55Smrg Cardinal i; 404c9e2be55Smrg 405c9e2be55Smrg if (toc == NULL && scrn == NULL) return; 406c9e2be55Smrg if (scrn == NULL) { 407c9e2be55Smrg for (i=0 ; i<toc->num_scrns ; i++) 408c9e2be55Smrg TocSetScrn((Toc) NULL, toc->scrn[i]); 409c9e2be55Smrg return; 410c9e2be55Smrg } 411c9e2be55Smrg if (scrn->toc == toc) return; 412c9e2be55Smrg if (scrn->toc != NULL) { 413c9e2be55Smrg for (i=0 ; i<scrn->toc->num_scrns ; i++) 414c9e2be55Smrg if (scrn->toc->scrn[i] == scrn) break; 415c9e2be55Smrg if (i >= scrn->toc->num_scrns) 416c9e2be55Smrg Punt("Couldn't find scrn in TocSetScrn!"); 417c9e2be55Smrg scrn->toc->scrn[i] = scrn->toc->scrn[--scrn->toc->num_scrns]; 418c9e2be55Smrg } 419c9e2be55Smrg scrn->toc = toc; 420c9e2be55Smrg if (toc == NULL) { 421c9e2be55Smrg TUResetTocLabel(scrn); 422c9e2be55Smrg TURedisplayToc(scrn); 423c9e2be55Smrg StoreWindowName(scrn, progName); 424c9e2be55Smrg } else { 425c9e2be55Smrg toc->num_scrns++; 42666d665a3Smrg toc->scrn = XtReallocArray(toc->scrn, toc->num_scrns, sizeof(Scrn)); 427c9e2be55Smrg toc->scrn[toc->num_scrns - 1] = scrn; 428c9e2be55Smrg TUEnsureScanIsValidAndOpen(toc, True); 429c9e2be55Smrg TUResetTocLabel(scrn); 430c9e2be55Smrg if (app_resources.prefix_wm_and_icon_name) { 431c9e2be55Smrg char wm_name[64]; 43266d665a3Smrg snprintf(wm_name, sizeof(wm_name), "%s: %s", 43366d665a3Smrg progName, toc->foldername); 434c9e2be55Smrg StoreWindowName(scrn, wm_name); 435c9e2be55Smrg } 436c9e2be55Smrg else 437c9e2be55Smrg StoreWindowName(scrn, toc->foldername); 438c9e2be55Smrg TURedisplayToc(scrn); 439c9e2be55Smrg SetCurrentFolderName(scrn, toc->foldername); 440c9e2be55Smrg } 441c9e2be55Smrg EnableProperButtons(scrn); 442c9e2be55Smrg} 443c9e2be55Smrg 444c9e2be55Smrg 445c9e2be55Smrg 446c9e2be55Smrg/* Remove the given message from the toc. Doesn't actually touch the file. 447c9e2be55Smrg Also note that it does not free the storage for the msg. */ 448c9e2be55Smrg 449c9e2be55Smrgvoid TocRemoveMsg(Toc toc, Msg msg) 450c9e2be55Smrg{ 451c9e2be55Smrg Msg newcurmsg; 452c9e2be55Smrg MsgList mlist; 453c9e2be55Smrg int i; 454c9e2be55Smrg if (toc->validity == unknown) 455c9e2be55Smrg TUGetFullFolderInfo(toc); 456c9e2be55Smrg if (toc->validity != valid) 457c9e2be55Smrg return; 458c9e2be55Smrg newcurmsg = TocMsgAfter(toc, msg); 459c9e2be55Smrg if (newcurmsg) newcurmsg->changed = TRUE; 460c9e2be55Smrg newcurmsg = toc->curmsg; 461c9e2be55Smrg if (msg == toc->curmsg) { 462c9e2be55Smrg newcurmsg = TocMsgAfter(toc, msg); 463c9e2be55Smrg if (newcurmsg == NULL) newcurmsg = TocMsgBefore(toc, msg); 464c9e2be55Smrg toc->curmsg = NULL; 465c9e2be55Smrg } 466c9e2be55Smrg toc->length -= msg->length; 467c9e2be55Smrg if (msg->visible) toc->lastPos -= msg->length; 468c9e2be55Smrg for(i = TUGetMsgPosition(toc, msg), toc->nummsgs--; i<toc->nummsgs ; i++) { 469c9e2be55Smrg toc->msgs[i] = toc->msgs[i+1]; 470c9e2be55Smrg if (msg->visible) toc->msgs[i]->position -= msg->length; 471c9e2be55Smrg } 472c9e2be55Smrg for (i=0 ; i<toc->numsequences ; i++) { 473c9e2be55Smrg mlist = toc->seqlist[i]->mlist; 474c9e2be55Smrg if (mlist) DeleteMsgFromMsgList(mlist, msg); 475c9e2be55Smrg } 476c9e2be55Smrg 477c9e2be55Smrg if (msg->visible && toc->num_scrns > 0 && !toc->needsrepaint) 478c9e2be55Smrg TSourceInvalid(toc, msg->position, -msg->length); 479c9e2be55Smrg TocSetCurMsg(toc, newcurmsg); 480c9e2be55Smrg TUSaveTocFile(toc); 481c9e2be55Smrg} 482d859ff80Smrg 483c9e2be55Smrg 484c9e2be55Smrg 485c9e2be55Smrgvoid TocRecheckValidity(Toc toc) 486c9e2be55Smrg{ 487c9e2be55Smrg Cardinal i; 488c9e2be55Smrg 489c9e2be55Smrg if (toc && toc->validity == valid && TUScanFileOutOfDate(toc)) { 490c9e2be55Smrg if (app_resources.block_events_on_busy) ShowBusyCursor(); 491c9e2be55Smrg 492c9e2be55Smrg TUScanFileForToc(toc); 493c9e2be55Smrg if (toc->source) 494c9e2be55Smrg TULoadTocFile(toc); 495c9e2be55Smrg for (i=0 ; i<toc->num_scrns ; i++) 496c9e2be55Smrg TURedisplayToc(toc->scrn[i]); 497c9e2be55Smrg 498c9e2be55Smrg if (app_resources.block_events_on_busy) UnshowBusyCursor(); 499c9e2be55Smrg } 500c9e2be55Smrg} 501c9e2be55Smrg 502c9e2be55Smrg 503c9e2be55Smrg/* Set the current message. */ 504c9e2be55Smrg 505c9e2be55Smrgvoid TocSetCurMsg(Toc toc, Msg msg) 506c9e2be55Smrg{ 507c9e2be55Smrg Msg msg2; 508c9e2be55Smrg Cardinal i; 509c9e2be55Smrg 510c9e2be55Smrg if (toc->validity != valid) return; 511c9e2be55Smrg if (msg != toc->curmsg) { 512c9e2be55Smrg msg2 = toc->curmsg; 513c9e2be55Smrg toc->curmsg = msg; 514c9e2be55Smrg if (msg2) 515c9e2be55Smrg MsgSetFate(msg2, msg2->fate, msg2->desttoc); 516c9e2be55Smrg } 517c9e2be55Smrg if (msg) { 518c9e2be55Smrg MsgSetFate(msg, msg->fate, msg->desttoc); 519c9e2be55Smrg if (toc->num_scrns) { 520c9e2be55Smrg if (toc->stopupdate) 521c9e2be55Smrg toc->needsrepaint = TRUE; 522c9e2be55Smrg else { 523c9e2be55Smrg for (i=0 ; i<toc->num_scrns ; i++) 524c9e2be55Smrg XawTextSetInsertionPoint(toc->scrn[i]->tocwidget, 525c9e2be55Smrg msg->position); 526c9e2be55Smrg } 527c9e2be55Smrg } 528c9e2be55Smrg } 529c9e2be55Smrg} 530c9e2be55Smrg 531c9e2be55Smrg 532c9e2be55Smrg/* Return the current message. */ 533c9e2be55Smrg 534c9e2be55SmrgMsg TocGetCurMsg(Toc toc) 535c9e2be55Smrg{ 536c9e2be55Smrg return toc->curmsg; 537c9e2be55Smrg} 538c9e2be55Smrg 539c9e2be55Smrg 540c9e2be55Smrg 541c9e2be55Smrg 542c9e2be55Smrg/* Return the message after the given one. (If none, return NULL.) */ 543c9e2be55Smrg 544c9e2be55SmrgMsg TocMsgAfter(Toc toc, Msg msg) 545c9e2be55Smrg{ 546c9e2be55Smrg int i; 547c9e2be55Smrg i = TUGetMsgPosition(toc, msg); 548c9e2be55Smrg do { 549c9e2be55Smrg i++; 550c9e2be55Smrg if (i >= toc->nummsgs) 551c9e2be55Smrg return NULL; 552c9e2be55Smrg } while (!(toc->msgs[i]->visible)); 553c9e2be55Smrg return toc->msgs[i]; 554c9e2be55Smrg} 555c9e2be55Smrg 556c9e2be55Smrg 557c9e2be55Smrg 558c9e2be55Smrg/* Return the message before the given one. (If none, return NULL.) */ 559c9e2be55Smrg 560c9e2be55SmrgMsg TocMsgBefore(Toc toc, Msg msg) 561c9e2be55Smrg{ 562c9e2be55Smrg int i; 563c9e2be55Smrg i = TUGetMsgPosition(toc, msg); 564c9e2be55Smrg do { 565c9e2be55Smrg i--; 566c9e2be55Smrg if (i < 0) 567c9e2be55Smrg return NULL; 568c9e2be55Smrg } while (!(toc->msgs[i]->visible)); 569c9e2be55Smrg return toc->msgs[i]; 570c9e2be55Smrg} 571c9e2be55Smrg 572c9e2be55Smrg 573c9e2be55Smrg 574c9e2be55Smrg/* The caller KNOWS the toc's information is out of date; rescan it. */ 575c9e2be55Smrg 576c9e2be55Smrgvoid TocForceRescan(Toc toc) 577c9e2be55Smrg{ 578c9e2be55Smrg register Cardinal i; 579c9e2be55Smrg 580c9e2be55Smrg if (toc->num_scrns) { 581c9e2be55Smrg toc->viewedseq = toc->seqlist[0]; 582c9e2be55Smrg for (i=0 ; i<toc->num_scrns ; i++) 583c9e2be55Smrg TUResetTocLabel(toc->scrn[i]); 584c9e2be55Smrg TUScanFileForToc(toc); 585c9e2be55Smrg TULoadTocFile(toc); 586c9e2be55Smrg for (i=0 ; i<toc->num_scrns ; i++) 587c9e2be55Smrg TURedisplayToc(toc->scrn[i]); 588c9e2be55Smrg } else { 589c9e2be55Smrg TUGetFullFolderInfo(toc); 590c9e2be55Smrg (void) unlink(toc->scanfile); 591c9e2be55Smrg toc->validity = invalid; 592c9e2be55Smrg } 593c9e2be55Smrg} 594c9e2be55Smrg 595c9e2be55Smrg 596c9e2be55Smrg 597c9e2be55Smrg/* The caller has just changed a sequence list. Reread them from mh. */ 598c9e2be55Smrg 599c9e2be55Smrgvoid TocReloadSeqLists(Toc toc) 600c9e2be55Smrg{ 601c9e2be55Smrg Cardinal i; 602c9e2be55Smrg 603c9e2be55Smrg TocSetCacheValid(toc); 604c9e2be55Smrg TULoadSeqLists(toc); 605c9e2be55Smrg TURefigureWhatsVisible(toc); 606c9e2be55Smrg for (i=0 ; i<toc->num_scrns ; i++) { 607c9e2be55Smrg TUResetTocLabel(toc->scrn[i]); 608c9e2be55Smrg EnableProperButtons(toc->scrn[i]); 609c9e2be55Smrg } 610c9e2be55Smrg} 611c9e2be55Smrg 612c9e2be55Smrg 613c9e2be55Smrg/*ARGSUSED*/ 614c9e2be55Smrgvoid XmhReloadSeqLists( 615c9e2be55Smrg Widget w, 616c9e2be55Smrg XEvent *event, 617c9e2be55Smrg String *params, 618c9e2be55Smrg Cardinal *num_params) 619c9e2be55Smrg{ 620c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 621c9e2be55Smrg TocReloadSeqLists(scrn->toc); 622c9e2be55Smrg TUCheckSequenceMenu(scrn->toc); 623c9e2be55Smrg} 624c9e2be55Smrg 625c9e2be55Smrg 626c9e2be55Smrg 627c9e2be55Smrg/* Return TRUE if the toc has an interesting sequence. */ 628c9e2be55Smrg 629c9e2be55Smrgint TocHasSequences(Toc toc) 630c9e2be55Smrg{ 631c9e2be55Smrg return toc && toc->numsequences > 1; 632c9e2be55Smrg} 633c9e2be55Smrg 634c9e2be55Smrg 635c9e2be55Smrg/* Change which sequence is being viewed. */ 636c9e2be55Smrg 637c9e2be55Smrgvoid TocChangeViewedSeq(Toc toc, Sequence seq) 638c9e2be55Smrg{ 639c9e2be55Smrg if (seq == NULL) seq = toc->viewedseq; 640c9e2be55Smrg toc->viewedseq = seq; 641c9e2be55Smrg toc->force_reset = True; /* %%% force Text source to be reset */ 642c9e2be55Smrg TURefigureWhatsVisible(toc); 643c9e2be55Smrg} 644c9e2be55Smrg 645c9e2be55Smrg 646c9e2be55Smrg/* Return the sequence with the given name in the given toc. */ 647c9e2be55Smrg 64866d665a3SmrgSequence TocGetSeqNamed(Toc toc, const char *name) 649c9e2be55Smrg{ 650c9e2be55Smrg register int i; 651c9e2be55Smrg if (name == NULL) 652c9e2be55Smrg return (Sequence) NULL; 653c9e2be55Smrg 654c9e2be55Smrg for (i=0 ; i<toc->numsequences ; i++) 655c9e2be55Smrg if (strcmp(toc->seqlist[i]->name, name) == 0) 656c9e2be55Smrg return toc->seqlist[i]; 657c9e2be55Smrg return (Sequence) NULL; 658c9e2be55Smrg} 659c9e2be55Smrg 660c9e2be55Smrg 661c9e2be55Smrg/* Return the sequence currently being viewed in the toc. */ 662c9e2be55Smrg 663c9e2be55SmrgSequence TocViewedSequence(Toc toc) 664c9e2be55Smrg{ 665c9e2be55Smrg return toc->viewedseq; 666c9e2be55Smrg} 667c9e2be55Smrg 668c9e2be55Smrg 669c9e2be55Smrg/* Set the selected sequence in the toc */ 670c9e2be55Smrg 671c9e2be55Smrgvoid TocSetSelectedSequence( 672c9e2be55Smrg Toc toc, 673c9e2be55Smrg Sequence sequence) 674c9e2be55Smrg{ 675d859ff80Smrg if (toc) 676c9e2be55Smrg toc->selectseq = sequence; 677c9e2be55Smrg} 678c9e2be55Smrg 679c9e2be55Smrg 680c9e2be55Smrg/* Return the sequence currently selected */ 681c9e2be55Smrg 682c9e2be55SmrgSequence TocSelectedSequence(Toc toc) 683c9e2be55Smrg{ 684c9e2be55Smrg if (toc) return (toc->selectseq); 685c9e2be55Smrg else return (Sequence) NULL; 686c9e2be55Smrg} 687c9e2be55Smrg 688c9e2be55Smrg 689c9e2be55Smrg/* Return the list of messages currently selected. */ 690c9e2be55Smrg 691c9e2be55Smrg#define SrcScan XawTextSourceScan 692c9e2be55Smrg 693c9e2be55SmrgMsgList TocCurMsgList(Toc toc) 694c9e2be55Smrg{ 695c9e2be55Smrg MsgList result; 696c9e2be55Smrg XawTextPosition pos1, pos2; 697c9e2be55Smrg 698c9e2be55Smrg if (toc->num_scrns == 0) return NULL; 699c9e2be55Smrg result = MakeNullMsgList(); 700c9e2be55Smrg XawTextGetSelectionPos( toc->scrn[0]->tocwidget, &pos1, &pos2); /* %%% */ 701c9e2be55Smrg if (pos1 < pos2) { 702c9e2be55Smrg pos1 = SrcScan(toc->source, pos1, XawstEOL, XawsdLeft, 1, FALSE); 703c9e2be55Smrg pos2 = SrcScan(toc->source, pos2, XawstPositions, XawsdLeft, 1, TRUE); 704c9e2be55Smrg pos2 = SrcScan(toc->source, pos2, XawstEOL, XawsdRight, 1, FALSE); 705c9e2be55Smrg while (pos1 < pos2) { 706c9e2be55Smrg AppendMsgList(result, MsgFromPosition(toc, pos1, XawsdRight)); 707c9e2be55Smrg pos1 = SrcScan(toc->source, pos1, XawstEOL, XawsdRight, 1, TRUE); 708c9e2be55Smrg } 709c9e2be55Smrg } 710c9e2be55Smrg return result; 711c9e2be55Smrg} 712c9e2be55Smrg 713c9e2be55Smrg 714c9e2be55Smrg 715c9e2be55Smrg/* Unset the current selection. */ 716c9e2be55Smrg 717c9e2be55Smrgvoid TocUnsetSelection(Toc toc) 718c9e2be55Smrg{ 719c9e2be55Smrg if (toc->source) 720c9e2be55Smrg XawTextUnsetSelection(toc->scrn[0]->tocwidget); 721c9e2be55Smrg} 722c9e2be55Smrg 723c9e2be55Smrg 724c9e2be55Smrg 725c9e2be55Smrg/* Create a brand new, blank message. */ 726c9e2be55Smrg 727c9e2be55SmrgMsg TocMakeNewMsg(Toc toc) 728c9e2be55Smrg{ 729c9e2be55Smrg Msg msg; 730c9e2be55Smrg static int looping = False; 731c9e2be55Smrg TUEnsureScanIsValidAndOpen(toc, False); 732c9e2be55Smrg msg = TUAppendToc(toc, "#### empty\n"); 733c9e2be55Smrg if (FileExists(MsgFileName(msg))) { 734c9e2be55Smrg if (looping++) Punt( "Cannot correct scan file" ); 735c9e2be55Smrg DEBUG2("**** FOLDER %s WAS INVALID; msg %d already existed!\n", 736c9e2be55Smrg toc->foldername, msg->msgid); 737c9e2be55Smrg TocForceRescan(toc); 738c9e2be55Smrg return TocMakeNewMsg(toc); /* Try again. Using recursion here is ugly, 739c9e2be55Smrg but what the hack ... */ 740c9e2be55Smrg } 741c9e2be55Smrg CopyFileAndCheck("/dev/null", MsgFileName(msg)); 742c9e2be55Smrg looping = False; 743c9e2be55Smrg return msg; 744c9e2be55Smrg} 745c9e2be55Smrg 746c9e2be55Smrg 747c9e2be55Smrg/* Set things to not update cache or display until further notice. */ 748c9e2be55Smrg 749c9e2be55Smrgvoid TocStopUpdate(Toc toc) 750c9e2be55Smrg{ 751c9e2be55Smrg Cardinal i; 752c9e2be55Smrg 753c9e2be55Smrg for (i=0 ; i<toc->num_scrns ; i++) 754c9e2be55Smrg XawTextDisableRedisplay(toc->scrn[i]->tocwidget); 755c9e2be55Smrg toc->stopupdate++; 756c9e2be55Smrg} 757c9e2be55Smrg 758c9e2be55Smrg 759c9e2be55Smrg/* Start updating again, and do whatever updating has been queued. */ 760c9e2be55Smrg 761c9e2be55Smrgvoid TocStartUpdate(Toc toc) 762c9e2be55Smrg{ 763c9e2be55Smrg Cardinal i; 764c9e2be55Smrg 765c9e2be55Smrg if (toc->stopupdate && --(toc->stopupdate) == 0) { 766c9e2be55Smrg for (i=0 ; i<toc->num_scrns ; i++) { 767d859ff80Smrg if (toc->needsrepaint) 768c9e2be55Smrg TURedisplayToc(toc->scrn[i]); 769c9e2be55Smrg if (toc->needslabelupdate) 770c9e2be55Smrg TUResetTocLabel(toc->scrn[i]); 771c9e2be55Smrg } 772c9e2be55Smrg if (toc->needscachesave) 773c9e2be55Smrg TUSaveTocFile(toc); 774c9e2be55Smrg } 775c9e2be55Smrg for (i=0 ; i<toc->num_scrns ; i++) 776c9e2be55Smrg XawTextEnableRedisplay(toc->scrn[i]->tocwidget); 777c9e2be55Smrg} 778c9e2be55Smrg 779c9e2be55Smrg 780c9e2be55Smrg 781c9e2be55Smrg/* Something has happened that could later convince us that our cache is out 782c9e2be55Smrg of date. Make this not happen; our cache really *is* up-to-date. */ 783c9e2be55Smrg 784c9e2be55Smrgvoid TocSetCacheValid(Toc toc) 785c9e2be55Smrg{ 786c9e2be55Smrg TUSaveTocFile(toc); 787c9e2be55Smrg} 788c9e2be55Smrg 789c9e2be55Smrg 790c9e2be55Smrg/* Return the full folder pathname of the given toc, prefixed w/'+' */ 791c9e2be55Smrg 792c9e2be55Smrgchar *TocMakeFolderName(Toc toc) 793c9e2be55Smrg{ 79466d665a3Smrg char* name; 79566d665a3Smrg XtAsprintf(&name, "+%s", toc->path); 796c9e2be55Smrg return name; 797c9e2be55Smrg} 798c9e2be55Smrg 799c9e2be55Smrgchar *TocName(Toc toc) 800c9e2be55Smrg{ 801c9e2be55Smrg return toc->foldername; 802c9e2be55Smrg} 803c9e2be55Smrg 804c9e2be55Smrg 805c9e2be55Smrg 806c9e2be55Smrg/* Given a foldername, return the corresponding toc. */ 807c9e2be55Smrg 80866d665a3SmrgToc TocGetNamed(const char *name) 809c9e2be55Smrg{ 810c9e2be55Smrg int i; 811c9e2be55Smrg for (i=0; i<numFolders ; i++) 812c9e2be55Smrg if (strcmp(folderList[i]->foldername, name) == 0) return folderList[i]; 813c9e2be55Smrg return NULL; 814c9e2be55Smrg} 815c9e2be55Smrg 816c9e2be55Smrg 817c9e2be55SmrgBoolean TocHasChanges(Toc toc) 818c9e2be55Smrg{ 819c9e2be55Smrg int i; 820c9e2be55Smrg for (i=0 ; i<toc->nummsgs ; i++) 821c9e2be55Smrg if (toc->msgs[i]->fate != Fignore) return True; 822c9e2be55Smrg 823c9e2be55Smrg return False; 824c9e2be55Smrg} 825c9e2be55Smrg 826c9e2be55Smrg 827c9e2be55Smrg 828c9e2be55Smrg/* Throw out all changes to this toc, and close all views of msgs in it. 829c9e2be55Smrg Requires confirmation by the user. */ 830c9e2be55Smrg 831c9e2be55Smrg/*ARGSUSED*/ 832c9e2be55Smrgstatic void TocCataclysmOkay( 833c9e2be55Smrg Widget widget, /* unused */ 834c9e2be55Smrg XtPointer client_data, 835c9e2be55Smrg XtPointer call_data) /* unused */ 836c9e2be55Smrg{ 837c9e2be55Smrg Toc toc = (Toc) client_data; 838c9e2be55Smrg register int i; 839c9e2be55Smrg 840c9e2be55Smrg for (i=0; i < toc->nummsgs; i++) 841c9e2be55Smrg MsgSetFate(toc->msgs[i], Fignore, (Toc)NULL); 842c9e2be55Smrg 843c9e2be55Smrg/* Doesn't make sense to have this MsgSetScrn for loop here. dmc. %%% */ 844c9e2be55Smrg for (i=0; i < toc->nummsgs; i++) 845d859ff80Smrg MsgSetScrn(toc->msgs[i], (Scrn) NULL, (XtCallbackList) NULL, 846c9e2be55Smrg (XtCallbackList) NULL); 847c9e2be55Smrg} 848d859ff80Smrg 849c9e2be55Smrgint TocConfirmCataclysm( 850c9e2be55Smrg Toc toc, 851c9e2be55Smrg XtCallbackList confirms, 852c9e2be55Smrg XtCallbackList cancels) 853d859ff80Smrg{ 854c9e2be55Smrg register int i; 855c9e2be55Smrg 856c9e2be55Smrg static XtCallbackRec yes_callbacks[] = { 857c9e2be55Smrg {TocCataclysmOkay, (XtPointer) NULL}, 858c9e2be55Smrg {(XtCallbackProc) NULL, (XtPointer) NULL}, 859c9e2be55Smrg {(XtCallbackProc) NULL, (XtPointer) NULL} 860c9e2be55Smrg }; 861c9e2be55Smrg 862c9e2be55Smrg if (! toc) 863c9e2be55Smrg return 0; 864c9e2be55Smrg 865c9e2be55Smrg if (TocHasChanges(toc)) { 866c9e2be55Smrg char str[300]; 867c9e2be55Smrg Widget tocwidget; 868c9e2be55Smrg 86966d665a3Smrg snprintf(str, sizeof(str), 87066d665a3Smrg "Are you sure you want to remove all changes to %s?", 87166d665a3Smrg toc->foldername); 872c9e2be55Smrg yes_callbacks[0].closure = (XtPointer) toc; 873c9e2be55Smrg yes_callbacks[1].callback = confirms[0].callback; 874c9e2be55Smrg yes_callbacks[1].closure = confirms[0].closure; 875c9e2be55Smrg 876c9e2be55Smrg tocwidget = NULL; 877c9e2be55Smrg for (i=0; i < toc->num_scrns; i++) 878c9e2be55Smrg if (toc->scrn[i]->mapped) { 879c9e2be55Smrg tocwidget = toc->scrn[i]->tocwidget; 880c9e2be55Smrg break; 881c9e2be55Smrg } 882c9e2be55Smrg 883c9e2be55Smrg PopupConfirm(tocwidget, str, yes_callbacks, cancels); 884c9e2be55Smrg return NEEDS_CONFIRMATION; 885c9e2be55Smrg } 886c9e2be55Smrg else { 887c9e2be55Smrg/* Doesn't make sense to have this MsgSetFate for loop here. dmc. %%% */ 888c9e2be55Smrg for (i=0 ; i<toc->nummsgs ; i++) 889c9e2be55Smrg MsgSetFate(toc->msgs[i], Fignore, (Toc)NULL); 890c9e2be55Smrg 891c9e2be55Smrg for (i=0 ; i<toc->nummsgs ; i++) 892c9e2be55Smrg if (MsgSetScrn(toc->msgs[i], (Scrn) NULL, confirms, cancels)) 893c9e2be55Smrg return NEEDS_CONFIRMATION; 894c9e2be55Smrg return 0; 895c9e2be55Smrg } 896c9e2be55Smrg} 897d859ff80Smrg 898c9e2be55Smrg 899c9e2be55Smrg/* Commit all the changes in this toc; all messages will meet their 'fate'. */ 900c9e2be55Smrg 901c9e2be55Smrg/*ARGSUSED*/ 902c9e2be55Smrgvoid TocCommitChanges( 903c9e2be55Smrg Widget widget, /* unused */ 904d859ff80Smrg XtPointer client_data, 905c9e2be55Smrg XtPointer call_data) /* unused */ 906c9e2be55Smrg{ 907c9e2be55Smrg Toc toc = (Toc) client_data; 908c9e2be55Smrg Msg msg; 909c9e2be55Smrg int i, cur = 0; 910c9e2be55Smrg char str[100], **argv = NULL; 911d859ff80Smrg FateType curfate, fate; 912c9e2be55Smrg Toc desttoc; 913c9e2be55Smrg Toc curdesttoc = NULL; 914c9e2be55Smrg XtCallbackRec confirms[2]; 915c9e2be55Smrg 916c9e2be55Smrg confirms[0].callback = TocCommitChanges; 917c9e2be55Smrg confirms[0].closure = (XtPointer) toc; 918c9e2be55Smrg confirms[1].callback = (XtCallbackProc) NULL; 919c9e2be55Smrg confirms[1].closure = (XtPointer) NULL; 920c9e2be55Smrg 921c9e2be55Smrg if (toc == NULL) return; 922c9e2be55Smrg for (i=0 ; i<toc->nummsgs ; i++) { 923c9e2be55Smrg msg = toc->msgs[i]; 924c9e2be55Smrg fate = MsgGetFate(msg, (Toc *)NULL); 925c9e2be55Smrg if (fate != Fignore && fate != Fcopy) 926c9e2be55Smrg if (MsgSetScrn(msg, (Scrn) NULL, confirms, (XtCallbackList) NULL) 927c9e2be55Smrg == NEEDS_CONFIRMATION) 928c9e2be55Smrg return; 929c9e2be55Smrg } 930c9e2be55Smrg XFlush(XtDisplay(toc->scrn[0]->parent)); 931c9e2be55Smrg for (i=0 ; i<numFolders ; i++) 932c9e2be55Smrg TocStopUpdate(folderList[i]); 933c9e2be55Smrg toc->haschanged = TRUE; 934c9e2be55Smrg if (app_resources.block_events_on_busy) ShowBusyCursor(); 935c9e2be55Smrg 936c9e2be55Smrg do { 937c9e2be55Smrg curfate = Fignore; 938c9e2be55Smrg i = 0; 939c9e2be55Smrg while (i < toc->nummsgs) { 940c9e2be55Smrg msg = toc->msgs[i]; 941c9e2be55Smrg fate = MsgGetFate(msg, &desttoc); 942c9e2be55Smrg if (curfate == Fignore && fate != Fignore) { 943c9e2be55Smrg curfate = fate; 944c9e2be55Smrg argv = MakeArgv(2); 945c9e2be55Smrg switch (curfate) { 946c9e2be55Smrg case Fdelete: 947c9e2be55Smrg argv[0] = XtNewString("rmm"); 948c9e2be55Smrg argv[1] = TocMakeFolderName(toc); 949c9e2be55Smrg cur = 2; 950c9e2be55Smrg curdesttoc = NULL; 951c9e2be55Smrg break; 952c9e2be55Smrg case Fmove: 953c9e2be55Smrg case Fcopy: 954c9e2be55Smrg argv[0] = XtNewString("refile"); 955c9e2be55Smrg cur = 1; 956c9e2be55Smrg curdesttoc = desttoc; 957c9e2be55Smrg break; 958c9e2be55Smrg default: 959c9e2be55Smrg break; 960c9e2be55Smrg } 961c9e2be55Smrg } 962c9e2be55Smrg if (curfate != Fignore && 963c9e2be55Smrg curfate == fate && desttoc == curdesttoc) { 964c9e2be55Smrg argv = ResizeArgv(argv, cur + 1); 96566d665a3Smrg snprintf(str, sizeof(str), "%d", MsgGetId(msg)); 966c9e2be55Smrg argv[cur++] = XtNewString(str); 967c9e2be55Smrg MsgSetFate(msg, Fignore, (Toc)NULL); 968c9e2be55Smrg if (curdesttoc) { 969c9e2be55Smrg (void) TUAppendToc(curdesttoc, MsgGetScanLine(msg)); 970c9e2be55Smrg curdesttoc->haschanged = TRUE; 971c9e2be55Smrg } 972c9e2be55Smrg if (curfate != Fcopy) { 973c9e2be55Smrg TocRemoveMsg(toc, msg); 974c9e2be55Smrg MsgFree(msg); 975c9e2be55Smrg i--; 976c9e2be55Smrg } 977c9e2be55Smrg if (cur > 40) 978c9e2be55Smrg break; /* Do only 40 at a time, just to be safe. */ 979d859ff80Smrg } 980c9e2be55Smrg i++; 981c9e2be55Smrg } 982c9e2be55Smrg if (curfate != Fignore) { 983c9e2be55Smrg switch (curfate) { 984c9e2be55Smrg case Fmove: 985c9e2be55Smrg case Fcopy: 986c9e2be55Smrg argv = ResizeArgv(argv, cur + 4); 987c9e2be55Smrg argv[cur++] = XtNewString(curfate == Fmove ? "-nolink" 988c9e2be55Smrg : "-link"); 989c9e2be55Smrg argv[cur++] = XtNewString("-src"); 990c9e2be55Smrg argv[cur++] = TocMakeFolderName(toc); 991c9e2be55Smrg argv[cur++] = TocMakeFolderName(curdesttoc); 992c9e2be55Smrg break; 993c9e2be55Smrg default: 994c9e2be55Smrg break; 995c9e2be55Smrg } 996c9e2be55Smrg if (app_resources.debug) { 997c9e2be55Smrg for (i = 0; i < cur; i++) 998c9e2be55Smrg (void) fprintf(stderr, "%s ", argv[i]); 999c9e2be55Smrg (void) fprintf(stderr, "\n"); 1000c9e2be55Smrg (void) fflush(stderr); 1001c9e2be55Smrg } 1002c9e2be55Smrg DoCommand(argv, (char *) NULL, (char *) NULL); 1003c9e2be55Smrg for (i = 0; argv[i]; i++) 1004c9e2be55Smrg XtFree((char *) argv[i]); 1005c9e2be55Smrg XtFree((char *) argv); 1006c9e2be55Smrg } 1007c9e2be55Smrg } while (curfate != Fignore); 1008c9e2be55Smrg for (i=0 ; i<numFolders ; i++) { 1009c9e2be55Smrg if (folderList[i]->haschanged) { 1010c9e2be55Smrg TocReloadSeqLists(folderList[i]); 1011c9e2be55Smrg folderList[i]->haschanged = FALSE; 1012c9e2be55Smrg } 1013c9e2be55Smrg TocStartUpdate(folderList[i]); 1014c9e2be55Smrg } 1015c9e2be55Smrg 1016c9e2be55Smrg if (app_resources.block_events_on_busy) UnshowBusyCursor(); 1017c9e2be55Smrg} 1018c9e2be55Smrg 1019c9e2be55Smrg 1020c9e2be55Smrg 1021c9e2be55Smrg/* Return whether the given toc can incorporate mail. */ 1022c9e2be55Smrg 1023c9e2be55Smrgint TocCanIncorporate(Toc toc) 1024c9e2be55Smrg{ 1025c9e2be55Smrg return (toc && (toc == InitialFolder || toc->incfile)); 1026c9e2be55Smrg} 1027c9e2be55Smrg 1028c9e2be55Smrg 1029c9e2be55Smrg/* Incorporate new messages into the given toc. */ 1030c9e2be55Smrg 1031c9e2be55Smrgint TocIncorporate(Toc toc) 1032c9e2be55Smrg{ 1033c9e2be55Smrg char **argv; 1034c9e2be55Smrg char str[100], *file, *ptr; 1035c9e2be55Smrg Msg msg, firstmessage = NULL; 1036c9e2be55Smrg FILEPTR fid; 1037c9e2be55Smrg 1038c9e2be55Smrg argv = MakeArgv(toc->incfile ? 7 : 4); 1039c9e2be55Smrg argv[0] = "inc"; 1040c9e2be55Smrg argv[1] = TocMakeFolderName(toc); 1041c9e2be55Smrg argv[2] = "-width"; 104266d665a3Smrg snprintf(str, sizeof(str), "%d", app_resources.toc_width); 1043c9e2be55Smrg argv[3] = str; 1044c9e2be55Smrg if (toc->incfile) { 1045c9e2be55Smrg argv[4] = "-file"; 1046c9e2be55Smrg argv[5] = toc->incfile; 1047c9e2be55Smrg argv[6] = "-truncate"; 1048c9e2be55Smrg } 1049c9e2be55Smrg if (app_resources.block_events_on_busy) ShowBusyCursor(); 1050c9e2be55Smrg 1051c9e2be55Smrg file = DoCommandToFile(argv); 1052c9e2be55Smrg XtFree(argv[1]); 1053c9e2be55Smrg XtFree((char *)argv); 1054c9e2be55Smrg TUGetFullFolderInfo(toc); 1055c9e2be55Smrg if (toc->validity == valid) { 1056c9e2be55Smrg fid = FOpenAndCheck(file, "r"); 1057c9e2be55Smrg TocStopUpdate(toc); 1058c9e2be55Smrg while ((ptr = ReadLineWithCR(fid))) { 1059c9e2be55Smrg if (atoi(ptr) > 0) { 1060c9e2be55Smrg msg = TUAppendToc(toc, ptr); 1061c9e2be55Smrg if (firstmessage == NULL) firstmessage = msg; 1062c9e2be55Smrg } 1063c9e2be55Smrg } 1064c9e2be55Smrg if (firstmessage && firstmessage->visible) { 1065c9e2be55Smrg TocSetCurMsg(toc, firstmessage); 1066c9e2be55Smrg } 1067c9e2be55Smrg TocStartUpdate(toc); 1068c9e2be55Smrg myfclose(fid); 1069c9e2be55Smrg } 1070c9e2be55Smrg DeleteFileAndCheck(file); 1071c9e2be55Smrg 1072c9e2be55Smrg if (app_resources.block_events_on_busy) UnshowBusyCursor(); 1073c9e2be55Smrg 1074c9e2be55Smrg toc->mailpending = False; 1075c9e2be55Smrg return (firstmessage != NULL); 1076c9e2be55Smrg} 1077c9e2be55Smrg 1078c9e2be55Smrg 1079c9e2be55Smrg/* The given message has changed. Rescan it and change the scanfile. */ 1080c9e2be55Smrg 1081c9e2be55Smrgvoid TocMsgChanged(Toc toc, Msg msg) 1082c9e2be55Smrg{ 1083c9e2be55Smrg char **argv, str[100], str2[10], *ptr; 1084c9e2be55Smrg int length, delta; 1085c9e2be55Smrg int i; 1086c9e2be55Smrg FateType fate; 1087c9e2be55Smrg Toc desttoc; 1088c9e2be55Smrg 1089c9e2be55Smrg if (toc->validity != valid) return; 1090c9e2be55Smrg fate = MsgGetFate(msg, &desttoc); 1091c9e2be55Smrg MsgSetFate(msg, Fignore, (Toc) NULL); 1092c9e2be55Smrg argv = MakeArgv(6); 1093c9e2be55Smrg argv[0] = "scan"; 1094c9e2be55Smrg argv[1] = TocMakeFolderName(toc); 109566d665a3Smrg snprintf(str, sizeof(str), "%d", msg->msgid); 1096c9e2be55Smrg argv[2] = str; 1097c9e2be55Smrg argv[3] = "-width"; 109866d665a3Smrg snprintf(str2, sizeof(str2), "%d", app_resources.toc_width); 1099c9e2be55Smrg argv[4] = str2; 1100c9e2be55Smrg argv[5] = "-noheader"; 1101c9e2be55Smrg ptr = DoCommandToString(argv); 1102c9e2be55Smrg XtFree(argv[1]); 1103c9e2be55Smrg XtFree((char *) argv); 1104c9e2be55Smrg if (strcmp(ptr, msg->buf) != 0) { 1105c9e2be55Smrg length = strlen(ptr); 1106c9e2be55Smrg delta = length - msg->length; 1107c9e2be55Smrg XtFree(msg->buf); 1108c9e2be55Smrg msg->buf = ptr; 1109c9e2be55Smrg msg->length = length; 1110c9e2be55Smrg toc->length += delta; 1111c9e2be55Smrg if (msg->visible) { 1112c9e2be55Smrg if (delta != 0) { 1113c9e2be55Smrg for (i=TUGetMsgPosition(toc, msg)+1; i<toc->nummsgs ; i++) 1114c9e2be55Smrg toc->msgs[i]->position += delta; 1115c9e2be55Smrg toc->lastPos += delta; 1116c9e2be55Smrg } 1117c9e2be55Smrg for (i=0 ; i<toc->num_scrns ; i++) 1118c9e2be55Smrg TURedisplayToc(toc->scrn[i]); 1119c9e2be55Smrg } 1120c9e2be55Smrg MsgSetFate(msg, fate, desttoc); 1121c9e2be55Smrg TUSaveTocFile(toc); 1122c9e2be55Smrg } else XtFree(ptr); 1123c9e2be55Smrg} 1124c9e2be55Smrg 1125c9e2be55Smrg 1126c9e2be55Smrg 1127c9e2be55SmrgMsg TocMsgFromId(Toc toc, int msgid) 1128c9e2be55Smrg{ 1129c9e2be55Smrg int h, l, m; 1130c9e2be55Smrg l = 0; 1131c9e2be55Smrg h = toc->nummsgs - 1; 1132c9e2be55Smrg if (h < 0) { 113366d665a3Smrg DEBUG1("Toc is empty! folder=%s\n", toc->foldername) 1134c9e2be55Smrg return NULL; 1135c9e2be55Smrg } 1136c9e2be55Smrg while (l < h - 1) { 1137c9e2be55Smrg m = (l + h) / 2; 1138c9e2be55Smrg if (toc->msgs[m]->msgid > msgid) 1139c9e2be55Smrg h = m; 1140c9e2be55Smrg else 1141c9e2be55Smrg l = m; 1142c9e2be55Smrg } 1143c9e2be55Smrg if (toc->msgs[l]->msgid == msgid) return toc->msgs[l]; 1144c9e2be55Smrg if (toc->msgs[h]->msgid == msgid) return toc->msgs[h]; 1145c9e2be55Smrg if (app_resources.debug) { 1146c9e2be55Smrg char str[100]; 114766d665a3Smrg snprintf(str, sizeof(str), 114866d665a3Smrg "TocMsgFromId search failed! hi=%d, lo=%d, msgid=%d\n", 114966d665a3Smrg h, l, msgid); 1150c9e2be55Smrg DEBUG( str ) 1151c9e2be55Smrg } 1152c9e2be55Smrg return NULL; 1153c9e2be55Smrg} 1154c9e2be55Smrg 1155d859ff80Smrg/* Sequence names are put on a stack which is specific to the folder. 1156c9e2be55Smrg * Sequence names are very volatile, so we make our own copies of the strings. 1157c9e2be55Smrg */ 1158c9e2be55Smrg 1159c9e2be55Smrg/*ARGSUSED*/ 1160c9e2be55Smrgvoid XmhPushSequence( 1161c9e2be55Smrg Widget w, 1162c9e2be55Smrg XEvent *event, 1163c9e2be55Smrg String *params, 1164c9e2be55Smrg Cardinal *count) 1165c9e2be55Smrg{ 1166c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 1167c9e2be55Smrg Toc toc; 1168c9e2be55Smrg Cardinal i; 1169c9e2be55Smrg 1170c9e2be55Smrg if (! (toc = scrn->toc)) return; 1171d859ff80Smrg 1172c9e2be55Smrg if (*count == 0) { 1173c9e2be55Smrg if (toc->selectseq) 1174c9e2be55Smrg Push(&toc->sequence_stack, XtNewString(toc->selectseq->name)); 1175c9e2be55Smrg } 1176c9e2be55Smrg else 1177d859ff80Smrg for (i=0; i < *count; i++) 1178c9e2be55Smrg Push(&toc->sequence_stack, XtNewString(params[i])); 1179c9e2be55Smrg} 1180c9e2be55Smrg 1181c9e2be55Smrg 1182c9e2be55Smrg/*ARGSUSED*/ 1183c9e2be55Smrgvoid XmhPopSequence( 1184c9e2be55Smrg Widget w, /* any widget on the screen of interest */ 1185c9e2be55Smrg XEvent *event, 1186c9e2be55Smrg String *params, 1187c9e2be55Smrg Cardinal *count) 1188c9e2be55Smrg{ 1189c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 119066d665a3Smrg const char *seqname; 1191c9e2be55Smrg Widget sequenceMenu, selected, original; 1192c9e2be55Smrg Button button; 1193c9e2be55Smrg Sequence sequence; 1194c9e2be55Smrg 1195c9e2be55Smrg if ((seqname = Pop(&scrn->toc->sequence_stack)) != NULL) { 1196c9e2be55Smrg 1197c9e2be55Smrg button = BBoxFindButtonNamed(scrn->mainbuttons, 1198c9e2be55Smrg MenuBoxButtons[XMH_SEQUENCE].button_name); 1199c9e2be55Smrg sequenceMenu = BBoxMenuOfButton(button); 1200c9e2be55Smrg 1201c9e2be55Smrg if ((selected = XawSimpleMenuGetActiveEntry(sequenceMenu))) 1202c9e2be55Smrg ToggleMenuItem(selected, False); 1203c9e2be55Smrg 1204c9e2be55Smrg if ((original = XtNameToWidget(sequenceMenu, seqname))) { 1205c9e2be55Smrg ToggleMenuItem(original, True); 1206c9e2be55Smrg sequence = TocGetSeqNamed(scrn->toc, seqname); 1207c9e2be55Smrg TocSetSelectedSequence(scrn->toc, sequence); 1208c9e2be55Smrg } 120966d665a3Smrg XtFree((char *)seqname); 1210c9e2be55Smrg } 1211c9e2be55Smrg} 1212