2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3 * with this source distribution.
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 * Public License for more details.
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #import "ESDebugController.h"
18 #import "ESDebugWindowController.h"
20 #import <Adium/AIMenuControllerProtocol.h>
21 #import <Adium/AIPreferenceControllerProtocol.h>
22 #import <AIUtilities/AIMenuAdditions.h>
24 #include <fcntl.h> //open(2)
25 #include <unistd.h> //close(2)
26 #include <errno.h> //errno
27 #include <string.h> //strerror(3)
29 #define CACHED_DEBUG_LOGS 100 //Number of logs to keep at any given time
30 #define KEY_DEBUG_WINDOW_OPEN @"Debug Window Open"
32 @implementation ESDebugController
36 static ESDebugController *sharedDebugController = nil;
40 if (sharedDebugController)
41 self = sharedDebugController;
43 if ((self = [super init])) {
44 sharedDebugController = self;
46 debugLogArray = [[NSMutableArray alloc] init];
52 - (void)controllerDidLoad
54 //Contact list menu tem
55 NSMenuItem *menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:AILocalizedString(@"Debug Window",nil)
57 action:@selector(showDebugWindow:)
59 [[adium menuController] addMenuItem:menuItem toLocation:LOC_Adium_About];
62 //Restore the debug window if it was open when we quit last time
63 if ([[[adium preferenceController] preferenceForKey:KEY_DEBUG_WINDOW_OPEN
64 group:GROUP_DEBUG] boolValue]) {
65 [ESDebugWindowController showDebugWindow];
68 [[adium preferenceController] registerPreferenceObserver:self forGroup:GROUP_DEBUG];
71 - (void)controllerWillClose
73 //Save the open state of the debug window
74 [[adium preferenceController] setPreference:([ESDebugWindowController debugWindowIsOpen] ?
75 [NSNumber numberWithBool:YES] :
77 forKey:KEY_DEBUG_WINDOW_OPEN
79 [ESDebugWindowController closeDebugWindow];
82 + (ESDebugController *)sharedDebugController
84 return sharedDebugController;
89 [debugLogArray release];
90 [debugLogFile closeFile];
91 [debugLogFile release];
93 sharedDebugController = nil;
98 - (void)showDebugWindow:(id)sender
100 [NSApp activateIgnoringOtherApps:YES];
101 [ESDebugWindowController showDebugWindow];
104 - (void)addMessage:(NSString *)actualMessage
106 if ((![actualMessage hasSuffix:@"\n"]) && (![actualMessage hasSuffix:@"\r"])) {
107 actualMessage = [actualMessage stringByAppendingString:@"\n"];
110 [debugLogArray addObject:actualMessage];
113 [debugLogFile writeData:[actualMessage dataUsingEncoding:NSUTF8StringEncoding]];
116 //Keep debugLogArray to a reasonable size
117 if ([debugLogArray count] > CACHED_DEBUG_LOGS) [debugLogArray removeObjectAtIndex:0];
119 [ESDebugWindowController addedDebugMessage:actualMessage];
122 - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key
123 object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime
125 if (firstTime || [key isEqualToString:KEY_DEBUG_WRITE_LOG]) {
126 BOOL writeLogs = [[prefDict objectForKey:KEY_DEBUG_WRITE_LOG] boolValue];
131 [debugLogFile release]; debugLogFile = nil;
136 - (NSArray *)debugLogArray
138 return debugLogArray;
140 - (void)clearDebugLogArray
142 [debugLogArray removeAllObjects];
145 - (NSFileHandle *)debugLogFile
148 NSFileManager *mgr = [NSFileManager defaultManager];
149 NSCalendarDate *date = [NSCalendarDate calendarDate];
150 NSString *folder, *dateString, *filename, *pathname;
151 unsigned counter = 0;
154 //make sure the containing folder for debug logs exists.
155 folder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, /*expandTilde*/ YES) objectAtIndex:0];
156 folder = [folder stringByAppendingPathComponent:@"Logs"];
157 folder = [folder stringByAppendingPathComponent:@"Adium Debug"];
158 BOOL success = [mgr createDirectoryAtPath:folder attributes:nil];
159 if((!success) && (errno != EEXIST)) {
160 /*raise an exception if the folder could not be created,
161 * but not if that was because it already exists.
163 NSAssert2(success, @"Could not create folder %@: %s", folder, strerror(errno));
166 /*get today's date, for the filename.
167 *the date is in YYYY-MM-DD format. duplicates are disambiguated with
168 *' 1', ' 2', ' 3', etc. appendages.
170 filename = dateString = [date descriptionWithCalendarFormat:@"%Y-%m-%d"];
171 while([mgr fileExistsAtPath:(pathname = [folder stringByAppendingPathComponent:[filename stringByAppendingPathExtension:@"log"]])]) {
172 filename = [dateString stringByAppendingFormat:@" %u", ++counter];
175 //create (if necessary) and open the file as writable, in append mode.
176 fd = open([pathname fileSystemRepresentation], O_CREAT | O_WRONLY | O_APPEND, 0644);
177 NSAssert2(fd > -1, @"could not create %@ nor open it for writing: %s", pathname, strerror(errno));
179 //note: the file handle takes ownership of fd.
181 * From the docs: "The object creating an NSFileHandle using this method owns fileDescriptor and is responsible for its disposition."
182 * which seems to indicate that the file handle does not take ownership of fd. Just for the record. -eds
184 debugLogFile = [[NSFileHandle alloc] initWithFileDescriptor:fd];
185 if(!debugLogFile) close(fd);
186 NSAssert1(debugLogFile != nil, @"could not create file handle for %@", pathname);
188 //write header (separates this session from previous sessions).
189 [debugLogFile writeData:[[NSString stringWithFormat:@"Opened debug log at %@\n", date] dataUsingEncoding:NSUTF8StringEncoding]];
196 - (void)controllerDidLoad {};
197 - (void)controllerWillClose {};
198 #endif /* DEBUG_BUILD */