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

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

org.expeditee.auth.EncryptedExpReader ->
org.expeditee.auth.EncryptedExpWriter ->
Actions ->
AttributeUtils ->
Frame ->
FrameIO ->
UserSettings ->

Changed how reading and writing encrypted files worked. A Frame attribute is now consulted to determine what to use as key for encryption. The 'profile' attribute setting is used to signal that the users personal aes key is used. Further enhancement will mean that other labels will be able to be used.


Actions ->

MailMode action now consults the database to reaquire the mail.

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