root/tags/2D14/JVChatEvent.m

Revision 2558, 10.4 kB (checked in by eridius, 3 years ago)

Remove all trailing whitespace from lines
Remove indentation on blank lines

Line 
1 #import "JVChatEvent.h"
2 #import "NSAttributedStringMoreAdditions.h"
3
4 #import <ChatCore/NSAttributedStringAdditions.h>
5 #import <ChatCore/NSStringAdditions.h>
6 #import <ChatCore/NSDataAdditions.h>
7 #import <libxml/xinclude.h>
8
9 @implementation JVChatEvent
10 - (id) init {
11         if( ( self = [super init] ) ) {
12                 _loadedMessage = NO;
13                 _loadedAttributes = NO;
14                 _loadedSmall = NO;
15                 _objectSpecifier = nil;
16                 _transcript = nil;
17                 _eventIdentifier = nil;
18                 _message = nil;
19                 _date = nil;
20                 _name = nil;
21                 _attributes = nil;
22         }
23
24         return self;
25 }
26
27 - (id) initWithNode:(xmlNode *) node andTranscript:(JVChatTranscript *) transcript {
28         if( ( self = [self init] ) ) {
29                 _node = node;
30                 _transcript = transcript; // weak reference
31
32                 if( ! _node || node -> type != XML_ELEMENT_NODE ) {
33                         [self release];
34                         return nil;
35                 }
36
37                 @synchronized( [self transcript] ) {
38                         xmlChar *prop = xmlGetProp( (xmlNode *) _node, (xmlChar *) "id" );
39                         _eventIdentifier = ( prop ? [[NSString allocWithZone:[self zone]] initWithUTF8String:(char *) prop] : nil );
40                         xmlFree( prop );
41                 }
42         }
43
44         return self;
45 }
46
47 + (id) eventWithNode:(xmlNode *) node andTranscript:(JVChatTranscript *) transcript {
48         return [[[self alloc] initWithNode:node andTranscript:transcript] autorelease];
49 }
50
51 - (void) dealloc {
52         [_eventIdentifier release];
53         [_date release];
54         [_name release];
55         [_message release];
56         [_attributes release];
57
58         _eventIdentifier = nil;
59         _date = nil;
60         _name = nil;
61         _message = nil;
62         _attributes = nil;
63
64         _transcript = nil; // weak reference
65         _node = NULL;
66
67         [super dealloc];
68 }
69
70 #pragma mark -
71
72 - (void) loadSmall {
73         if( _loadedSmall || ! _node ) return;
74
75         @synchronized( [self transcript] ) {
76                 xmlChar *prop = xmlGetProp( (xmlNode *) _node, (xmlChar *) "name" );
77                 _name = ( prop ? [[NSString allocWithZone:[self zone]] initWithUTF8String:(char *) prop] : nil );
78                 xmlFree( prop );
79
80                 prop = xmlGetProp( (xmlNode *) _node, (xmlChar *) "occurred" );
81                 _date = ( prop ? [[NSDate allocWithZone:[self zone]] initWithString:[NSString stringWithUTF8String:(char *) prop]] : nil );
82                 xmlFree( prop );
83         }
84
85         _loadedSmall = YES;
86 }
87
88 - (void) loadMessage {
89         if( _loadedMessage || ! _node ) return;
90
91         @synchronized( [self transcript] ) {
92                 xmlNode *subNode = ((xmlNode *) _node) -> children;
93
94                 do {
95                         if( subNode -> type == XML_ELEMENT_NODE && ! strncmp( "message", (char *) subNode -> name, 6 ) ) {
96                                 _message = [[NSTextStorage allocWithZone:[self zone]] initWithXHTMLTree:subNode baseURL:nil defaultAttributes:nil];
97                                 break;
98                         }
99                 } while( ( subNode = subNode -> next ) );
100         }
101
102         _loadedMessage = YES;
103 }
104
105 - (void) loadAttributes {
106         if( _loadedAttributes || ! _node ) return;
107
108         @synchronized( [self transcript] ) {
109                 xmlNode *subNode = ((xmlNode *) _node) -> children;
110                 NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
111
112                 do {
113                         if( subNode -> type == XML_ELEMENT_NODE && strncmp( "message", (char *) subNode -> name, 6 ) ) { // everything but "message"
114                                 NSMutableDictionary *properties = [NSMutableDictionary dictionary];
115                                 xmlAttrPtr prop = NULL;
116                                 for( prop = subNode -> properties; prop; prop = prop -> next ) {
117                                         xmlChar *value = xmlGetProp( subNode, prop -> name );
118                                         if( value ) {
119                                                 [properties setObject:[NSString stringWithUTF8String:(char *) value] forKey:[NSString stringWithUTF8String:(char *) prop -> name]];
120                                                 xmlFree( value );
121                                         }
122                                 }
123
124                                 xmlNode *cnode = subNode -> children;
125                                 unsigned count = 0;
126
127                                 do {
128                                         if( cnode && cnode -> type == XML_ELEMENT_NODE ) count++;
129                                 } while( cnode && ( cnode = cnode -> next ) );
130
131                                 id value = nil;
132                                 if( count > 0 ) {
133                                         value = [NSTextStorage attributedStringWithXHTMLTree:subNode baseURL:nil defaultAttributes:nil];
134                                 } else {
135                                         xmlChar *content = xmlNodeGetContent( subNode );
136                                         value = [NSString stringWithUTF8String:(char *) content];
137                                         xmlFree( content );
138                                 }
139
140                                 if( [properties count] ) {
141                                         [properties setObject:value forKey:@"value"];
142                                         [attributes setObject:properties forKey:[NSString stringWithUTF8String:(char *) subNode -> name]];
143                                 } else {
144                                         [attributes setObject:value forKey:[NSString stringWithUTF8String:(char *) subNode -> name]];
145                                 }
146                         }
147                 } while( ( subNode = subNode -> next ) );
148         }
149
150         _loadedAttributes = YES;
151 }
152
153 #pragma mark -
154
155 - (void *) node {
156         return _node;
157 }
158
159 - (void) setNode:(xmlNode *) node {
160         _node = node;
161 }
162
163 #pragma mark -
164
165 - (JVChatTranscript *) transcript {
166         return _transcript;
167 }
168
169 - (NSString *) eventIdentifier {
170         return _eventIdentifier;
171 }
172
173 #pragma mark -
174
175 - (NSDate *) date {
176         [self loadSmall];
177         return _date;
178 }
179
180 #pragma mark -
181
182 - (NSString *) name {
183         [self loadSmall];
184         return _name;
185 }
186
187 #pragma mark -
188
189 - (NSTextStorage *) message {
190         [self loadMessage];
191         return _message;
192 }
193
194 - (NSString *) messageAsPlainText {
195         return [[self message] string];
196 }
197
198 - (NSString *) messageAsHTML {
199         NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], @"IgnoreFonts", [NSNumber numberWithBool:YES], @"IgnoreFontSizes", nil];
200         return [[self message] HTMLFormatWithOptions:options];
201 }
202
203 #pragma mark -
204
205 - (NSDictionary *) attributes {
206         [self loadAttributes];
207         return _attributes;
208 }
209 @end
210
211 #pragma mark -
212
213 @implementation JVMutableChatEvent
214 + (id) chatEventWithName:(NSString *) name andMessage:(id) message {
215         return [[[self alloc] initWithName:name andMessage:message] autorelease];
216 }
217
218 #pragma mark -
219
220 - (id) init {
221         if( ( self = [super init] ) ) _doc = NULL;
222         return self;
223 }
224
225 - (id) initWithName:(NSString *) name andMessage:(id) message {
226         if( ( self = [self init] ) ) {
227                 _loadedMessage = YES;
228                 _loadedAttributes = YES;
229                 _loadedSmall = YES;
230                 [self setDate:[NSDate date]];
231                 [self setName:name];
232                 [self setMessage:message];
233                 [self setEventIdentifier:[NSString locallyUniqueString]];
234         }
235
236         return self;
237 }
238
239 - (void) dealloc {
240         if( _doc ) xmlFreeDoc( _doc );
241         _doc = NULL;
242
243         [super dealloc];
244 }
245
246 #pragma mark -
247
248 - (void *) node {
249         if( ! _node ) {
250                 if( _doc ) xmlFreeDoc( _doc );
251                 _doc = xmlNewDoc( (xmlChar *) "1.0" );
252
253                 xmlNodePtr root = xmlNewNode( NULL, (xmlChar *) "event" );
254                 xmlSetProp( root, (xmlChar *) "id", (xmlChar *) [[self eventIdentifier] UTF8String] );
255                 xmlSetProp( root, (xmlChar *) "name", (xmlChar *) [[self name] UTF8String] );
256                 xmlSetProp( root, (xmlChar *) "occurred", (xmlChar *) [[[self date] description] UTF8String] );
257                 xmlDocSetRootElement( _doc, root );
258
259                 xmlDocPtr msgDoc = NULL;
260                 xmlNodePtr child = NULL;
261                 const char *msgStr = NULL;
262
263                 if( [self message] ) {
264                         NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], @"IgnoreFonts", [NSNumber numberWithBool:YES], @"IgnoreFontSizes", nil];
265                         NSString *msgValue = [[self message] HTMLFormatWithOptions:options];
266                         msgValue = [msgValue stringByStrippingIllegalXMLCharacters];
267
268                         msgStr = [[NSString stringWithFormat:@"<message>%@</message>", msgValue] UTF8String];
269
270                         msgDoc = xmlParseMemory( msgStr, strlen( msgStr ) );
271                         child = xmlDocCopyNode( xmlDocGetRootElement( msgDoc ), _doc, 1 );
272                         xmlAddChild( root, child );
273                         xmlFreeDoc( msgDoc );
274                 }
275
276                 NSEnumerator *kenumerator = [[self attributes] keyEnumerator];
277                 NSEnumerator *enumerator = [[self attributes] objectEnumerator];
278                 NSString *key = nil;
279                 id value = nil;
280
281                 while( ( key = [kenumerator nextObject] ) && ( value = [enumerator nextObject] ) ) {
282                         msgStr = NULL;
283
284                         if( [value respondsToSelector:@selector( xmlDescriptionWithTagName: )] ) {
285                                 msgStr = [(NSString *)[value performSelector:@selector( xmlDescriptionWithTagName: ) withObject:key] UTF8String];
286                         } else if( [value isKindOfClass:[NSAttributedString class]] ) {
287                                 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], @"IgnoreFonts", [NSNumber numberWithBool:YES], @"IgnoreFontSizes", nil];
288                                 value = [value HTMLFormatWithOptions:options];
289                                 value = [value stringByStrippingIllegalXMLCharacters];
290                                 if( [(NSString *)value length] )
291                                         msgStr = [[NSString stringWithFormat:@"<%@>%@</%@>", key, value, key] UTF8String];
292                         } else if( [value isKindOfClass:[NSString class]] ) {
293                                 value = [value stringByEncodingXMLSpecialCharactersAsEntities];
294                                 value = [value stringByStrippingIllegalXMLCharacters];
295                                 if( [(NSString *)value length] )
296                                         msgStr = [[NSString stringWithFormat:@"<%@>%@</%@>", key, value, key] UTF8String];
297                         } else if( [value isKindOfClass:[NSData class]] ) {
298                                 value = [value base64EncodingWithLineLength:0];
299                                 if( [(NSString *)value length] )
300                                         msgStr = [[NSString stringWithFormat:@"<%@ encoding=\"base64\">%@</%@>", key, value, key] UTF8String];
301                         }
302
303                         if( ! msgStr ) msgStr = [[NSString stringWithFormat:@"<%@ />", key] UTF8String];
304
305                         msgDoc = xmlParseMemory( msgStr, strlen( msgStr ) );
306                         child = xmlDocCopyNode( xmlDocGetRootElement( msgDoc ), _doc, 1 );
307                         xmlAddChild( root, child );
308                         xmlFreeDoc( msgDoc );
309                 }
310
311                 _node = root;
312         }
313
314         return _node;
315 }
316
317 - (void) setNode:(xmlNode *) node {
318         if( _doc ) {
319                 xmlFreeDoc( _doc );
320                 _doc = NULL;
321         }
322
323         _node = node;
324 }
325
326 #pragma mark -
327
328 - (void) setDate:(NSDate *) date {
329         [self setNode:NULL];
330         [_date autorelease];
331         _date = [date copyWithZone:[self zone]];
332 }
333
334 - (void) setName:(NSString *) name {
335         [self setNode:NULL];
336         [_name autorelease];
337         _name = [name copyWithZone:[self zone]];
338 }
339
340 #pragma mark -
341
342 - (void) setMessage:(id) message {
343         [self setNode:NULL];
344         if( ! _message ) {
345                 if( [message isKindOfClass:[NSTextStorage class]] ) _message = [message retain];
346                 else if( [message isKindOfClass:[NSAttributedString class]] ) _message = [[NSTextStorage alloc] initWithAttributedString:message];
347                 else if( [message isKindOfClass:[NSString class]] ) _message = [[NSTextStorage alloc] initWithXHTMLFragment:(NSString *)message baseURL:nil defaultAttributes:nil];
348         } else if( _message && [message isKindOfClass:[NSAttributedString class]] ) {
349                 [_message setAttributedString:message];
350         } else if( _message && [message isKindOfClass:[NSString class]] ) {
351                 id string = [NSAttributedString attributedStringWithXHTMLFragment:(NSString *)message baseURL:nil defaultAttributes:nil];
352                 [_message setAttributedString:string];
353         }
354 }
355
356 - (void) setMessageAsPlainText:(NSString *) message {
357         [self setMessage:[[[NSAttributedString alloc] initWithString:message] autorelease]];
358 }
359
360 - (void) setMessageAsHTML:(NSString *) message {
361         [self setMessage:message];
362 }
363
364 #pragma mark -
365
366 - (void) setAttributes:(NSDictionary *) attributes {
367         [self setNode:NULL];
368         [_attributes autorelease];
369         _attributes = [attributes copyWithZone:[self zone]];
370 }
371
372 #pragma mark -
373
374 - (void) setEventIdentifier:(NSString *) identifier {
375         [self setNode:NULL];
376         [_eventIdentifier autorelease];
377         _eventIdentifier = [identifier copyWithZone:[self zone]];
378 }
379 @end
Note: See TracBrowser for help on using the browser.