2 Copyright (C) 2000-2006 SKYRIX Software AG
3 Copyright (C) 2006 Helge Hess
5 This file is part of SOPE.
7 SOPE is free software; you can redistribute it and/or modify it under
8 the terms of the GNU Lesser General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with SOPE; see the file COPYING. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include <NGObjWeb/WEClientCapabilities.h>
24 #include <NGObjWeb/WOAssociation.h>
25 #include <NGObjWeb/WOContext.h>
26 #include <NGObjWeb/WOComponent.h>
27 #include <NGObjWeb/WOResponse.h>
31 #define WEUA_UNKNOWN 0
33 #define WEUA_Netscape 2
39 #define WEUA_WebFolder 8
40 #define WEUA_Mozilla 9
41 #define WEUA_OmniWeb 10
43 #define WEUA_Konqueror 12
46 #define WEUA_CADAVER 15
47 #define WEUA_GOLIVE 16
48 #define WEUA_MACOSX_DAVFS 17
50 #define WEUA_JavaSDK 19
51 #define WEUA_PythonURLLIB 20
52 #define WEUA_AppleDAVAccess 21
53 #define WEUA_MSWebPublisher 22
55 #define WEUA_Evolution 24
56 #define WEUA_MSOutlook 25
57 #define WEUA_MSOutlookExpress 26
58 #define WEUA_GNOMEVFS 27
59 #define WEUA_ZideLook 28
60 #define WEUA_Safari 29
62 #define WEUA_Entourage 31
63 #define WEUA_NetNewsWire 32
64 #define WEUA_xmlrpclib_py 33
65 #define WEUA_Morgul 34
66 #define WEUA_CFNetwork 35
67 #define WEUA_KungLog 36
70 #define WEUA_NewsFire 39
71 #define WEUA_Goliath 40
72 #define WEUA_PerlHTTPDAV 41
73 #define WEUA_Google 42
74 #define WEUA_WebDrive 43
75 #define WEUA_Sunbird 44
77 #define WEOS_UNKNOWN 0
78 #define WEOS_WINDOWS 1
83 #define WECPU_UNKNOWN 0
88 @interface WEClientCapabilities(Privates)
89 - (id)initWithRequest:(WORequest *)_request;
92 @implementation WEClientCapabilities
94 - (id)initWithRequest:(WORequest *)_request {
98 int defaultOS = WEOS_UNKNOWN;
99 int defaultCPU = WECPU_UNKNOWN;
103 if ((ac = [_request headerForKey:@"accept-charset"])) {
104 /* not really correct ..., eg could have quality "0" ! */
105 ac = [ac lowercaseString];
106 if ([ac rangeOfString:@"utf-8"].length > 0)
107 self->flags.acceptUTF8 = 1;
110 /* process user-agent */
112 self->userAgent = [[_request headerForKey:@"user-agent"] copy];
113 ua = [self->userAgent cString];
115 /* no user-agent, eg telnet */
121 if ((tmp = strstr(ua, "Opera"))) {
122 /* Opera (can fake to be MSIE or Netscape) */
123 self->browser = WEUA_Opera;
125 /* go to next space */
126 while (!isspace(*tmp) && (*tmp != '\0')) tmp++;
128 while (isspace(*tmp) && (*tmp != '\0')) tmp++;
130 self->browserMajorVersion = atoi(tmp);
131 if ((tmp = index(tmp, '.'))) {
133 self->browserMinorVersion = atoi(tmp);
136 else if (strstr(ua, "NeonConnection") != NULL ||
137 strstr(ua, "ZIDEStore") != NULL ||
138 strstr(ua, "ZideLook-Codeon") != NULL) {
139 self->browser = WEUA_ZideLook;
140 self->browserMinorVersion = 0;
141 self->browserMajorVersion = 0;
143 else if ((tmp = strstr(ua, "Safari/"))) {
144 /* Hm, Safari says it is a Mozilla/5.0 ? */
146 self->browser = WEUA_Safari;
147 tmp += 7; /* skip "Safari/" */
148 combinedVersion = atoi(tmp);
149 /* well, don't know how this is supposed to work? 100=v1.1 */
150 if (combinedVersion == 100 /* 100 is v1.1 */) {
151 self->browserMajorVersion = 1;
152 self->browserMinorVersion = 1;
155 /* watch for upcoming versions ... */
156 self->browserMajorVersion = combinedVersion / 100;
159 else if ((tmp = strstr(ua, "Sunbird/"))) {
160 /* Sunbird says it is a Mozilla */
161 self->browser = WEUA_Sunbird;
162 tmp += 8; /* skip "Sunbird/" */
164 self->browserMajorVersion = atoi(tmp);
165 if ((tmp = index(tmp, '.'))) {
167 self->browserMinorVersion = atoi(tmp);
170 else if (strstr(ua, "Outlook-Express/")) {
171 /* Outlook Express 5.5 mailbox access via http */
172 self->browser = WEUA_MSOutlookExpress;
174 else if (strstr(ua, "Outlook Express/")) {
175 /* Outlook Express 5.0 mailbox access via http */
176 self->browser = WEUA_MSOutlookExpress;
178 else if (strstr(ua, "Microsoft-Outlook/")) {
179 /* Outlook 2002 mailbox access via http */
180 self->browser = WEUA_MSOutlook;
182 else if (strstr(ua, "Microsoft HTTP Post")) {
183 /* Outlook 2000 with WebPublishing Assistent */
184 self->browser = WEUA_MSWebPublisher;
186 else if (strstr(ua, "Entourage/10")) {
187 /* Entourage MacOSX 10.1.4 */
188 self->browser = WEUA_Entourage;
190 else if (strstr(ua, "Microsoft-WebDAV-MiniRedir/5")) {
191 /* WebFolders Win XP SP 2 */
192 self->browser = WEUA_WebFolder;
194 else if ((tmp = strstr(ua, "MSIE"))) {
195 /* Internet Explorer */
196 self->browser = WEUA_IE;
198 /* go to next space */
199 while (!isspace(*tmp) && (*tmp != '\0')) tmp++;
201 while (isspace(*tmp) && (*tmp != '\0')) tmp++;
203 self->browserMajorVersion = atoi(tmp);
204 if ((tmp = index(tmp, '.'))) {
206 self->browserMinorVersion = atoi(tmp);
209 else if ((tmp = strstr(ua, "Konqueror"))) {
210 /* Konqueror (KDE2 FileManager) */
211 self->browser = WEUA_Konqueror;
213 if ((tmp = index(tmp, '/'))) {
215 self->browserMajorVersion = atoi(tmp);
216 if ((tmp = index(tmp, '.'))) {
218 self->browserMinorVersion = atoi(tmp);
222 else if ((tmp = strstr(ua, "Netscape6"))) {
224 self->browser = WEUA_Netscape;
226 if ((tmp = index(tmp, '/'))) {
228 self->browserMajorVersion = atoi(tmp);
229 if ((tmp = index(tmp, '.'))) {
231 self->browserMinorVersion = atoi(tmp);
235 else if (strstr(ua, "Lynx")) {
237 self->browser = WEUA_Lynx;
239 else if (strstr(ua, "Links")) {
241 self->browser = WEUA_Links;
243 else if (strstr(ua, "gnome-vfs")) {
245 self->browser = WEUA_GNOMEVFS;
247 else if (strstr(ua, "cadaver")) {
248 /* Cadaver DAV browser */
249 self->browser = WEUA_CADAVER;
251 else if (strstr(ua, "GoLive")) {
253 self->browser = WEUA_GOLIVE;
255 else if (strstr(ua, "DAV.pm")) {
257 self->browser = WEUA_PerlHTTPDAV;
259 else if (strstr(ua, "Darwin") != NULL && strstr(ua, "fetch/") != NULL) {
260 /* MacOSX 10.0 DAV FileSystem */
261 self->browser = WEUA_MACOSX_DAVFS;
263 else if (strstr(ua, "Darwin") != NULL && strstr(ua, "WebDAVFS/") != NULL) {
264 /* MacOSX DAV FileSystem */
265 self->browser = WEUA_MACOSX_DAVFS;
267 else if (strstr(ua, "OmniWeb")) {
269 self->browser = WEUA_OmniWeb;
271 else if (strstr(ua, "Evolution")) {
273 self->browser = WEUA_Evolution;
275 else if (strstr(ua, "Soup/")) {
276 /* SOUP (GNOME WebDAV library) */
277 self->browser = WEUA_SOUP;
279 else if (strstr(ua, "amaya")) {
281 self->browser = WEUA_Amaya;
283 else if (strstr(ua, "NetNewsWire/")) {
285 self->browser = WEUA_NetNewsWire;
287 else if (strstr(ua, "Dillo")) {
289 self->browser = WEUA_Dillo;
291 else if (strstr(ua, "Java")) {
293 self->browser = WEUA_JavaSDK;
295 else if (strstr(ua, "Python-urllib")) {
296 /* Python URL module */
297 self->browser = WEUA_PythonURLLIB;
299 else if (strstr(ua, "xmlrpclib.py/")) {
300 /* Python XML-RPC module */
301 self->browser = WEUA_xmlrpclib_py;
303 else if (strstr(ua, "Emacs")) {
305 self->browser = WEUA_Emacs;
307 else if (strstr(ua, "iCab")) {
309 self->browser = WEUA_iCab;
311 else if (strstr(ua, "Wget")) {
313 self->browser = WEUA_Wget;
315 else if (strstr(ua, "DAVAccess")) {
316 /* Apple MacOSX 10.2.1 / iCal 1.0 DAV Access Framework */
317 self->browser = WEUA_AppleDAVAccess;
319 else if (strstr(ua, "DAVKit/")) {
320 /* some iCal 1.x DAV Access Framework, report as Apple DAV access */
321 self->browser = WEUA_AppleDAVAccess;
323 else if (strstr(ua, "Microsoft Data Access Internet Publishing Provider")) {
325 self->browser = WEUA_WebFolder;
327 else if (strstr(ua, "Microsoft Office Protocol Discovery")) {
328 /* Word 2003, treat as WebFolder */
329 self->browser = WEUA_WebFolder;
331 else if (strstr(ua, "curl")) {
333 self->browser = WEUA_CURL;
335 else if (strstr(ua, "Mozilla")) {
336 /* other Netscape browser */
337 if (strstr(ua, "Mozilla/5")) {
338 self->browser = WEUA_Mozilla;
339 self->browserMajorVersion = 5;
341 else if (strstr(ua, "Mozilla/4")) {
342 self->browser = WEUA_Netscape;
343 self->browserMajorVersion = 4;
346 NSLog(@"%s: Unknown Mozilla Browser: user-agent='%@'",
347 __PRETTY_FUNCTION__, self->userAgent);
350 else if (strstr(ua, "Morgul")) {
351 self->browser = WEUA_Morgul;
353 else if (strstr(ua, "WebDrive")) {
354 self->browser = WEUA_WebDrive;
356 else if (strstr(ua, "CFNetwork/1.1")) {
357 self->browser = WEUA_CFNetwork;
359 else if (strstr(ua, "Kung-Log/")) {
360 self->browser = WEUA_KungLog;
362 else if (strstr(ua, "ecto")) {
363 self->browser = WEUA_Ecto;
365 else if (strstr(ua, "NewsFire")) {
366 self->browser = WEUA_NewsFire;
368 else if (strstr(ua, "Goliath")) {
369 self->browser = WEUA_Goliath;
371 else if (strstr(ua, "SOPE/")) {
372 self->browser = WEUA_SOPE;
374 else if (strstr(ua, "Mediapartners-Google/")) {
375 self->browser = WEUA_Google;
378 /* unknown browser */
379 self->browser = WEUA_UNKNOWN;
381 if (self->userAgent) {
382 NSLog(@"%s: Unknown WebClient: user-agent='%@'",
383 __PRETTY_FUNCTION__, self->userAgent);
389 if (strstr(ua, "Windows") != NULL || strstr(ua, "WinNT") != NULL)
390 self->os = WEOS_WINDOWS;
391 else if (strstr(ua, "Linux"))
392 self->os = WEOS_LINUX;
393 else if (strstr(ua, "Mac"))
394 self->os = WEOS_MACOS;
395 else if (strstr(ua, "SunOS"))
396 self->os = WEOS_SUNOS;
398 self->os = defaultOS;
402 if (strstr(ua, "sun4u"))
403 self->cpu = WECPU_SPARC;
404 else if (strstr(ua, "i686") || strstr(ua, "i586"))
405 self->cpu = WECPU_IX86;
406 else if (strstr(ua, "PowerPC") || strstr(ua, "ppc") || strstr(ua, "PPC"))
407 self->cpu = WECPU_PPC;
408 else if (self->os == WEOS_WINDOWS)
409 /* assume ix86 if OS is Windows .. */
410 self->cpu = WECPU_IX86;
412 self->cpu = defaultCPU;
418 [self->userAgent release];
424 - (NSString *)userAgent {
425 return self->userAgent;
428 - (NSString *)userAgentType {
429 switch (self->browser) {
430 case WEUA_IE: return @"IE";
431 case WEUA_Netscape: return @"Netscape";
432 case WEUA_Lynx: return @"Lynx";
433 case WEUA_Links: return @"Links";
434 case WEUA_Opera: return @"Opera";
435 case WEUA_Amaya: return @"Amaya";
436 case WEUA_Emacs: return @"Emacs";
437 case WEUA_Wget: return @"Wget";
438 case WEUA_WebFolder: return @"WebFolder";
439 case WEUA_DAVFS: return @"DAVFS";
440 case WEUA_MACOSX_DAVFS: return @"MacOSXDAVFS";
441 case WEUA_CADAVER: return @"Cadaver";
442 case WEUA_GOLIVE: return @"GoLive";
443 case WEUA_Mozilla: return @"Mozilla";
444 case WEUA_OmniWeb: return @"OmniWeb";
445 case WEUA_iCab: return @"iCab";
446 case WEUA_Konqueror: return @"Konqueror";
447 case WEUA_Dillo: return @"Dillo";
448 case WEUA_JavaSDK: return @"Java";
449 case WEUA_PythonURLLIB: return @"Python-urllib";
450 case WEUA_AppleDAVAccess: return @"AppleDAVAccess";
451 case WEUA_MSWebPublisher: return @"MSWebPublisher";
452 case WEUA_CURL: return @"CURL";
453 case WEUA_Evolution: return @"Evolution";
454 case WEUA_SOUP: return @"SOUP";
455 case WEUA_MSOutlook: return @"MSOutlook";
456 case WEUA_MSOutlookExpress: return @"MSOutlookExpress";
457 case WEUA_GNOMEVFS: return @"GNOME-VFS";
458 case WEUA_ZideLook: return @"ZideLook";
459 case WEUA_Safari: return @"Safari";
460 case WEUA_Entourage: return @"Entourage";
461 case WEUA_NetNewsWire: return @"NetNewsWire";
462 case WEUA_xmlrpclib_py: return @"xmlrpclib.py";
463 case WEUA_Morgul: return @"Morgul";
464 case WEUA_KungLog: return @"KungLog";
465 case WEUA_Ecto: return @"Ecto";
466 case WEUA_NewsFire: return @"NewsFire";
467 case WEUA_Goliath: return @"Goliath";
468 case WEUA_PerlHTTPDAV: return @"PerlHTTPDAV";
469 case WEUA_Google: return @"Google";
470 case WEUA_WebDrive: return @"WebDrive";
471 case WEUA_Sunbird: return @"Sunbird";
472 default: return @"unknown";
477 case WEOS_WINDOWS: return @"Windows";
478 case WEOS_LINUX: return @"Linux";
479 case WEOS_MACOS: return @"MacOS";
480 case WEOS_SUNOS: return @"SunOS";
481 default: return @"unknown";
486 case WECPU_IX86: return @"ix86";
487 case WECPU_SPARC: return @"sparc";
488 case WECPU_PPC: return @"ppc";
489 default: return @"unknown";
493 - (unsigned char)majorVersion {
494 return self->browserMajorVersion;
496 - (unsigned char)minorVersion {
497 return self->browserMinorVersion;
500 /* browser capabilities */
502 - (BOOL)isJavaScriptBrowser {
503 switch (self->browser) {
517 - (BOOL)isVBScriptBrowser {
518 switch (self->browser) {
527 - (BOOL)isFastTableBrowser {
528 switch (self->browser) {
540 return (self->browserMajorVersion >= 6)
548 - (BOOL)isCSS2Browser {
549 switch (self->browser) {
550 case WEUA_IE: return (self->browserMajorVersion >= 5) ? YES : NO;
551 case WEUA_Netscape: return (self->browserMajorVersion >= 6) ? YES : NO;
552 case WEUA_Opera: return (self->browserMajorVersion >= 4) ? YES : NO;
553 case WEUA_Mozilla: return YES;
554 case WEUA_Safari: return YES;
555 case WEUA_Konqueror: return NO;
560 - (BOOL)isCSS1Browser {
561 switch (self->browser) {
562 case WEUA_IE: return (self->browserMajorVersion >= 4) ? YES : NO;
563 case WEUA_Netscape: return (self->browserMajorVersion >= 4) ? YES : NO;
564 case WEUA_Opera: return (self->browserMajorVersion >= 4) ? YES : NO;
565 case WEUA_Safari: return YES;
566 case WEUA_Konqueror: return NO;
571 - (BOOL)ignoresCSSOnFormElements {
572 if (self->browser == WEUA_Safari) /* Safari always displays Aqua buttons */
575 return [self isCSS1Browser] ? NO : YES;
578 - (BOOL)isXULBrowser {
579 if (self->browser == WEUA_Safari) // TODO: Safari supports some XUL stuff
581 if ((self->browser == WEUA_Netscape) && (self->browserMajorVersion >= 6))
583 if (self->browser == WEUA_Mozilla)
588 - (BOOL)isTextModeBrowser {
589 if (self->browser == WEUA_Lynx) return YES;
590 if (self->browser == WEUA_Links) return YES;
591 if (self->browser == WEUA_Emacs) return YES;
595 - (BOOL)isIFrameBrowser {
596 if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
599 /* as suggested in OGo bug #634 */
600 if ((self->browser == WEUA_Mozilla) && (self->browserMajorVersion >= 5))
607 if (self->browser == WEUA_Wget) return YES;
608 if (self->browser == WEUA_JavaSDK) return YES;
609 if (self->browser == WEUA_PythonURLLIB) return YES;
610 if (self->browser == WEUA_Google) return YES;
613 - (BOOL)isDAVClient {
614 if (self->browser == WEUA_WebFolder) return YES;
615 if (self->browser == WEUA_DAVFS) return YES;
616 if (self->browser == WEUA_MACOSX_DAVFS) return YES;
617 if (self->browser == WEUA_CADAVER) return YES;
618 if (self->browser == WEUA_GOLIVE) return YES;
619 if (self->browser == WEUA_AppleDAVAccess) return YES;
620 if (self->browser == WEUA_Evolution) return YES;
621 if (self->browser == WEUA_SOUP) return YES;
622 if (self->browser == WEUA_MSOutlook) return YES;
623 if (self->browser == WEUA_MSOutlookExpress) return YES;
624 if (self->browser == WEUA_GNOMEVFS) return YES;
625 if (self->browser == WEUA_ZideLook) return YES;
626 if (self->browser == WEUA_Entourage) return YES;
627 if (self->browser == WEUA_Morgul) return YES;
628 if (self->browser == WEUA_Goliath) return YES;
629 if (self->browser == WEUA_PerlHTTPDAV) return YES;
630 if (self->browser == WEUA_WebDrive) return YES;
631 if (self->browser == WEUA_Sunbird) return YES;
635 - (BOOL)isXmlRpcClient {
636 if (self->browser == WEUA_xmlrpclib_py) return YES;
637 if (self->browser == WEUA_KungLog) return YES;
638 if (self->browser == WEUA_Ecto) return YES;
641 - (BOOL)isBLogClient {
642 if (self->browser == WEUA_KungLog) return YES;
643 if (self->browser == WEUA_Ecto) return YES;
646 - (BOOL)isRSSClient {
647 if (self->browser == WEUA_NetNewsWire) return YES;
648 if (self->browser == WEUA_NewsFire) return YES;
652 - (BOOL)doesSupportCSSOverflow {
653 if (![self isCSS1Browser])
655 if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
661 - (BOOL)doesSupportDHTMLDragAndDrop {
662 if (![self isJavaScriptBrowser])
664 if (self->os != WEOS_WINDOWS)
666 if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
671 - (BOOL)doesSupportXMLDataIslands {
672 if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
677 - (BOOL)doesSupportUTF8Encoding {
678 if (self->flags.acceptUTF8)
679 /* explicit UTF-8 support signaled in HTTP header */
682 switch (self->browser) {
690 /* browser so new, that they always supported UTF-8 ... */
693 if (self->browserMajorVersion >= 5)
695 return NO; // TODO: find out, whether IE 4 gurantees UTF-8 support
703 - (BOOL)isInternetExplorer {
704 return self->browser == WEUA_IE ? YES : NO;
706 - (BOOL)isInternetExplorer5 {
707 return (self->browser == WEUA_IE) && (self->browserMajorVersion == 5)
712 return self->browser == WEUA_Netscape ? YES : NO;
714 - (BOOL)isNetscape6 {
715 return (self->browser == WEUA_Netscape) && (self->browserMajorVersion == 6)
720 return self->browser == WEUA_Lynx ? YES : NO;
723 return self->browser == WEUA_Opera ? YES : NO;
726 return self->browser == WEUA_Amaya ? YES : NO;
729 return self->browser == WEUA_Emacs ? YES : NO;
732 return self->browser == WEUA_Wget ? YES : NO;
734 - (BOOL)isWebFolder {
735 return self->browser == WEUA_WebFolder ? YES : NO;
738 return self->browser == WEUA_Mozilla ? YES : NO;
741 return self->browser == WEUA_OmniWeb ? YES : NO;
744 return self->browser == WEUA_iCab ? YES : NO;
746 - (BOOL)isKonqueror {
747 return self->browser == WEUA_Konqueror ? YES : NO;
752 - (BOOL)isWindowsBrowser {
753 return self->os == WEOS_WINDOWS ? YES : NO;
755 - (BOOL)isLinuxBrowser {
756 return self->os == WEOS_LINUX ? YES : NO;
758 - (BOOL)isMacBrowser {
759 return self->os == WEOS_MACOS ? YES : NO;
761 - (BOOL)isSunOSBrowser {
762 return self->os == WEOS_SUNOS ? YES : NO;
764 - (BOOL)isUnixBrowser {
772 - (BOOL)isX11Browser {
773 if ([self isTextModeBrowser])
775 if (![self isUnixBrowser])
782 - (id)copyWithZone:(NSZone *)_zone {
783 return [self retain];
788 - (NSString *)description {
791 s = [NSMutableString stringWithFormat:@"<%@[0x%p]:",
792 NSStringFromClass([self class]), self];
794 //[s appendFormat:@" ua='%@'", self->userAgent];
795 [s appendFormat:@" type=%@ v%i.%i",
796 [self userAgentType],
797 self->browserMajorVersion, self->browserMinorVersion];
798 [s appendFormat:@" os=%@", [self os]];
799 [s appendFormat:@" cpu=%@", [self cpu]];
801 if ([self isFastTableBrowser]) [s appendString:@" fast-tbl"];
802 if ([self isCSS1Browser]) [s appendString:@" css1"];
803 if ([self isCSS2Browser]) [s appendString:@" css2"];
804 if ([self isXULBrowser]) [s appendString:@" xul"];
805 if ([self isTextModeBrowser]) [s appendString:@" text"];
806 if ([self isRobot]) [s appendString:@" robot"];
807 if ([self isJavaScriptBrowser]) [s appendString:@" js"];
808 if ([self isVBScriptBrowser]) [s appendString:@" vb"];
810 [s appendString:@">"];
814 @end /* WEClientCapabilities */
816 static NSString *ClientCapsCacheKey = @"WEClientCapabilities";
818 @implementation WORequest(ClientCapabilities)
820 - (WEClientCapabilities *)clientCapabilities {
822 WEClientCapabilities *ccaps;
823 NSMutableDictionary *md;
825 if ((ua = [self userInfo]) == nil) {
826 ccaps = [WEClientCapabilities alloc];
827 if ((ccaps = [ccaps initWithRequest:self]) == nil)
829 ccaps = [ccaps autorelease];
831 ua = [[NSDictionary alloc] initWithObjects:&ccaps
832 forKeys:&ClientCapsCacheKey
834 [self setUserInfo:ua];
839 if ((ccaps = [ua objectForKey:ClientCapsCacheKey]))
842 ccaps = [WEClientCapabilities alloc];
843 if ((ccaps = [ccaps initWithRequest:self]) == nil)
845 ccaps = [ccaps autorelease];
847 md = [ua mutableCopy];
848 [md setObject:ccaps forKey:ClientCapsCacheKey];
851 [self setUserInfo:ua];
856 @end /* WORequest(ClientCapabilities) */
858 static NSString *WEClientDetectorFormName = @"WEClientDetect";
860 @implementation JSClientCapabilityDetector
862 - (id)initWithName:(NSString *)_name
863 associations:(NSDictionary *)_config
864 template:(WOElement *)_c
866 if ((self = [super initWithName:_name associations:_config template:_c])) {
867 self->formName = OWGetProperty(_config, @"formName");
868 self->clientCaps = OWGetProperty(_config, @"clientCaps");
874 [self->formName release];
875 [self->clientCaps release];
879 - (NSString *)_formNameInContext:(WOContext *)_ctx {
881 return [self->formName stringValueInComponent:[_ctx component]];
885 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
886 if (![_ctx isInForm]) {
888 warnWithFormat:@"you must use %@ inside a form !",
889 NSStringFromClass([self class])];
893 if (![[[_ctx request] clientCapabilities] isJavaScriptBrowser])
894 /* only works on JavaScript browsers ... */
897 [_response appendContentString:@"<input type='hidden' name='"];
898 [_response appendContentString:WEClientDetectorFormName];
899 [_response appendContentString:@"' value='browserConfig' />"];
901 [_response appendContentString:@"<script language='JavaScript'>\n"];
902 [_response appendContentString:@"<!-- hide\n"];
904 [_response appendContentString:@"// -->\n"];
905 [_response appendContentString:@"</script>"];
908 @end /* JSClientCapabilityDetector */
911 Netscape 4.76, Windows NT 4
912 'Mozilla/4.76 [en] (WinNT; U)'
914 Netscape 6, Windows NT 4
915 'Mozilla/5.0 (Windows; U; WinNT4.0; en-US; m18) Gecko/20001108 Netscape6/6.0'
917 Netscape Navigator 3.01[de], MacOS 8.1
918 'Mozilla/3.01 [de]-C-MACOS8 (Macintosh; I; PPC)'
920 Netscape Communicator 4.51, SuSE Linux 6.1
921 'Mozilla/4.51 [en] (X11; I; Linux 2.2.13 i686)'
923 Mozilla M17, Windows NT 4
924 'Mozilla/5.0 (Windows; U; WinNT4.0; en-US; m17) Gecko/20000807'
926 Internet Explorer 5.5, Windows NT 4
927 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0)'
929 Internet Explorer 3.0.1, MacOS 8.1
930 'Mozilla/3.0 (compatible; MSIE 3.0.1; Mac_PowerPC; Mac OS8)'
932 Internet Explorer 5.0, MacOS 8.1
933 'Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC)'
935 Internet Explorer 5.0, SPARC Solaris 2.6 (trex)
936 'Mozilla/4.0 (compatible; MSIE 5.0; SunOS 5.6 sun4u; X11)'
938 Konqueror/2.0, SuSE Linux 7.0
939 'Mozilla/5.0 (compatible; Konqueror/2.0; X11); Supports MD5-Digest; Supports gzip encoding'
941 Lynx, SuSE Linux 6.1 (marvin)
942 'Lynx/2.8rel.2 libwww-FM/2.14'
944 Lynx, SPARC Solaris 2.6 (trex)
945 'Lynx/2.7 libwww-FM/2.14'
947 Opera 4.02, Windows NT 4
948 'Mozilla/4.73 (Windows NT 4.0; U) Opera 4.02 [en]'
950 Opera 5.0, Windows NT 4
951 'Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0) Opera 5.0 [en]'
953 Amaya 4.0, Windows NT 4
954 'amaya/V4.0 libwww/5.3.1'
956 XEmacs, SuSE Linux 6.1
957 'Emacs-W3/4.0pre.39 URL/p4.0pre.39 (i686-pc-linux; X11)'
959 XEmacs, SuSE Linux 7.2
960 'Emacs-W3/4.0pre.46 URL/p4.0pre.46 (i386-suse-linux; X11)'
965 Windows 'WebFolder' NT4
966 'Microsoft Data Access Internet Publishing Provider Cache Manager'
967 'Mozilla/2.0 (compatible; MS FrontPage 4.0)'
970 Windows 98 IE 5 WebFolders
971 'Microsoft Data Access Internet Publishing Provider DAV'
974 'OmniWeb/3.0.2 OWF/1999C'
976 Links, SuSE Linux 6.1 (marvin)
977 'Links (0.95; Linux 2.2.13 i686)'
983 fetch/1.0 Darwin/1.3.7 (Power Macintosh)
986 WebDAVFS/1.0 Darwin/5.1 (Power Macintosh)
989 WebDAVFS/1.2.1 (01218000) Darwin/6.1 (Power Macintosh)
992 WebDAVFS/1.4.1 (01418000) Darwin/8.6.0 (Power Macintosh)
995 'cadaver/0.17.0 neon/0.12.0-dev'
998 'GoLive/5. 0 [] (Windows 98; RATBERT)'
1001 - (very) small X11 web browser
1008 'Python-urllib/1.13'
1010 Apple MacOSX 10.2.1 / iCal 1.0 DAV Access Framework
1013 Outlook 2000 on W2K with M$ Web Publishing Assistent
1014 'Microsoft HTTP Post (RFC1867)'
1016 CURL program (libcurl)
1017 'curl/7.9.8 (i686-suse-linux) libcurl 7.9.8 (OpenSSL 0.9.6g) (ipv6 enabled)'
1019 Evolution 1.0.8 with Exchange Connector (WebDAV)
1022 Outlook 2002 on W2K (HotMail HTTP access)
1023 'Microsoft-Outlook/10.0 (TmstmpExt)'
1025 Outlook Express 5.5 on W2K (HotMail HTTP access)
1026 'Outlook-Express/5.5 (MSIE 5.5; Windows NT 5.0; Q312461; T312461; TmstmpExt)'
1028 Outlook Express 6.0 on W2K (HotMail HTTP access)
1029 'Outlook-Express/6.0 (MSIE 6.0; Windows NT 5.0; Q312461; T312461; TmstmpExt)'
1031 Nautilus (GNOME Virtual Filesystem)
1034 Konqueror 3.0.3 (SuSE 8.1)
1035 - does not send a user-agent in webdav:// mode !
1038 'neon/0.23.5 NeonConnection 0.0'
1040 Safari v74 (MacOSX 10.2)
1041 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/74 (KHTML, like Gecko) Safari/74'
1042 - why does it say Mozilla/5.0 ??
1044 Evolution 1.4.0 with Exchange Connector 1.4.0 (SuSE 8.2)
1047 Mozilla Firebird 0.6 (MacOSX 10.2)
1048 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6'
1050 SOUP (Evo OGo Connector by Anders)
1053 Entourage/X (Entourage WebDAV 10.1.4, MacOSX)
1054 'Entourage/10.0 (Mac_PowerPC; DigExt; TmstmpExt)'
1056 Some unknown iCal.app
1059 NetNewsWire full version:
1060 'NetNewsWire/1.0.5 (Mac OS X; http://ranchero.com/netnewswire/)'
1062 NetNewsWire lite version:
1063 'NetNewsWire/1.0.3 (Mac OS X; Lite; http://ranchero.com/netnewswire/)'
1066 'xmlrpclib.py/1.0.0 (by www.pythonware.com)'
1068 Windows 2000 IE 6 WebFolders
1069 'Microsoft Data Access Internet Publishing Provider DAV 1.1'
1071 Morgul, Windows WebDAV client
1074 Apple iSync v122 / CoreFoundation Network
1077 Kung-Log (WebServicesCore)
1078 'Kung-Log/1.3 (Macintosh; U; PPC Mac OS X) WebServicesCore'
1080 Ecto (WebServicesCore)
1081 'ecto (Macintosh; U; PPC Mac OS X) WebServicesCore'
1087 'Goliath/1.0.1 (Macintosh-Carbon; PPC)'
1093 'Mediapartners-Google/2.1'
1095 WebFolders Win XP SP2
1096 'Microsoft-WebDAV-MiniRedir/5.1.2600'
1099 'Microsoft Office Protocol Discovery'
1102 'WebDrive 7.10.1475 DAV'
1104 Nokia N80, Opera 8 (352x416, 24b)
1105 'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Symbian OS; Series 60/; 7439) Opera 8.60 [de]'
1106 'X-OS-Prefs: fw:352; fh:416; cd:24c; pl:3; pj:0; pa:1;pi:0;ps:0;'
1109 'User-Agent: Mozilla/5.0 (SymbianOS/9.1; U; en-us) AppleWebKit/413 (KHTML, like Gecko) Safari/413'
1111 Nokia N80, WAP Browser
1112 'User-Agent: NokiaN80-1/3.0 (3.0611.0.8) Series60/3.0 Profile/MIDP-2.0 Configuration/CLDC-1.1'
1113 'x-wap-profile: "http://nds1.nds.nokia.com/uaprof/NN80-1r100.xml"'
1115 Sony/Ericsson T610 (128x160, 16b)
1116 'user-agent: SonyEricssonT610/R301 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/6.3.0.0.0'
1117 'x-up-devcap-charset: US-ASCII,ISO-8859-1,UTF-8,ISO-10646-UCS-2'
1118 'x-up-devcap-iscolor: 1'
1119 'x-up-devcap-max-pdu: 10000'
1120 'x-up-devcap-screendepth: 16'
1121 'x-up-devcap-screenpixels: 128,160'
1122 'x-up-forwarded-for: 10.233.155.62'
1123 'x-up-subno: 981574289-60174629'
1124 'x-up-wtls-info: off'
1125 'x-wap-profile: "http://wap.sonyericsson.com/UAprof/T610R301.xml"'