source: trunk/src/org/expeditee/gui/FrameIO.java@ 1363

Last change on this file since 1363 was 1363, checked in by bln4, 5 years ago

It is now possible to complete the process of recovering access to a Expeditee account. Further work, in the form of frames in the authentication frameset, are to follow.
A refactoring/tidy up has also been completed.

File size: 66.3 KB
RevLine 
[919]1/**
2 * FrameIO.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
[4]19package org.expeditee.gui;
20
[348]21import java.io.BufferedOutputStream;
[4]22import java.io.BufferedReader;
23import java.io.BufferedWriter;
24import java.io.File;
[7]25import java.io.FileInputStream;
[162]26import java.io.FileNotFoundException;
[7]27import java.io.FileOutputStream;
[4]28import java.io.FileReader;
29import java.io.FileWriter;
30import java.io.IOException;
[348]31import java.io.OutputStream;
32import java.io.OutputStreamWriter;
33import java.io.Writer;
[997]34import java.nio.channels.FileChannel;
[1244]35import java.nio.file.Files;
36import java.nio.file.Path;
[1242]37import java.nio.file.Paths;
[1293]38import java.nio.file.StandardCopyOption;
[105]39import java.sql.Time;
[1317]40import java.util.ArrayList;
[1242]41import java.util.Arrays;
[162]42import java.util.Collection;
[4]43import java.util.HashMap;
[162]44import java.util.LinkedList;
[1219]45import java.util.List;
[1242]46import java.util.Map;
[1270]47import java.util.function.Consumer;
[1242]48import java.util.stream.Collectors;
[4]49
[1244]50import org.apollo.io.AudioPathManager;
[415]51import org.expeditee.actions.Actions;
[8]52import org.expeditee.agents.ExistingFramesetException;
[1242]53import org.expeditee.agents.InvalidFramesetNameException;
[1283]54import org.expeditee.auth.AuthenticatorBrowser;
[1219]55import org.expeditee.auth.EncryptedExpReader;
[1227]56import org.expeditee.auth.EncryptedExpWriter;
[1363]57import org.expeditee.auth.mail.gui.MailBay;
[1242]58import org.expeditee.gio.EcosystemManager;
[4]59import org.expeditee.io.Conversion;
60import org.expeditee.io.ExpReader;
61import org.expeditee.io.ExpWriter;
62import org.expeditee.io.FrameReader;
63import org.expeditee.io.FrameWriter;
64import org.expeditee.io.KMSReader;
65import org.expeditee.io.KMSWriter;
66import org.expeditee.items.Item;
67import org.expeditee.items.ItemUtils;
[924]68import org.expeditee.items.Justification;
[454]69import org.expeditee.items.PermissionPair;
[778]70import org.expeditee.items.Text;
[454]71import org.expeditee.items.UserAppliedPermission;
[298]72import org.expeditee.network.FrameShare;
[1242]73import org.expeditee.setting.Setting;
[570]74import org.expeditee.settings.UserSettings;
[778]75import org.expeditee.settings.folders.FolderSettings;
76import org.expeditee.settings.templates.TemplateSettings;
[419]77import org.expeditee.stats.Formatter;
78import org.expeditee.stats.Logger;
[4]79import org.expeditee.stats.SessionStats;
80
81/**
82 * This class provides static methods for all saving and loading of Frames
83 * to\from disk. This class also handles any caching of previously loaded
84 * Frames.
85 *
86 * @author jdm18
87 *
88 */
[1244]89
90
[4]91public class FrameIO {
92
[24]93 private static final char FRAME_NAME_LAST_CHAR = 'A';
94
[1242]95 // The parent path that all others are relative to. Also referred to as Expeditee Home.
[4]96 public static String PARENT_FOLDER;
[1274]97
[1242]98 public static String PROFILE_PATH;
[4]99 public static String FRAME_PATH;
[1242]100 public static String IMAGES_PATH;
[1244]101 public static String AUDIO_PATH;
[286]102 public static String PUBLIC_PATH;
[1242]103 public static String TRASH_PATH;
[761]104 public static String FONT_PATH;
[504]105 public static String DICT_PATH;
[1274]106 public static String EXPORTS_PATH;
107 public static String STATISTICS_PATH;
108 public static String LOGS_PATH;
109 public static String MESSAGES_PATH;
110 public static String MAIL_PATH;
[1242]111 public static String SHARED_FRAMESETS_PATH;
112 public static String CONTACTS_PATH;
[1274]113 public static String RESOURCES_PRIVATE_PATH;
[1242]114 public static String RESOURCES_PATH;
115 public static String FRAME_PRIVATE_PATH;
116 public static String IMAGES_PRIVATE_PATH;
[1244]117 public static String AUDIO_PRIVATE_PATH;
[1257]118 public static String HELP_PRIVATE_PATH;
[1242]119 public static String HELP_PATH;
[1277]120 public static String DEAD_DROPS_PATH;
[1274]121
[1242]122 // Paths that appear to be unused.
123 public static String TEMPLATES_PATH;
124
125 // Variables for controlling cache functionality.
[4]126 public static final int MAX_NAME_LENGTH = 64;
[86]127 public static final int MAX_CACHE = 100;
[214]128 private static HashMap<String, Frame> _Cache = new FrameCache();
[1357]129 private static final boolean ENABLE_CACHE = true;
[4]130 private static boolean _UseCache = true;
131 private static boolean _SuspendedCache = false;
[1242]132
133 private static final String INF_FILENAME = "frame.inf";
134
[1244]135 public static void changeParentAndSubFolders(String newFolder) {
[1328]136 // Partial Paths
137 PARENT_FOLDER = newFolder;
[1244]138 PUBLIC_PATH = PARENT_FOLDER + "public" + File.separator;
139 TRASH_PATH = PARENT_FOLDER + "trash" + File.separator;
140 PROFILE_PATH = PARENT_FOLDER + "profiles" + File.separator;
[1274]141 EXPORTS_PATH = PARENT_FOLDER + "exports" + File.separator;
142 STATISTICS_PATH = PARENT_FOLDER + "statistics" + File.separator;
143 LOGS_PATH = PARENT_FOLDER + "logs" + File.separator;
[1244]144
[1328]145 String resourcesPublicPath = PARENT_FOLDER + "resources-public" + File.separator;
146 String resourcesPrivateIndividualPath = PARENT_FOLDER + "resources-" + UserSettings.UserName.get() + File.separator;
147
[1244]148 if (UserSettings.PublicAndPrivateResources) {
[1328]149 // Paths for the new regime
[1244]150 FONT_PATH = resourcesPublicPath + "fonts" + File.separator;
151 DICT_PATH = resourcesPublicPath + "dict" + File.separator;
[1328]152 HELP_PATH = resourcesPublicPath + "documentation" + File.separator;
153 HELP_PRIVATE_PATH = resourcesPrivateIndividualPath + "documentation" + File.separator;
154 FRAME_PATH = resourcesPublicPath + "framesets" + File.separator;
155 FRAME_PRIVATE_PATH = resourcesPrivateIndividualPath + "framesets" + File.separator;
156 MESSAGES_PATH = resourcesPrivateIndividualPath + "messages" + File.separator;
[1244]157 IMAGES_PATH = resourcesPublicPath + "images" + File.separator;
[1328]158 IMAGES_PRIVATE_PATH = resourcesPrivateIndividualPath + "images" + File.separator;
[1244]159 AUDIO_PATH = resourcesPublicPath + "audio" + File.separator;
[1328]160 AUDIO_PRIVATE_PATH = resourcesPrivateIndividualPath + "audio" + File.separator;
161
162 // Used only when extracting resources (when expeditee is run for first time)
163 RESOURCES_PRIVATE_PATH = PARENT_FOLDER + "resources-private" + File.separator;
164
165 if (AuthenticatorBrowser.isAuthenticated()) {
166 // Paths for the new regime while authenticated
167 SHARED_FRAMESETS_PATH = resourcesPrivateIndividualPath + "framesets-shared" + File.separator;
168 DEAD_DROPS_PATH = resourcesPrivateIndividualPath + "deaddrops" + File.separator;
169 CONTACTS_PATH = resourcesPrivateIndividualPath + "contacts" + File.separator;
170 MAIL_PATH = resourcesPrivateIndividualPath + "mail" + File.separator;
171 } else {
172 SHARED_FRAMESETS_PATH = null;
173 DEAD_DROPS_PATH = null;
174 CONTACTS_PATH = null;
175 MAIL_PATH = null;
176 }
[1251]177 } else {
[1328]178 // Paths for the old regime
[1244]179 FONT_PATH = PARENT_FOLDER + "fonts" + File.separator;
180 DICT_PATH = PARENT_FOLDER + "dict" + File.separator;
[1328]181 HELP_PATH = PARENT_FOLDER + "documentation" + File.separator;
182 FRAME_PATH = PARENT_FOLDER + "framesets" + File.separator;
183 MESSAGES_PATH = PARENT_FOLDER + "messages" + File.separator;
[1244]184 IMAGES_PATH = PARENT_FOLDER + "images" + File.separator;
185 AUDIO_PATH = PARENT_FOLDER + "audio" + File.separator;
186
[1353]187 // These paths are not used by old regime.
188 HELP_PRIVATE_PATH = null;
189 FRAME_PRIVATE_PATH = null;
190 IMAGES_PRIVATE_PATH = null;
191 AUDIO_PRIVATE_PATH = null;
192 // - This last one is never used because old regime is never extracted. If we are going to FrameUtils.extractResources then we are doing new regime.
193 RESOURCES_PRIVATE_PATH = null;
194
[1328]195 if (AuthenticatorBrowser.isAuthenticated()) {
196 // Paths for the old regime while authenticated
197 SHARED_FRAMESETS_PATH = PARENT_FOLDER + "framesets-shared" + File.separator;
198 DEAD_DROPS_PATH = PARENT_FOLDER + "deaddrops" + File.separator;
199 CONTACTS_PATH = PARENT_FOLDER + "contacts" + File.separator;
200 MAIL_PATH = PARENT_FOLDER + "mail" + File.separator;
[1274]201 } else {
[1328]202 SHARED_FRAMESETS_PATH = null;
203 DEAD_DROPS_PATH = null;
204 CONTACTS_PATH = null;
205 MAIL_PATH = null;
[1274]206 }
[1328]207 }
[1244]208
209 System.err.println("**** FrameIO::changeParentAndSubFolder(): Calling AudioPathManger.changeParentAndSubFolder()");
210 AudioPathManager.changeParentAndSubFolders(newFolder);
211 }
212
[1328]213// public static void changeParentAndSubFolders(String newFolder) {
214// // Partial Paths.
215// PARENT_FOLDER = newFolder;
216// String resourcesPublicPath = PARENT_FOLDER + "resources-public" + File.separator;
217// String resourcesPrivateIndividualPath = PARENT_FOLDER + "resources-" + UserSettings.UserName.get() + File.separator;
218//
219// // Standard paths.
220// PUBLIC_PATH = PARENT_FOLDER + "public" + File.separator;
221// TRASH_PATH = PARENT_FOLDER + "trash" + File.separator;
222// HELP_PATH = PARENT_FOLDER + "documentation" + File.separator;
223// PROFILE_PATH = PARENT_FOLDER + "profiles" + File.separator;
224// EXPORTS_PATH = PARENT_FOLDER + "exports" + File.separator;
225// STATISTICS_PATH = PARENT_FOLDER + "statistics" + File.separator;
226// LOGS_PATH = PARENT_FOLDER + "logs" + File.separator;
227//
228//
229// // Conditional paths
230// if (UserSettings.PublicAndPrivateResources) {
231// // Work with a system of public and private folders
232//
233// FONT_PATH = resourcesPublicPath + "fonts" + File.separator;
234// DICT_PATH = resourcesPublicPath + "dict" + File.separator;
235// IMAGES_PATH = resourcesPublicPath + "images" + File.separator;
236// AUDIO_PATH = resourcesPublicPath + "audio" + File.separator;
237// FRAME_PATH = resourcesPublicPath + "framesets" + File.separator;
238// } else {
239// FONT_PATH = PARENT_FOLDER + "fonts" + File.separator;
240// DICT_PATH = PARENT_FOLDER + "dict" + File.separator;
241// IMAGES_PATH = PARENT_FOLDER + "images" + File.separator;
242// AUDIO_PATH = PARENT_FOLDER + "audio" + File.separator;
243// FRAME_PATH = PARENT_FOLDER + "framesets" + File.separator;
244// DEAD_DROPS_PATH = PARENT_FOLDER + "deaddrops" + File.separator;
245// }
246//
247// if (!UserSettings.PublicAndPrivateResources || (AuthenticatorBrowser.isAuthenticationRequired() && !AuthenticatorBrowser.isAuthenticated())) {
248//
249// if (UserSettings.UserName.get().equals(AuthenticatorBrowser.USER_NOBODY)) {
250// System.err.println("**** FrameIO::changeParentAndSubFolders(): Not setting subfolders for user '"+AuthenticatorBrowser.USER_NOBODY+"'");
251// }
252//
253// // If we are using the old regime, or user.name set to Browser.USER_NOBODY
254// // => then these paths should not be used.
255// RESOURCES_PATH = null;
256// SHARED_FRAMESETS_PATH = null;
257// RESOURCES_PRIVATE_PATH = null;
258// FRAME_PRIVATE_PATH = null;
259// IMAGES_PRIVATE_PATH = null;
260// AUDIO_PRIVATE_PATH = null;
261// CONTACTS_PATH = null;
262// HELP_PRIVATE_PATH = null;
263//
264// if (!UserSettings.PublicAndPrivateResources) {
265// MESSAGES_PATH = PARENT_FOLDER + "messages" + File.separator;
266// } else {
267// MESSAGES_PATH = resourcesPrivateIndividualPath + "messages" + File.separator;
268// }
269//
270// } else {
271// RESOURCES_PATH = resourcesPublicPath + "documentation" + File.separator;
272// SHARED_FRAMESETS_PATH = resourcesPrivateIndividualPath + "framesets-shared" + File.separator;
273//
274// RESOURCES_PRIVATE_PATH = PARENT_FOLDER + "resources-private" + File.separator;
275// FRAME_PRIVATE_PATH = resourcesPrivateIndividualPath + "framesets" + File.separator;
276// IMAGES_PRIVATE_PATH = resourcesPrivateIndividualPath + "images" + File.separator;
277// AUDIO_PRIVATE_PATH = resourcesPrivateIndividualPath + "audio" + File.separator;
278// CONTACTS_PATH = resourcesPrivateIndividualPath + "contacts" + File.separator;
279// HELP_PRIVATE_PATH = resourcesPrivateIndividualPath + "documentation" + File.separator;
280// MESSAGES_PATH = resourcesPrivateIndividualPath + "messages" + File.separator;
281// MAIL_PATH = resourcesPrivateIndividualPath + "mail" + File.separator;
282// DEAD_DROPS_PATH = resourcesPrivateIndividualPath + "deaddrops" + File.separator;
283// }
284//
285//
286// System.err.println("**** FrameIO::changeParentAndSubFolder(): Calling AudioPathManger.changeParentAndSubFolder()");
287// AudioPathManager.changeParentAndSubFolders(newFolder);
288// }
289
[4]290 // All methods are static, this should not be instantiated
291 private FrameIO() {
292 }
293
294 public static boolean isCacheOn() {
295 return _UseCache && ENABLE_CACHE;
296 }
297
298 public static void Precache(String framename) {
299 // if the cache is turned off, do nothing
[1188]300 if (!isCacheOn()) {
[4]301 return;
[1188]302 }
[4]303
304 // if the frame is already in the cache, do nothing
[1188]305 if (_Cache.containsKey(framename.toLowerCase())) {
[4]306 return;
[1188]307 }
[4]308
309 // otherwise, load the frame and put it in the cache
310 Logger.Log(Logger.SYSTEM, Logger.LOAD, "Precaching " + framename + ".");
311
312 // do not display errors encountered to the user
313 // (they will be shown at load time)
[689]314 MessageBay.suppressMessages(true);
[4]315 // loading automatically caches the frame is caching is turned on
[307]316 LoadFromDisk(framename, null, false);
[689]317 MessageBay.suppressMessages(false);
[4]318 }
319
320 /**
321 * Checks if a string is a representation of a positive integer.
322 *
323 * @param s
324 * @return true if s is a positive integer
325 */
326 public static boolean isPositiveInteger(String s) {
[1188]327 if (s == null || s.length() == 0) {
[4]328 return false;
[1188]329 }
[4]330
331 for (int i = 0; i < s.length(); i++) {
[1188]332 if (!Character.isDigit(s.charAt(i))) {
[4]333 return false;
[1188]334 }
[4]335 }
336 return true;
337 }
[1188]338
[1242]339 /**
340 * Loads a frame with the specified name.
341 * By using a dot separated framename, users are able to specify the path to find the frameset in.
342 * @param frameName The frame to load.
343 * @return the loaded frame
344 */
[4]345 public static Frame LoadFrame(String frameName) {
[1242]346 if (frameName.contains(".")) {
347 String[] split = frameName.split("\\.");
348 String[] pathSplit = Arrays.copyOfRange(split, 0, split.length - 1);
349 String name = split[split.length - 1];
350 String path = Arrays.asList(pathSplit).stream().collect(Collectors.joining(File.separator));
351 return LoadFrame(name, Paths.get(FrameIO.PARENT_FOLDER).resolve(path).toString() + File.separator, false);
352 } else {
[1284]353 return LoadFrame(frameName, null, false);
[1242]354 }
[282]355 }
[298]356
[307]357 public static Frame LoadFrame(String frameName, String path) {
358 return LoadFrame(frameName, path, false);
359 }
360
[1219]361 public static Frame LoadFrame(String frameName, String path, boolean ignoreAnnotations) {
[1188]362 if (!isValidFrameName(frameName)) {
363 return null;
364 }
[1242]365
[108]366 String frameNameLower = frameName.toLowerCase();
[4]367 // first try reading from cache
[108]368 if (isCacheOn() && _Cache.containsKey(frameNameLower)) {
[1102]369 Logger.Log(Logger.SYSTEM, Logger.LOAD, "Loading " + frameName + " from cache.");
[247]370 Frame frame = _Cache.get(frameNameLower);
[1229]371
[1242]372 // if frame in cache is older than the one on disk then don't use the cached one
373 File file = new File(frame.getFramePathReal());
374 long lastModified = file.lastModified();
375 if (lastModified <= frame.getLastModifyPrecise()) {
[1229]376 return frame;
377 }
[4]378 }
379
380 Logger.Log(Logger.SYSTEM, Logger.LOAD, "Loading " + frameName
381 + " from disk.");
[307]382
[1242]383 Frame fromDisk = LoadFromDisk(frameName, path, ignoreAnnotations);
384 return fromDisk;
[4]385 }
386
[997]387 //Loads the 'restore' version of a frame if there is one
[1229]388 public static Frame LoadRestoreFrame(Frame frameToRestore) {
[997]389
[1229]390 String fullPath = getFrameFullPathName(frameToRestore.getPath(), frameToRestore
391 .getName());
392 //System.out.println("fullpath: " + fullPath);
393 String restoreVersion = fullPath + ".restore";
394 //System.out.println("restoreversion" + restoreVersion);
395 File source = new File(restoreVersion);
396 File dest = new File(fullPath);
397
398 FileChannel inputChannel = null;
399 FileChannel outputChannel = null;
400
401 try{
[1242]402 FileInputStream source_fis = new FileInputStream(source);
403 inputChannel = source_fis.getChannel();
404
405 FileOutputStream dest_fos = new FileOutputStream(dest);
406 outputChannel = dest_fos.getChannel();
[997]407
[1242]408 outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
409 inputChannel.close();
410 outputChannel.close();
411 source_fis.close();
412 dest_fos.close();
[1229]413 }
414 catch(Exception e){
415 System.err.println("No restore point detected.");
416 }
417 String frameName = frameToRestore.getName();
418 String frameNameLower = frameName.toLowerCase();
[997]419
[1229]420 // first try reading from cache
421 if (isCacheOn() && _Cache.containsKey(frameNameLower)) {
422 Logger.Log(Logger.SYSTEM, Logger.LOAD, "Clearing " + frameName
423 + " from cache.");
424 _Cache.remove(frameNameLower);
425 }
426
427 return LoadFrame(frameName, frameToRestore.getPath(), true);
428 }
429
[305]430 public static BufferedReader LoadPublicFrame(String frameName) {
431 String fullPath = FrameIO.getFrameFullPathName(PUBLIC_PATH, frameName);
[306]432
[1188]433 if (fullPath == null) {
[307]434 return null;
[1188]435 }
[336]436
[305]437 File frameFile = new File(fullPath);
438 if (frameFile.exists() && frameFile.canRead()) {
439 try {
440 return new BufferedReader(new FileReader(frameFile));
441 } catch (FileNotFoundException e) {
442 e.printStackTrace();
443 }
[298]444 }
[305]445 return null;
[298]446 }
447
[307]448 private static Frame LoadFromDisk(String framename, String knownPath,
[298]449 boolean ignoreAnnotations) {
450 Frame loaded = null;
451
[307]452 if (knownPath != null) {
[1242]453 loaded = LoadKnownPath(knownPath, framename);
[307]454 } else {
[1244]455 List<String> directoriesToSearch = FolderSettings.FrameDirs.getAbsoluteDirs();
[1219]456
[1316]457// if (AuthenticatorBrowser.Authenticated) {
458// // if we are running Expeditee Authenticated, consult user profile as location for framesets first
459// String profilePath = FrameIO.PROFILE_PATH + UserSettings.UserName.get() + File.separator;
460// directoriesToSearch.add(0, profilePath);
461// }
[1219]462
463 for (String path : directoriesToSearch) {
[1242]464 loaded = LoadKnownPath(path, framename);
[307]465 if (loaded != null) {
466 break;
467 }
[4]468 }
469 }
[336]470
[305]471 if (loaded == null && FrameShare.getInstance() != null) {
[307]472 loaded = FrameShare.getInstance().loadFrame(framename, knownPath);
[298]473 }
474
475 if (loaded != null) {
476 FrameUtils.Parse(loaded, true, ignoreAnnotations);
[1242]477 FrameIO.setSavedProperties(loaded);
[298]478 }
479
[4]480 return loaded;
481 }
482
483 /**
[7]484 * Gets a list of all the framesets available to the user
485 *
486 * @return a string containing a list of all the available framesets on
487 * separate lines
488 */
489 public static String getFramesetList() {
490 StringBuffer list = new StringBuffer();
491
[1244]492 for (String path : FolderSettings.FrameDirs.getAbsoluteDirs()) {
[97]493 File files = new File(path);
[1188]494 if (!files.exists()) {
[97]495 continue;
[1188]496 }
[7]497 for (File f : (new File(path)).listFiles()) {
498 if (f.isDirectory()) {
499 list.append(f.getName()).append('\n');
500 }
501 }
502 }
503 // remove the final new line char
504 list.deleteCharAt(list.length() - 1);
505 return list.toString();
506 }
[1316]507
508 /**
509 * Gets a list of all the profiles available to the user
510 *
511 * @return a list containing all the available framesets on separate lines
512 */
513 public static List<String> getProfilesList() {
[1317]514 File[] listFiles = new File(FrameIO.PROFILE_PATH).listFiles();
515 if (listFiles == null) return new ArrayList<String>();
516 List<File> potentialProfiles = Arrays.asList(listFiles);
[1316]517 potentialProfiles.removeIf(file -> !file.isDirectory());
518 return potentialProfiles.stream().map(dir -> dir.getName()).collect(Collectors.toList());
519 }
[7]520
521 /**
[4]522 * Gets the full path and file name of the frame.
[1242]523 * This is a alias for Frame::getFramePathLogical
[4]524 * @param path-
525 * the directory in which to look for the frameset containing the
526 * frame.
527 * @param frameName-
528 * the name of the frame for which the path is being requested.
529 * @return null if the frame can not be located.
530 */
[298]531 public static synchronized String getFrameFullPathName(String path,
532 String frameName) {
[997]533
534 String source;
535 String fileName = null;
536 if(frameName.contains("restore")){
537 source = path + File.separator;// + frameName;
538 fileName = path + File.separator + frameName + ExpReader.EXTENTION;
539
540 }
541 else
542 {
543 source = path + Conversion.getFramesetName(frameName)
544 + File.separator;
545 }
546
[4]547
548 File tester = new File(source);
[1188]549 if (!tester.exists()) {
[4]550 return null;
[1188]551 }
[4]552
[997]553 String fullPath;
554
555 if(frameName.contains("restore")){
556
557 fullPath = fileName;
558 }
559 else
560 {
561 // check for the new file name format
562 fullPath = source + Conversion.getFrameNumber(frameName)
563 + ExpReader.EXTENTION;
564 }
565
[4]566 tester = new File(fullPath);
567
[1188]568 if (tester.exists()) {
[4]569 return fullPath;
[1188]570 }
[4]571
[601]572 // check for oldfile name format
[97]573 fullPath = source + Conversion.getFramesetName(frameName) + "."
[4]574 + Conversion.getFrameNumber(frameName);
575 tester = new File(fullPath);
576
[1188]577 if (tester.exists()) {
[4]578 return fullPath;
[1188]579 }
[4]580
581 return null;
582 }
583
[97]584 public static boolean canAccessFrame(String frameName) {
[1102]585 Frame current = DisplayController.getCurrentFrame();
[436]586 // Just in case the current frame is not yet saved...
[298]587 if (frameName.equals(current.getName())) {
588 FrameIO.SaveFrame(current, false, false);
[294]589 current.change();
590 return true;
591 }
[298]592
[1244]593 for (String path : FolderSettings.FrameDirs.getAbsoluteDirs()) {
[1188]594 if (getFrameFullPathName(path, frameName) != null) {
[4]595 return true;
[1188]596 }
[4]597 }
598 return false;
599 }
600
[162]601 public static Collection<String> searchFrame(String frameName,
602 String pattern, String path) {
603 String fullPath = null;
604 if (path == null) {
[1244]605 for (String possiblePath : FolderSettings.FrameDirs.getAbsoluteDirs()) {
[162]606 fullPath = getFrameFullPathName(possiblePath, frameName);
[1188]607 if (fullPath != null) {
[162]608 break;
[1188]609 }
[162]610 }
611 } else {
612 fullPath = getFrameFullPathName(path, frameName);
613 }
614 // If the frame was not located return null
[1188]615 if (fullPath == null) {
[162]616 return null;
[1188]617 }
[162]618 Collection<String> results = new LinkedList<String>();
619 // Open the file and search the text items
620 try {
621 BufferedReader reader = new BufferedReader(new FileReader(fullPath));
622 String next;
623 while (reader.ready() && ((next = reader.readLine()) != null)) {
624 if (next.startsWith("T")) {
625 String toSearch = next.substring(2);
[1188]626 if (toSearch.toLowerCase().contains(pattern)) {
[162]627 results.add(toSearch);
[1188]628 }
[1289]629 } else if (next.startsWith("+T+")) {
630 String toSearch = next.substring(4);
631 if (toSearch.toLowerCase().contains(pattern)) {
632 results.add(toSearch);
633 }
[162]634 }
635 }
[1219]636 reader.close();
[162]637 } catch (FileNotFoundException e) {
638 e.printStackTrace();
639 return null;
640 } catch (IOException e) {
641 e.printStackTrace();
642 }
643 return results;
644 }
645
[1242]646 private static Frame LoadKnownPath(String path, String frameName) {
[4]647 String fullPath = getFrameFullPathName(path, frameName);
[1188]648 if (fullPath == null) {
[4]649 return null;
[1188]650 }
[4]651
652 try {
653 FrameReader reader;
[1242]654
655 // Get the frameset name.
656 int i = frameName.length() - 1;
657 for (; i >= 0; i--) {
658 if (!Character.isDigit(frameName.charAt(i))) {
659 break;
660 }
661 }
662 if (i < 0) {
663 System.err.println("LoadKnownFrame was provided with a invalid Frame name: " + frameName);
664 return null;
665 }
666 String framesetName = frameName.substring(0, i + 1);
667
668 String redirectTo = ExpReader.redirectTo(fullPath);
669 while (redirectTo != null) {
670 fullPath = path + framesetName + File.separator + redirectTo;
671 redirectTo = ExpReader.redirectTo(fullPath);
672 }
673
[601]674 if (fullPath.endsWith(ExpReader.EXTENTION)) {
[1200]675 if (EncryptedExpReader.isEncryptedExpediteeFile(fullPath)) {
[1227]676 reader = new EncryptedExpReader(frameName);
[1200]677 } else {
678 reader = new ExpReader(frameName);
679 }
[4]680 } else {
681 reader = new KMSReader();
682 }
683 Frame frame = reader.readFrame(fullPath);
684
685 if (frame == null) {
[121]686 MessageBay.errorMessage("Error: " + frameName
[4]687 + " could not be successfully loaded.");
688 return null;
689 }
690
[298]691 frame.setPath(path);
[4]692
693 // do not put 0 frames or virtual frames into the cache
[336]694 // Why are zero frames not put in the cache
[1188]695 if (_Cache.size() > MAX_CACHE) {
[4]696 _Cache.clear();
[1188]697 }
[4]698
[1188]699 if (frame.getNumber() > 0 && isCacheOn()) {
[4]700 _Cache.put(frameName.toLowerCase(), frame);
[1188]701 }
[4]702
703 return frame;
704 } catch (IOException ioe) {
705 ioe.printStackTrace();
706 Logger.Log(ioe);
707 } catch (Exception e) {
708 e.printStackTrace();
709 Logger.Log(e);
[121]710 MessageBay.errorMessage("Error: " + frameName
[4]711 + " could not be successfully loaded.");
712 }
713
714 return null;
715 }
716
717 public static void Reload() {
718 // disable cache
719 boolean cache = _UseCache;
720
721 _UseCache = false;
[1102]722 Frame fresh = FrameIO.LoadFrame(DisplayController.getCurrentFrame().getName());
[4]723 _UseCache = cache;
[1188]724 if (_Cache.containsKey(fresh.getName().toLowerCase())) {
[108]725 addToCache(fresh);
[1188]726 }
[1102]727 DisplayController.setCurrentFrame(fresh, false);
[4]728 }
729
730 public static Frame LoadPrevious(Frame current) {
[7]731 checkTDFC(current);
732
[4]733 // the current name and number
[24]734 String name = current.getFramesetName();
[80]735 int num = current.getNumber() - 1;
[4]736
737 // loop until a frame that exists is found
738 for (; num >= 0; num--) {
[307]739 Frame f = LoadFrame(name + num, current.getPath());
[1188]740 if (f != null) {
[4]741 return f;
[1188]742 }
[4]743 }
744
745 // if we did not find another Frame then this one must be the last one
746 // in the frameset
[121]747 MessageBay
748 .displayMessageOnce("This is the first frame in the frameset");
[4]749 return null;
750 }
751
752 /**
753 * Returns the next Frame in the current Frameset (The Frame with the next
754 * highest Frame number) If the current Frame is the last one in the
755 * Frameset, or an error occurs then null is returned.
756 *
757 * @return The Frame after this one in the current frameset, or null
758 */
759 public static Frame LoadNext(Frame current) {
[7]760 checkTDFC(current);
[4]761
762 // the current name and number
[80]763 int num = current.getNumber() + 1;
[4]764 int max = num + 1;
[24]765 String name = current.getFramesetName();
[4]766
767 // read the maximum from the INF file
768 try {
[307]769 max = ReadINF(current.getPath(), current.getFramesetName(), false);
[4]770 } catch (IOException ioe) {
[121]771 MessageBay.errorMessage("Error loading INF file for frameset '"
[4]772 + name + "'");
773 return null;
774 }
775
776 // loop until a frame that exists is found
777 for (; num <= max; num++) {
[307]778 Frame f = LoadFrame(name + num, current.getPath());
[1188]779 if (f != null) {
[4]780 return f;
[1188]781 }
[4]782 }
783
784 // if we did not find another Frame then this one must be the last one
785 // in the frameset
[162]786 MessageBay.displayMessageOnce("This is the last frame in the frameset");
[4]787 return null;
788 }
789
[7]790 /**
791 * This method checks if the current frame has just been created with TDFC.
792 * If it has the frame is saved regardless of whether it has been edited or
793 * not and the TDFC item property is cleared. This is to ensure that the
794 * link is saved on the parent frame.
795 *
796 * @param current
797 */
[86]798 public static void checkTDFC(Frame current) {
[70]799 if (FrameUtils.getTdfcItem() != null) {
800 FrameUtils.setTdfcItem(null);
[7]801 current.change();
802 }
803 }
804
[4]805 public static Frame LoadLast(String framesetName, String path) {
806 // read the maximum from the INF file
807 int max;
808 try {
[307]809 max = ReadINF(path, framesetName, false);
[4]810 } catch (IOException ioe) {
[121]811 MessageBay.errorMessage("Error loading INF file for frameset '"
[4]812 + framesetName + "'");
813 return null;
814 }
815
816 // loop backwards until a frame that exists is found
817 for (int num = max; num > 0; num--) {
[307]818 Frame f = LoadFromDisk(framesetName + num, path, false);
[1188]819 if (f != null) {
[4]820 return f;
[1188]821 }
[4]822 }
823
824 // if we did not find another Frame then this one must be the last one
825 // in the frameset
[121]826 MessageBay.displayMessage("This is the last frame in the frameset");
[4]827 return null;
828 }
[24]829
[13]830 public static Frame LoadZero(String framesetName, String path) {
[24]831 return LoadFrame(framesetName + 0);
[13]832 }
[4]833
[13]834 public static Frame LoadZero() {
[1102]835 Frame current = DisplayController.getCurrentFrame();
[298]836 return LoadZero(current.getFramesetName(), current.getPath());
[13]837 }
[24]838
[4]839 public static Frame LoadLast() {
[1102]840 Frame current = DisplayController.getCurrentFrame();
[298]841 return LoadLast(current.getFramesetName(), current.getPath());
[4]842 }
843
844 public static Frame LoadNext() {
[1102]845 return LoadNext(DisplayController.getCurrentFrame());
[4]846 }
847
848 public static Frame LoadPrevious() {
[1102]849 return LoadPrevious(DisplayController.getCurrentFrame());
[4]850 }
851
852 /**
853 * Deletes the given Frame on disk and removes the cached Frame if there is
854 * one. Also adds the deleted frame into the deletedFrames frameset.
855 *
856 * @param toDelete
857 * The Frame to be deleted
[162]858 * @return The name the deleted frame was changed to, or null if the delete
859 * failed
[4]860 */
[154]861 public static String DeleteFrame(Frame toDelete) throws IOException,
[97]862 SecurityException {
[1188]863 if (toDelete == null) {
[154]864 return null;
[1188]865 }
[7]866
[72]867 // Dont delete the zero frame
[80]868 if (toDelete.getNumber() == 0) {
[97]869 throw new SecurityException("Deleting a zero frame is illegal");
[72]870 }
871
[298]872 // Dont delete the zero frame
873 if (!toDelete.isLocal()) {
874 throw new SecurityException("Attempted to delete remote frame");
875 }
876
[4]877 SaveFrame(toDelete);
878
[97]879 // Copy deleted frames to the DeletedFrames frameset
[4]880 // get the last used frame in the destination frameset
881 final String DELETED_FRAMES = "DeletedFrames";
882 int lastNumber = FrameIO.getLastNumber(DELETED_FRAMES);
883 String framePath;
[8]884 try {
[4]885 // create the new frameset
[298]886 Frame one = FrameIO.CreateFrameset(DELETED_FRAMES, toDelete
887 .getPath());
888 framePath = one.getPath();
[4]889 lastNumber = 0;
[8]890 } catch (Exception e) {
[4]891 Frame zero = FrameIO.LoadFrame(DELETED_FRAMES + "0");
[298]892 framePath = zero.getPath();
[4]893 }
894
895 // get the fill path to determine which file version it is
[298]896 String source = getFrameFullPathName(toDelete.getPath(), toDelete
897 .getName());
[4]898
[80]899 String oldFrameName = toDelete.getName().toLowerCase();
[4]900 // Now save the frame in the new location
901 toDelete.setFrameset(DELETED_FRAMES);
902 toDelete.setFrameNumber(lastNumber + 1);
[298]903 toDelete.setPath(framePath);
[154]904 ForceSaveFrame(toDelete);
[4]905
[1188]906 if (_Cache.containsKey(oldFrameName)) {
[4]907 _Cache.remove(oldFrameName);
[1188]908 }
[4]909
[601]910 File del = new File(source);
911
912 java.io.FileInputStream ff = new java.io.FileInputStream(del);
913 ff.close();
914
915 if (del.delete()) {
[154]916 return toDelete.getName();
917 }
[162]918
[154]919 return null;
[4]920 }
921
922 /**
923 * Creates a new Frame in the given frameset and assigns it the given Title,
924 * which can be null. The newly created Frame is a copy of the frameset's .0
925 * file with the number updated based on the last recorded Frame name in the
926 * frameset's INF file.
927 *
928 * @param frameset
929 * The frameset to create the new Frame in
930 * @param frameTitle
931 * The title to assign to the newly created Frame (can be NULL).
932 * @return The newly created Frame.
933 */
[298]934 public static synchronized Frame CreateFrame(String frameset,
935 String frameTitle, String templateFrame) throws RuntimeException {
[4]936
[72]937 if (!FrameIO.isValidFramesetName(frameset)) {
[86]938 throw new RuntimeException(frameset
939 + " is not a valid frameset name");
[72]940 }
[86]941
[4]942 int next = -1;
943
944 // disable caching of 0 frames
[336]945 // Mike says: Why is caching of 0 frames being disabled?
946 /*
947 * Especially since 0 frames are not event put into the cache in the
948 * frist place
949 */
950 // SuspendCache();
951 /*
952 * Suspending the cache causes infinate loops when trying to load a zero
953 * frame which has a ao which contains an v or av which contains a link
954 * to the ao frame
955 */
956
[72]957 String zeroFrameName = frameset + "0";
958 Frame destFramesetZero = LoadFrame(zeroFrameName);
959 if (destFramesetZero == null) {
960 throw new RuntimeException(zeroFrameName + " could not be found");
961 }
[64]962
[4]963 Frame template = null;
[72]964 if (templateFrame == null) {
[4]965 // load in frame.0
[72]966 template = destFramesetZero;
967 } else {
[4]968 template = LoadFrame(templateFrame);
[72]969 if (template == null) {
970 throw new RuntimeException("LinkTemplate " + templateFrame
971 + " could not be found");
972 }
973 }
[4]974
975 ResumeCache();
976
977 // read the next number from the INF file
978 try {
[307]979 next = ReadINF(destFramesetZero.getPath(), frameset, true);
[4]980 } catch (IOException ioe) {
981 ioe.printStackTrace();
[72]982 throw new RuntimeException("INF file could not be read");
[4]983 }
984
[1102]985 // Remove the old frame from the cache then add the new one
[86]986 // TODO figure out some way that we can put both in the cache
987 _Cache.remove(template.getName().toLowerCase());
[4]988 // set the number and title of the new frame
[86]989 template.setName(frameset, ++next);
[4]990 template.setTitle(frameTitle);
[86]991 // _Cache.put(template.getName().toLowerCase(), template);
[4]992
993 Logger.Log(Logger.SYSTEM, Logger.TDFC, "Creating new frame: "
[80]994 + template.getName() + " from TDFC");
[4]995
[655]996 template.setOwner(UserSettings.UserName.get());
[424]997 template.reset();
[4]998 template.resetDateCreated();
[427]999
[4]1000 for (Item i : template.getItems()) {
[1188]1001 if (ItemUtils.startsWithTag(i, ItemUtils.TAG_PARENT)) {
[4]1002 i.setLink(null);
[1188]1003 }
[4]1004 }
[162]1005
[924]1006 // do auto shrinking of the title IF not in twin frames mode and the title is not centred
[130]1007 Item titleItem = template.getTitleItem();
[4]1008
[1102]1009 if (!DisplayController.isTwinFramesOn() && !Justification.center.equals(((Text)titleItem).getJustification())) {
[130]1010 if ((titleItem.getX() + 1) < template.getNameItem().getX()) {
[1244]1011 int title_item_xr = titleItem.getX() + titleItem.getBoundsWidth(); // should really be '... -1'
1012 int frame_name_xl = template.getNameItem().getX();
1013 if (frame_name_xl < DisplayController.MINIMUM_FRAME_WIDTH) {
1014 frame_name_xl = DisplayController.MINIMUM_FRAME_WIDTH;
1015 }
1016
1017 while ((titleItem.getSize() > Text.MINIMUM_FONT_SIZE) && title_item_xr > frame_name_xl) {
[130]1018 titleItem.setSize(titleItem.getSize() - 1);
[1244]1019 System.err.println("**** shrunk titleItem: " + titleItem + " to font size: " + titleItem.getSize());
[130]1020 }
1021 } else {
1022 System.out.println("Bad title x position: " + titleItem.getX());
1023 }
1024 }
[362]1025 // Assign a width to the title.
[400]1026 titleItem.setRightMargin(template.getNameItem().getX(), true);
[416]1027
[4]1028 return template;
1029 }
1030
1031 public static void DisableCache() {
[1343]1032 //System.err.println(" --------- Cache Disabled --------- ");
[4]1033 _UseCache = false;
1034 }
1035
1036 public static void EnableCache() {
[1343]1037 //System.err.println(" --------- Cache Enabled --------- ");
[4]1038 _UseCache = true;
1039 }
1040
1041 public static void SuspendCache() {
[1343]1042 //System.err.println("SuspendCache: _UseCache" + " was " + _UseCache);
[4]1043 if (_UseCache) {
1044 DisableCache();
1045 _SuspendedCache = true;
1046 } else {
1047 _SuspendedCache = false;
1048 }
[1343]1049 //System.err.println(" Cache is suspended -> " + _SuspendedCache);
1050 //System.err.println(" _UseCache is -> " + _UseCache);
1051 //System.err.println();
[4]1052 }
1053
1054 public static void ResumeCache() {
[1343]1055 //System.err.println("ResumeCache: _UseCache" + " was " + _UseCache);
[4]1056 if (_SuspendedCache) {
1057 EnableCache();
1058 _SuspendedCache = false;
1059 }
[1343]1060 //System.err.println(" Cache is suspended -> " + _SuspendedCache);
1061 //System.err.println(" _UseCache is -> " + _UseCache);
1062 //System.err.println();
[4]1063 }
1064
[1102]1065 public static void RefreshCacheImages()
1066 {
[67]1067 SuspendCache();
[1188]1068 for (Frame frame : _Cache.values()) {
1069 frame.setBuffer(null);
1070 }
[67]1071 ResumeCache();
1072 }
1073
[4]1074 /**
1075 * Creates a new frameset using the given name. This includes creating a new
1076 * subdirectory in the <code>FRAME_PATH</code> directory, Copying over the
1077 * default.0 frame from the default frameset, copying the .0 Frame to make a
1078 * .1 Frame, and creating the frameset's INF file.
1079 *
1080 * @param frameset
1081 * The name of the Frameset to create
1082 * @return The first Frame of the new Frameset (Frame.1)
1083 */
[8]1084 public static Frame CreateFrameset(String frameset, String path)
1085 throws Exception {
[7]1086 return CreateFrameset(frameset, path, false);
[4]1087 }
1088
1089 /**
1090 * Tests if the given String is a 'proper' framename, that is, the String
1091 * must begin with a character, end with a number with 0 or more letters and
[24]1092 * numbers in between.
[4]1093 *
1094 * @param frameName
1095 * The String to test for validity as a frame name
1096 * @return True if the given framename is proper, false otherwise.
1097 */
1098 public static boolean isValidFrameName(String frameName) {
1099
[1188]1100 if (frameName == null || frameName.length() < 2) {
[4]1101 return false;
[1188]1102 }
[4]1103
[24]1104 int lastCharIndex = frameName.length() - 1;
[4]1105 // String must begin with a letter and end with a digit
[24]1106 if (!Character.isLetter(frameName.charAt(0))
[1188]1107 || !Character.isDigit(frameName.charAt(lastCharIndex))) {
[4]1108 return false;
[1188]1109 }
[4]1110
[7]1111 // All the characters between first and last must be letters
[24]1112 // or digits
1113 for (int i = 1; i < lastCharIndex; i++) {
[1188]1114 if (!isValidFrameNameChar(frameName.charAt(i))) {
[24]1115 return false;
[1188]1116 }
[4]1117 }
1118 return true;
1119 }
1120
[427]1121 private static boolean isValidFrameNameChar(char c) {
[1242]1122 return c == '-' || c == '.' || Character.isLetterOrDigit(c);
[427]1123 }
1124
[4]1125 /**
1126 * Saves the given Frame to disk in the corresponding frameset directory.
1127 * This is the same as calling SaveFrame(toSave, true)
1128 *
1129 * @param toSave
[105]1130 * The Frame to save to disk
[4]1131 */
1132 public static String SaveFrame(Frame toSave) {
1133 return SaveFrame(toSave, true);
1134 }
1135
[376]1136 /**
1137 * Saves a frame.
[416]1138 *
1139 * @param toSave
1140 * the frame to save
1141 * @param inc
1142 * true if the frames counter should be incremented
[376]1143 * @return the text content of the frame
1144 */
[67]1145 public static String SaveFrame(Frame toSave, boolean inc) {
1146 return SaveFrame(toSave, inc, true);
1147 }
1148
[4]1149 /**
1150 * Saves the given Frame to disk in the corresponding frameset directory, if
1151 * inc is true then the saved frames counter is incremented, otherwise it is
1152 * untouched.
1153 *
1154 * @param toSave
[1242]1155 * The Frame to save to disk
[4]1156 * @param inc
[1242]1157 * True if the saved frames counter should be incremented, false otherwise.
[67]1158 * @param checkBackup
[1242]1159 * True if the frame should be checked for the back up tag
[4]1160 */
[1242]1161 public static String SaveFrame(Frame toSave, boolean inc, boolean checkBackup) {
[162]1162 // TODO When loading a frame maybe append onto the event history too-
[1232]1163 // with a break to indicate the end of a session
[1242]1164
[162]1165 if (toSave == null || !toSave.hasChanged() || toSave.isSaved()) {
[7]1166 return "";
[105]1167 }
[4]1168
[86]1169 // Dont save if the frame is protected and it exists
[162]1170 if (checkBackup && toSave.isReadOnly()) {
[86]1171 _Cache.remove(toSave.getName().toLowerCase());
1172 return "";
1173 }
1174
[416]1175 /* Dont save the frame if it has the noSave tag */
1176 if (toSave.hasAnnotation("nosave")) {
[1200]1177 Actions.LegacyPerformActionCatchErrors(toSave, null, "Restore");
[416]1178 return "";
1179 }
1180
[298]1181 // Save frame that is not local through the Networking classes
[306]1182 if (!toSave.isLocal()) {
1183 return FrameShare.getInstance().saveFrame(toSave);
1184 }
[298]1185
[416]1186 /* Format the frame if it has the autoFormat tag */
1187 if (toSave.hasAnnotation("autoformat")) {
[1200]1188 Actions.LegacyPerformActionCatchErrors(toSave, null, "Format");
[415]1189 }
[416]1190
[298]1191 /**
1192 * Get the full path only to determine which format to use for saving
1193 * the frame. At this stage use Exp format for saving Exp frames only.
1194 * Later this will be changed so that KMS frames will be updated to the
1195 * Exp format.
1196 */
1197 String fullPath = getFrameFullPathName(toSave.getPath(), toSave
1198 .getName());
1199
[67]1200 // Check if the frame exists
1201 if (checkBackup && fullPath == null) {
1202 // The first time a frame with the backup tag is saved, dont back it
1203 // up
1204 checkBackup = false;
1205 }
[601]1206
1207 FrameWriter writer = null;
[589]1208 int savedVersion;
[4]1209 try {
1210 // if its a new frame or an existing Exp frame...
[1242]1211 if (fullPath == null || fullPath.endsWith(ExpReader.EXTENTION)) {
[1283]1212 if (toSave.getNumber() != AuthenticatorBrowser.CREDENTIALS_FRAME &&
[1227]1213 toSave.getEncryptionLabel() != null) {
1214 writer = new EncryptedExpWriter(toSave.getEncryptionLabel());
[1219]1215 savedVersion = EncryptedExpReader.getVersion(fullPath);
1216 } else {
1217 writer = new ExpWriter();
1218 savedVersion = ExpReader.getVersion(fullPath);
1219 }
[1242]1220
1221 // Is the file this would be saved to a redirect?
1222 String redirectTo = ExpReader.redirectTo(fullPath);
1223 if (redirectTo != null) {
1224 String redirectedPath = toSave.getFramePathReal();
1225 writer.setOutputLocation(redirectedPath);
1226 }
1227
[601]1228 } else {
1229 writer = new KMSWriter();
1230 savedVersion = KMSReader.getVersion(fullPath);
1231 }
[1232]1232
[348]1233 // Check if the frame doesnt exist
[416]1234 // if (savedVersion < 0) {
1235 // /*
1236 // * This will happen if the user has two Expeditee's running at
1237 // * once and closes the first. When the second one closes the
1238 // * messages directory will have been deleted.
1239 // */
1240 // MessageBay
1241 // .errorMessage("Could not save frame that does not exist: "
1242 // + toSave.getName());
1243 // return null;
1244 // }
[348]1245
[67]1246 // Check if we are trying to save an out of date version
[1342]1247 // Q: Why do we ignore version conflicts if the saved version is zero?
1248 // A: Sometimes a Frame object in memory with a specified path is not 'connected'
1249 // to the file found at that specified path yet. This occurs if a frame object
1250 // has been created, its path assigned and saved to disk; with the intention
1251 // discarding this Frame object and later saving a different Frame object to
1252 // that File. One example of this is when @old frames are created.
1253 // The new Frame object that is created and saved only to be discarded, has a
1254 // version number of zero.
1255 // Therefore, if the file created from the discarded Frame has its modification
1256 // date compared to the modification date on the Frame object that will eventually
1257 // be used to overwrite that file, it causes a false positive conflict. Checking
1258 // for the zero version number fixes this.
[1219]1259 String framesetName = toSave.getFramesetName();
1260 boolean isBayFrameset =
1261 framesetName.equalsIgnoreCase(MessageBay.MESSAGES_FRAMESET_NAME) ||
1262 framesetName.equalsIgnoreCase(MailBay.EXPEDITEE_MAIL_FRAMESET_NAME);
[1337]1263 long fileLastModify = fullPath != null ? new File(fullPath).lastModified() : 0;
[1242]1264 long frameLastModify = toSave.getLastModifyPrecise();
1265 boolean fileModifyConflict = fileLastModify > frameLastModify && !isBayFrameset;
1266 boolean versionConflict = savedVersion > toSave.getVersion() && !isBayFrameset;
[1337]1267 if ((fileModifyConflict || versionConflict) && savedVersion > 0) {
[67]1268 // remove this frame from the cache if it is there
1269 // This will make sure links to the original are set correctly
[80]1270 _Cache.remove(toSave.getName().toLowerCase());
[298]1271 int nextnum = ReadINF(toSave.getPath(), toSave
[307]1272 .getFramesetName(), false) + 1;
[67]1273 SuspendCache();
[80]1274 Frame original = LoadFrame(toSave.getName());
[67]1275 toSave.setFrameNumber(nextnum);
1276 ResumeCache();
1277 // Put the modified version in the cache
[108]1278 addToCache(toSave);
[67]1279 // Show the messages alerting the user
1280 Text originalMessage = new Text(-1);
[121]1281 originalMessage.setColor(MessageBay.ERROR_COLOR);
[1242]1282 StringBuilder message = new StringBuilder(original.getName()
1283 + " was updated by another user. ");
1284 if (fileModifyConflict) {
1285 message.append("{ File modify conflict }");
[1325]1286 System.err.println("Thread name: " + Thread.currentThread().getName());
1287 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
1288 for (StackTraceElement ste: stackTrace) {
1289 System.err.println(ste.toString());
1290 }
[1242]1291 }
1292 if (versionConflict) {
1293 message.append("{ Version conflict }");
1294 }
1295 originalMessage.setText(message.toString());
[80]1296 originalMessage.setLink(original.getName());
[67]1297 Text yourMessage = new Text(-1);
[121]1298 yourMessage.setColor(MessageBay.ERROR_COLOR);
[67]1299 yourMessage.setText("Your version was renamed "
[80]1300 + toSave.getName());
1301 yourMessage.setLink(toSave.getName());
[121]1302 MessageBay.displayMessage(originalMessage);
1303 MessageBay.displayMessage(yourMessage);
[1242]1304 EcosystemManager.getMiscManager().beep();
[67]1305 } else if (checkBackup
[70]1306 && ItemUtils.ContainsExactTag(toSave.getItems(),
[4]1307 ItemUtils.TAG_BACKUP)) {
1308 SuspendCache();
[427]1309 String oldFramesetName = toSave.getFramesetName() + "-old";
1310
[80]1311 Frame original = LoadFrame(toSave.getName());
[1188]1312 if (original == null) {
[4]1313 original = toSave;
[1188]1314 }
[80]1315 int orignum = original.getNumber();
[4]1316
[427]1317 int nextnum = -1;
1318 try {
1319 nextnum = ReadINF(toSave.getPath(), oldFramesetName, false) + 1;
1320 } catch (RuntimeException e) {
1321 try {
1322 CreateFrameset(oldFramesetName, toSave.getPath());
1323 nextnum = 1;
1324 } catch (Exception e1) {
1325 e1.printStackTrace();
1326 }
1327 }
[429]1328
[427]1329 if (nextnum > 0) {
1330 original.setFrameset(oldFramesetName);
1331 original.setFrameNumber(nextnum);
[454]1332 original.setPermission(new PermissionPair(UserAppliedPermission.copy));
[427]1333 original.change();
1334 SaveFrame(original, false, false);
1335 }
[4]1336
[70]1337 Item i = ItemUtils.FindExactTag(toSave.getItems(),
[4]1338 ItemUtils.TAG_BACKUP);
[80]1339 i.setLink(original.getName());
[4]1340 toSave.setFrameNumber(orignum);
1341 ResumeCache();
1342 }
[105]1343
[162]1344 // int oldMode = FrameGraphics.getMode();
1345 // if (oldMode != FrameGraphics.MODE_XRAY)
1346 // FrameGraphics.setMode(FrameGraphics.MODE_XRAY, true);
[1242]1347
[4]1348 writer.writeFrame(toSave);
[162]1349 // FrameGraphics.setMode(oldMode, true);
[4]1350 toSave.setSaved();
[1242]1351
1352 // Update general stuff about frame
1353 setSavedProperties(toSave);
1354
[105]1355 if (inc) {
[80]1356 SessionStats.SavedFrame(toSave.getName());
[105]1357 }
[4]1358
1359 // avoid out-of-sync frames (when in TwinFrames mode)
[1188]1360 if (_Cache.containsKey(toSave.getName().toLowerCase())) {
[108]1361 addToCache(toSave);
[1188]1362 }
[4]1363
[86]1364 Logger.Log(Logger.SYSTEM, Logger.SAVE, "Saving " + toSave.getName()
1365 + " to disk.");
[4]1366
1367 // check that the INF file is not out of date
[307]1368 int last = ReadINF(toSave.getPath(), toSave.getFramesetName(),
1369 false);
[1188]1370 if (last <= toSave.getNumber()) {
[298]1371 WriteINF(toSave.getPath(), toSave.getFramesetName(), toSave
[80]1372 .getName());
[1188]1373 }
[4]1374
1375 // check if this was the profile frame (and thus needs
1376 // re-parsing)
[95]1377 if (isProfileFrame(toSave)) {
[1242]1378 Frame profile = FrameIO.LoadFrame(toSave.getFramesetName() + "1");
[97]1379 assert (profile != null);
[95]1380 FrameUtils.ParseProfile(profile);
[4]1381 }
1382 } catch (IOException ioe) {
[311]1383 ioe.printStackTrace();
[95]1384 ioe.getStackTrace();
[4]1385 Logger.Log(ioe);
[7]1386 return null;
[4]1387 }
[1242]1388 toSave.notifyObservers(false);
[4]1389
1390 return writer.getFileContents();
1391 }
1392
[95]1393 /**
[997]1394 * Saves the given Frame to disk in the corresponding frameset directory as a RESTORE, if
1395 * inc is true then the saved frames counter is incremented, otherwise it is
1396 * untouched.
1397 *
1398 * @param toSave
1399 * The Frame to save to disk as the DEFAULT COPY
1400 * @param inc
1401 * True if the saved frames counter should be incremented, false
1402 * otherwise.
1403 * @param checkBackup
1404 * True if the frame should be checked for the back up tag
1405 */
1406 public static String SaveFrameAsRestore(Frame toSave, boolean inc,
1407 boolean checkBackup) {
1408
1409 String sf = SaveFrame(toSave, inc, checkBackup);
1410 String fullPath = getFrameFullPathName(toSave.getPath(), toSave
1411 .getName());
1412 //System.out.println(fullPath);
1413 String restoreVersion = fullPath + ".restore";
1414 File source = new File(fullPath);
1415 File dest = new File(restoreVersion);
1416
1417 FileChannel inputChannel = null;
1418 FileChannel outputChannel = null;
1419
1420 try{
1421 FileInputStream source_fis = new FileInputStream(source);
1422 inputChannel = source_fis.getChannel();
1423
1424 FileOutputStream dest_fos = new FileOutputStream(dest);
1425 outputChannel = dest_fos.getChannel();
1426
1427 outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
1428 inputChannel.close();
1429 outputChannel.close();
1430 source_fis.close();
1431 dest_fos.close();
1432 }
1433 catch(Exception e){
1434 e.printStackTrace();
1435 }
1436
1437 return sf;
1438 }
1439
1440 /**
[108]1441 * @param toAdd
1442 */
1443 public static void addToCache(Frame toAdd) {
1444 _Cache.put(toAdd.getName().toLowerCase(), toAdd);
1445 }
[1242]1446
1447 public static void ClearCache() {
1448 _Cache.clear();
1449 }
[108]1450
1451 /**
[95]1452 * Checks if a frame is in the current user profile frameset.
[97]1453 *
1454 * @param toCheck
1455 * the frame to check
[95]1456 * @return true if the frame is in the current user profile frameset
1457 */
[1102]1458 public static boolean isProfileFrame(Frame toCheck)
1459 {
[1188]1460 if (toCheck.getNumber() == 0) {
1461 return false;
1462 }
[1102]1463
[348]1464 return toCheck.getPath().equals(PROFILE_PATH);
[416]1465 // return toCheck.getFramesetName()
1466 // .equalsIgnoreCase(UserSettings.ProfileName);
[95]1467 }
1468
[1102]1469 public static Frame LoadProfile(String userName)
1470 {
[1200]1471 final String profilesLoc = System.getProperty("profiles.loc");
1472 if (profilesLoc != null) {
1473 return LoadFrame(userName + "1", profilesLoc);
1474 } else {
1475 return LoadFrame(userName + "1");
1476 }
[4]1477 }
1478
[1270]1479 public static Frame CreateNewProfile(String username, Map<String, Setting> initialSettings, Map<String, Consumer<Frame>> toNotifyOnSet) throws InvalidFramesetNameException, ExistingFramesetException {
[23]1480 Frame profile = CreateFrameset(username, PROFILE_PATH, true);
[1350]1481 if (profile != null) {
1482 FrameUtils.CreateDefaultProfile(username, profile, initialSettings, toNotifyOnSet);
1483 } else {
1484 System.err.println("An error occured while attempting to create the profile named: " + username);
1485 System.err.println("Unable to proceed.");
1486 System.exit(1);
1487 }
[4]1488 return profile;
1489 }
1490
1491 /**
1492 * Reads the INF file that corresponds to the given Frame name
1493 *
1494 * @param framename
1495 * The Frame to lookup the INF file for
1496 * @throws IOException
1497 * Any exceptions encountered by the BufferedReader used to read
1498 * the INF.
1499 */
[307]1500 public static int ReadINF(String path, String frameset, boolean update)
1501 throws IOException {
[4]1502 assert (!frameset.endsWith("."));
[307]1503 try {
1504 // read INF
1505 BufferedReader reader;
1506 try {
1507 // Check on the local drive
1508 reader = new BufferedReader(new FileReader(path
1509 + frameset.toLowerCase() + File.separator
1510 + INF_FILENAME));
1511 } catch (Exception e) {
1512 reader = new BufferedReader(new FileReader(path
1513 + frameset.toLowerCase() + File.separator
1514 + frameset.toLowerCase() + ".inf"));
1515 }
1516 String inf = reader.readLine();
1517 reader.close();
[4]1518
[307]1519 int next = Conversion.getFrameNumber(inf);
1520 // update INF file
1521 if (update) {
1522 try {
1523 WriteINF(path, frameset, frameset + (next + 1));
1524 } catch (IOException ioe) {
1525 ioe.printStackTrace();
1526 Logger.Log(ioe);
1527 }
1528 }
1529 return next;
[4]1530 } catch (Exception e) {
1531 }
1532
[307]1533 // Check peers
1534 return FrameShare.getInstance().getInfNumber(path, frameset, update);
[4]1535 }
1536
1537 /**
1538 * Writes the given String out to the INF file corresponding to the current
1539 * frameset.
1540 *
1541 * @param toWrite
1542 * The String to write to the file.
1543 * @throws IOException
1544 * Any exception encountered by the BufferedWriter.
1545 */
[307]1546 public static void WriteINF(String path, String frameset, String frameName)
[4]1547 throws IOException {
[307]1548 try {
1549 assert (!frameset.endsWith("."));
[4]1550
[307]1551 path += frameset.toLowerCase() + File.separator + INF_FILENAME;
[4]1552
[307]1553 BufferedWriter writer = new BufferedWriter(new FileWriter(path));
1554 writer.write(frameName);
1555 writer.close();
1556 } catch (Exception e) {
1557
1558 }
[4]1559 }
1560
1561 public static boolean FrameIsCached(String name) {
1562 return _Cache.containsKey(name);
1563 }
[298]1564
[206]1565 /**
1566 * Gets a frame from the cache.
1567 *
1568 * @param name
[298]1569 * The frame to get from the cache
[206]1570 *
[298]1571 * @return The frame from cache. Null if not cached.
[206]1572 */
1573 public static Frame FrameFromCache(String name) {
1574 return _Cache.get(name);
1575 }
[4]1576
[12]1577 public static String ConvertToValidFramesetName(String toValidate) {
[64]1578 assert (toValidate != null && toValidate.length() > 0);
1579
[24]1580 StringBuffer result = new StringBuffer();
[4]1581
[64]1582 if (Character.isDigit(toValidate.charAt(0))) {
[24]1583 result.append(FRAME_NAME_LAST_CHAR);
1584 }
[64]1585
[24]1586 boolean capital = false;
[64]1587 for (int i = 0; i < toValidate.length()
1588 && result.length() < MAX_NAME_LENGTH; i++) {
[4]1589 char cur = toValidate.charAt(i);
1590
1591 // capitalize all characters after spaces
[12]1592 if (Character.isLetterOrDigit(cur)) {
[4]1593 if (capital) {
1594 capital = false;
[24]1595 result.append(Character.toUpperCase(cur));
[1188]1596 } else {
[24]1597 result.append(cur);
[1188]1598 }
[12]1599 } else {
1600 capital = true;
[4]1601 }
1602 }
[24]1603 assert (result.length() > 0);
1604 int lastCharIndex = result.length() - 1;
[64]1605 if (!Character.isLetter(result.charAt(lastCharIndex))) {
[1188]1606 if (lastCharIndex == MAX_NAME_LENGTH - 1) {
[64]1607 result.setCharAt(lastCharIndex, FRAME_NAME_LAST_CHAR);
[1188]1608 } else {
[24]1609 result.append(FRAME_NAME_LAST_CHAR);
[1188]1610 }
[24]1611 }
[64]1612
[72]1613 assert (isValidFramesetName(result.toString()));
[24]1614 return result.toString();
[4]1615 }
1616
[72]1617 public static Frame CreateNewFrame(Item linker) throws RuntimeException {
[80]1618 String title = linker.getName();
[4]1619
[80]1620 String templateLink = linker.getAbsoluteLinkTemplate();
1621 String framesetLink = linker.getAbsoluteLinkFrameset();
[1102]1622 String frameset = (framesetLink != null ? framesetLink : DisplayController
[72]1623 .getCurrentFrame().getFramesetName());
[4]1624
1625 Frame newFrame = FrameIO.CreateFrame(frameset, title, templateLink);
1626 return newFrame;
1627 }
[734]1628
1629 public static Frame CreateNewFrame(Item linker, OnNewFrameAction action) throws RuntimeException {
1630 Frame newFrame = FrameIO.CreateNewFrame(linker);
[1188]1631 if(action != null) {
1632 action.exec(linker, newFrame);
1633 }
[734]1634 return newFrame;
1635 }
[4]1636
1637 /**
1638 * Creates a new Frameset on disk, including a .0, .1, and .inf files. The
1639 * Default.0 frame is copied to make the initial .0 and .1 Frames
1640 *
1641 * @param name
1642 * The Frameset name to use
1643 * @return The name of the first Frame in the newly created Frameset (the .1
1644 * frame)
1645 */
[8]1646 public static Frame CreateNewFrameset(String name) throws Exception {
[1102]1647 String path = DisplayController.getCurrentFrame().getPath();
[4]1648
1649 // if current frameset is profile directory change it to framesets
1650 if (path.equals(FrameIO.PROFILE_PATH)) {
1651 path = FrameIO.FRAME_PATH;
1652 }
1653
[429]1654 Frame newFrame = FrameIO.CreateFrameset(name, path);
1655
1656 if (newFrame == null) {
1657 // Cant create directories if the path is readonly or there is no
1658 // space available
1659 newFrame = FrameIO.CreateFrameset(name, FrameIO.FRAME_PATH);
1660 }
1661
1662 if (newFrame == null) {
1663 // TODO handle running out of disk space here
1664 }
1665
1666 return newFrame;
[4]1667 }
1668
1669 /**
1670 *
1671 * @param frameset
1672 * @return
1673 */
1674 public static int getLastNumber(String frameset) { // Rob thinks it might
1675 // have been
1676 // GetHighestNumExFrame
1677 // TODO minimise the number of frames being read in!!
1678 int num = -1;
1679
1680 Frame zero = LoadFrame(frameset + "0");
1681
1682 // the frameset does not exist (or has no 0 frame)
[1188]1683 if (zero == null) {
[4]1684 return -1;
[1188]1685 }
[4]1686
1687 try {
[307]1688 num = ReadINF(zero.getPath(), frameset, false);
[4]1689 } catch (IOException e) {
1690 // TODO Auto-generated catch block
1691 // e.printStackTrace();
1692 }
1693
1694 /*
1695 * Michael doesnt think the code below is really needed... it will just
1696 * slow things down when we are reading frames over a network***** for (;
1697 * num >= 0; num--) { System.out.println("This code is loading frames to
1698 * find the highest existing frame..."); if (LoadFrame(frameset + num) !=
1699 * null) break; }
1700 */
1701
1702 return num;
1703 }
1704
[97]1705 /**
1706 * Checks if a given frameset is accessable.
1707 *
1708 * @param framesetName
1709 * @return
1710 */
[1280]1711 public static boolean canAccessFrameset(String framesetName) {
[97]1712 framesetName = framesetName.toLowerCase();
[1244]1713 for (String path : FolderSettings.FrameDirs.getAbsoluteDirs()) {
[1280]1714 if (canAccessFrameset(framesetName, Paths.get(path))) {
[97]1715 return true;
[1188]1716 }
[97]1717 }
1718 return false;
[7]1719 }
[1280]1720
1721 public static boolean canAccessFrameset(String framesetName, Path path) {
1722 File framesetDir = path.resolve(framesetName).toFile();
1723 if (framesetDir.exists() && framesetDir.isDirectory()) {
1724 return true;
1725 } else {
1726 return false;
1727 }
1728 }
[7]1729
[1242]1730 public static Frame CreateFrameset(String frameset, String path, boolean recreate) throws InvalidFramesetNameException, ExistingFramesetException {
[7]1731 String conversion = frameset + " --> ";
1732
[1188]1733 if (!isValidFramesetName(frameset)) {
[1242]1734 throw new InvalidFramesetNameException(frameset);
[1188]1735 }
[24]1736
[97]1737 if (!recreate && FrameIO.canAccessFrameset(frameset)) {
[8]1738 throw new ExistingFramesetException(frameset);
[7]1739 }
1740
1741 conversion += frameset;
1742 Logger.Log(Logger.SYSTEM, Logger.NEW_FRAMESET, "Frameset Name: "
1743 + conversion);
1744 conversion = frameset;
1745
1746 /**
1747 * TODO: Update this to exclude any\all invalid filename characters
1748 */
1749 // ignore annotation character
[1188]1750 if (frameset.startsWith("@")) {
[7]1751 frameset = frameset.substring(1);
[1188]1752 }
[7]1753
1754 conversion += " --> " + frameset;
1755 Logger.Log(Logger.SYSTEM, Logger.NEW_FRAMESET, "Name: " + conversion);
1756
1757 // create the new Frameset directory
1758 File dir = new File(path + frameset.toLowerCase() + File.separator);
1759
[429]1760 // If the directory doesnt already exist then create it...
1761 if (!dir.exists()) {
1762 if (!dir.mkdirs()) {
[1349]1763 /*
1764 * If the directory does not exist, but could not be created then there is something wrong.
1765 * Prior to May 2019 the only known reason for this was because the disk could be full.
1766 * Since then, we have discovered that null can occur when working with Google file stream.
1767 * A directory can return false to an existence check, but then fail to create the directory
[1354]1768 * due to it already existing because of sync issues. While we have not confirmed, this may
[1349]1769 * be the case with other network drives as well.
1770 */
[1354]1771 System.err.println("Failed to create directory for frameset: " + frameset);
[429]1772 return null;
1773 }
1774 }
[7]1775
1776 // create the new INF file
1777 try {
[25]1778 WriteINF(path, frameset, frameset + '1');
[7]1779 } catch (IOException ioe) {
1780 ioe.printStackTrace();
1781 Logger.Log(ioe);
1782 }
1783
1784 SuspendCache();
1785 // copy the default .0 and .1 files
[98]1786 Frame base = null;
[7]1787 try {
[778]1788 base = LoadFrame(TemplateSettings.DefaultFrame.get());
[7]1789 } catch (Exception e) {
[98]1790 }
1791 // The frame may not be accessed for various reasons... in all these
1792 // cases just create a new one
1793 if (base == null) {
[7]1794 base = new Frame();
1795 }
[98]1796
[7]1797 ResumeCache();
1798
[424]1799 base.reset();
[7]1800 base.resetDateCreated();
1801 base.setFrameset(frameset);
1802 base.setFrameNumber(0);
[24]1803 base.setTitle(base.getFramesetName() + "0");
[298]1804 base.setPath(path);
[7]1805 base.change();
[655]1806 base.setOwner(UserSettings.UserName.get());
[7]1807 SaveFrame(base, false);
1808
[424]1809 base.reset();
[7]1810 base.resetDateCreated();
1811 base.setFrameNumber(1);
1812 base.setTitle(frameset);
1813 base.change();
[655]1814 base.setOwner(UserSettings.UserName.get());
[7]1815 SaveFrame(base, true);
[1242]1816
1817 FrameIO.setSavedProperties(base);
[7]1818
[1102]1819 Logger.Log(Logger.SYSTEM, Logger.NEW_FRAMESET, "Created new frameset: " + frameset);
[7]1820
1821 return base;
[24]1822 }
1823
1824 /**
1825 * Tests if a frameset name is valid. That is it must begin and end with a
1826 * letter and contain only letters and digits in between.
1827 *
[64]1828 * @param frameset
1829 * the name to be tested
[24]1830 * @return true if the frameset name is valid
1831 */
[72]1832 public static boolean isValidFramesetName(String frameset) {
[24]1833 if (frameset == null) {
1834 return false;
1835 }
[64]1836
[24]1837 int nameLength = frameset.length();
[64]1838 if (frameset.length() <= 0 || nameLength > MAX_NAME_LENGTH) {
[24]1839 return false;
1840 }
[64]1841
1842 int lastCharIndex = nameLength - 1;
1843
1844 if (!Character.isLetter(frameset.charAt(0))
[1188]1845 || !Character.isLetter(frameset.charAt(lastCharIndex))) {
[24]1846 return false;
[1188]1847 }
[24]1848
1849 for (int i = 1; i < lastCharIndex; i++) {
[427]1850 if (!isValidFrameNameChar(frameset.charAt(i))) {
[13]1851 return false;
1852 }
1853 }
1854 return true;
[7]1855 }
1856
[298]1857 public static boolean deleteFrameset(String framesetName) {
[1293]1858 return moveFrameset(framesetName, FrameIO.TRASH_PATH, true);
[298]1859 }
1860
[1293]1861 public static boolean moveFrameset(String framesetName, String destinationFolder, boolean override) {
[1188]1862 if (!FrameIO.canAccessFrameset(framesetName)) {
[7]1863 return false;
[1188]1864 }
[416]1865 // Clear the cache
[362]1866 _Cache.clear();
[416]1867
[64]1868 // Search all the available directories for the directory
[1244]1869 for (String path : FolderSettings.FrameDirs.getAbsoluteDirs()) {
[1293]1870 return moveFrameset(framesetName, path, destinationFolder, override);
[1280]1871 }
1872 return false;
1873 }
1874
[1293]1875 public static boolean moveFrameset(String framesetName, String path, String destinationFolder, boolean override) {
[1280]1876 String source = path + framesetName.toLowerCase() + File.separator;
1877 File framesetDirectory = new File(source);
1878 // Once we have found the directory move it
1879 if (framesetDirectory.exists()) {
1880 String destPath = destinationFolder
1881 + framesetName.toLowerCase();
1882 int copyNumber = 1;
1883 File dest = new File(destPath + File.separator);
1884 // Create the destination folder if it doesnt already exist
1885 if (!dest.getParentFile().exists()) {
1886 dest.mkdirs();
1887 }
1888 // If a frameset with the same name is already in the
1889 // destination add
1890 // a number to the end
[1293]1891 while (dest.exists() && !override) {
[1280]1892 dest = new File(destPath + ++copyNumber + File.separator);
1893 }
1894 try {
[1293]1895 moveFileTree(framesetDirectory.toPath(), dest.toPath());
[1280]1896 } catch (IOException e) {
1897 e.printStackTrace();
1898 return false;
1899 }
1900
1901 for (File f : framesetDirectory.listFiles()) {
1902 if (!f.delete()) {
1903 return false;
[1188]1904 }
[7]1905 }
[1280]1906 if (!framesetDirectory.delete()) {
1907 return false;
1908 }
1909 return true;
1910 } else {
1911 return false;
[7]1912 }
1913 }
1914
1915 public static boolean CopyFrameset(String framesetToCopy,
1916 String copiedFrameset) throws Exception {
[1188]1917 if (!FrameIO.canAccessFrameset(framesetToCopy)) {
[7]1918 return false;
[1188]1919 }
1920 if (FrameIO.canAccessFrameset(copiedFrameset)) {
[7]1921 return false;
[1188]1922 }
[7]1923 // search through all the directories to find the frameset we are
1924 // copying
[1244]1925 for (String path : FolderSettings.FrameDirs.getAbsoluteDirs()) {
[7]1926 String source = path + framesetToCopy.toLowerCase()
1927 + File.separator;
1928 File framesetDirectory = new File(source);
1929 if (framesetDirectory.exists()) {
1930 // copy the frameset
1931 File copyFramesetDirectory = new File(path
1932 + copiedFrameset.toLowerCase() + File.separator);
[1188]1933 if (!copyFramesetDirectory.mkdirs()) {
[7]1934 return false;
[1188]1935 }
[7]1936 // copy each of the frames
1937 for (File f : framesetDirectory.listFiles()) {
[97]1938 // Ignore hidden files
[1188]1939 if (f.getName().charAt(0) == '.') {
[97]1940 continue;
[1188]1941 }
[7]1942 String copyPath = copyFramesetDirectory.getAbsolutePath()
1943 + File.separator + f.getName();
1944 FrameIO.copyFile(f.getAbsolutePath(), copyPath);
1945 }
1946 return true;
1947 }
1948 }
1949 return false;
1950 }
1951
[80]1952 /**
1953 * Copies a file from one location to another.
[86]1954 *
[80]1955 * @param existingFile
1956 * @param newFileName
1957 * @throws Exception
1958 */
[7]1959 public static void copyFile(String existingFile, String newFileName)
[1105]1960 throws IOException {
[7]1961 FileInputStream is = new FileInputStream(existingFile);
1962 FileOutputStream os = new FileOutputStream(newFileName, false);
1963 int data;
1964 while ((data = is.read()) != -1) {
1965 os.write(data);
1966 }
1967 os.flush();
1968 os.close();
1969 is.close();
1970 }
1971
1972 /**
1973 * Saves a frame regardless of whether or not the frame is marked as having
1974 * been changed.
1975 *
1976 * @param frame
1977 * the frame to save
1978 * @return the contents of the frame or null if it could not be saved
1979 */
1980 public static String ForceSaveFrame(Frame frame) {
1981 frame.change();
1982 return SaveFrame(frame, false);
1983 }
1984
[72]1985 public static boolean isValidLink(String frameName) {
[86]1986 return frameName == null || isPositiveInteger(frameName)
1987 || isValidFrameName(frameName);
[72]1988 }
1989
[306]1990 public static void SavePublicFrame(String peerName, String frameName,
1991 int version, BufferedReader packetContents) {
1992 // TODO handle versioning - add version to the header
1993 // Remote user uploads version based on an old version
1994
1995 // Remove it from the cache so that next time it is loaded we get the up
1996 // todate version
1997 _Cache.remove(frameName.toLowerCase());
1998
1999 // Save to file
2000 String filename = PUBLIC_PATH + Conversion.getFramesetName(frameName)
2001 + File.separator + Conversion.getFrameNumber(frameName)
[601]2002 + ExpReader.EXTENTION;
[306]2003
2004 File file = new File(filename);
2005 // Ensure the file exists
2006 if (file.exists()) {
2007 // Check the versions
[601]2008 int savedVersion = ExpReader.getVersion(filename);
[306]2009
2010 if (savedVersion > version) {
2011 // remove this frame from the cache if it is there
2012 // This will make sure links to the original are set correctly
2013 // _Cache.remove(frameName.toLowerCase());
2014
2015 int nextNum = 0;
2016 try {
2017 nextNum = ReadINF(PUBLIC_PATH, Conversion
[307]2018 .getFramesetName(frameName), false) + 1;
[306]2019 } catch (IOException e) {
2020 e.printStackTrace();
2021 }
2022
2023 String newName = Conversion.getFramesetName(frameName)
2024 + nextNum;
2025 filename = PUBLIC_PATH + Conversion.getFramesetName(frameName)
[601]2026 + File.separator + nextNum + ExpReader.EXTENTION;
[306]2027
2028 // Show the messages alerting the user
2029 Text originalMessage = new Text(-1);
2030 originalMessage.setColor(MessageBay.ERROR_COLOR);
2031 originalMessage.setText(frameName + " was edited by "
2032 + peerName);
2033 originalMessage.setLink(frameName);
2034 Text yourMessage = new Text(-1);
2035 yourMessage.setColor(MessageBay.ERROR_COLOR);
2036 yourMessage.setText("Their version was renamed " + newName);
2037 yourMessage.setLink(newName);
2038 MessageBay.displayMessage(originalMessage);
2039 MessageBay.displayMessage(yourMessage);
2040
2041 Frame editedFrame = FrameIO.LoadFrame(frameName);
2042
2043 FrameShare.getInstance().sendMessage(
2044 frameName + " was recently edited by "
2045 + editedFrame.getLastModifyUser(), peerName);
2046 FrameShare.getInstance().sendMessage(
2047 "Your version was renamed " + newName, peerName);
2048 }
[307]2049 }
[306]2050
[307]2051 // Save the new version
2052 try {
[348]2053 // FileWriter fw = new FileWriter(file);
2054
2055 // Open an Output Stream Writer to set encoding
2056 OutputStream fout = new FileOutputStream(file);
2057 OutputStream bout = new BufferedOutputStream(fout);
2058 Writer fw = new OutputStreamWriter(bout, "UTF-8");
2059
[307]2060 String nextLine = null;
2061 while ((nextLine = packetContents.readLine()) != null) {
2062 fw.write(nextLine + '\n');
[306]2063 }
[307]2064 fw.flush();
2065 fw.close();
2066 MessageBay.displayMessage("Saved remote frame: " + frameName);
2067 } catch (IOException e) {
2068 MessageBay.errorMessage("Error remote saving " + frameName + ": "
2069 + e.getMessage());
2070 e.printStackTrace();
[306]2071 }
2072 }
2073
2074 public static void setSavedProperties(Frame toSave) {
[1229]2075 toSave.setLastModifyDate(Formatter.getDateTime(), System.currentTimeMillis());
[655]2076 toSave.setLastModifyUser(UserSettings.UserName.get());
[306]2077 toSave.setVersion(toSave.getVersion() + 1);
2078 Time darkTime = new Time(SessionStats.getFrameDarkTime().getTime()
2079 + toSave.getDarkTime().getTime());
2080 Time activeTime = new Time(SessionStats.getFrameActiveTime().getTime()
2081 + toSave.getActiveTime().getTime());
2082 toSave.setDarkTime(darkTime);
2083 toSave.setActiveTime(activeTime);
2084 }
[1244]2085
[1270]2086 public static Path setupPersonalResources(String username) {
[1244]2087 Path personalResources = Paths.get(FrameIO.PARENT_FOLDER).resolve("resources-" + username);
2088 personalResources.toFile().mkdir();
[1274]2089 File[] globalResourcesToCopy = Paths.get(FrameIO.RESOURCES_PRIVATE_PATH).toFile().listFiles();
[1244]2090
2091 try {
2092 for (File toCopy: globalResourcesToCopy) {
2093 Path p = Paths.get(toCopy.getAbsolutePath());
2094 if (!p.getFileName().toString().equals(".res") && !p.getFileName().toString().equals("about")) {
[1293]2095 moveFileTree(p.toAbsolutePath(), personalResources.resolve(p.getFileName()));
[1244]2096 }
2097 }
[1330]2098 } catch (IOException e) {
[1244]2099 e.printStackTrace();
2100 personalResources = null;
2101 }
2102
2103 return personalResources;
2104 }
2105
[1270]2106 public static void migrateFrame(Frame toMigrate, Path destinationDirectory) {
2107 Path source = Paths.get(toMigrate.getFramePathReal());
2108 String destination = source.relativize(destinationDirectory).toString().substring(3).replace(File.separator, "/");
2109 try {
[1271]2110 Files.move(source, destinationDirectory);
[1270]2111 } catch (IOException e) {
2112 System.err.println("FrameIO::migrateFrame: failed to migrate from to new location. Message: " + e.getMessage());
2113 return;
2114 }
2115 try {
2116 FileWriter out = new FileWriter(source.toFile());
2117 out.write("REDIRECT:" + destination);
2118 out.flush();
2119 out.close();
2120 } catch (IOException e) {
2121 System.err.println("FrameIO::migrateFrame: failed to update file [" + source + "] to redirect to [" + destination + "] following migration. Message: " + e.getMessage());
2122 }
2123 }
2124
[1293]2125 private static void moveFileTree(Path source, Path target) throws IOException {
[1244]2126 if (source.toFile().isDirectory()) {
[1293]2127 if (!target.toFile().exists()) {
2128 Files.copy(source, target);
2129 }
[1244]2130 File[] files = source.toFile().listFiles();
2131 for (File file: files) {
2132 Path asPath = Paths.get(file.getAbsolutePath());
[1293]2133 moveFileTree(asPath, target.resolve(asPath.getFileName()));
[1244]2134 }
[1293]2135 } else {
2136 Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
[1244]2137 }
2138 }
[4]2139}
Note: See TracBrowser for help on using the repository browser.