2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include <NGObjWeb/WEClientCapabilities.h>
23 #include <NGObjWeb/WOAssociation.h>
24 #include <NGObjWeb/WOContext.h>
25 #include <NGObjWeb/WOComponent.h>
26 #include <NGObjWeb/WOResponse.h>
30 #define WEUA_UNKNOWN 0
32 #define WEUA_Netscape 2
38 #define WEUA_WebFolder 8
39 #define WEUA_Mozilla 9
40 #define WEUA_OmniWeb 10
42 #define WEUA_Konqueror 12
45 #define WEUA_CADAVER 15
46 #define WEUA_GOLIVE 16
47 #define WEUA_MACOSX_DAVFS 17
49 #define WEUA_JavaSDK 19
50 #define WEUA_PythonURLLIB 20
51 #define WEUA_AppleDAVAccess 21
52 #define WEUA_MSWebPublisher 22
54 #define WEUA_Evolution 24
55 #define WEUA_MSOutlook 25
56 #define WEUA_MSOutlookExpress 26
57 #define WEUA_GNOMEVFS 27
58 #define WEUA_ZideLook 28
59 #define WEUA_Safari 29
61 #define WEUA_Entourage 31
62 #define WEUA_NetNewsWire 32
63 #define WEUA_xmlrpclib_py 33
64 #define WEUA_Morgul 34
65 #define WEUA_CFNetwork 35
66 #define WEUA_KungLog 36
69 #define WEUA_NewsFire 39
71 #define WEOS_UNKNOWN 0
72 #define WEOS_WINDOWS 1
77 #define WECPU_UNKNOWN 0
82 @interface WEClientCapabilities(Privates)
83 - (id)initWithRequest:(WORequest *)_request;
86 @implementation WEClientCapabilities
88 - (id)initWithRequest:(WORequest *)_request {
90 const unsigned char *ua;
91 const unsigned char *tmp;
92 int defaultOS = WEOS_UNKNOWN;
93 int defaultCPU = WECPU_UNKNOWN;
97 if ((ac = [_request headerForKey:@"accept-charset"])) {
98 /* not really correct ..., eg could have quality "0" ! */
99 ac = [ac lowercaseString];
100 if ([ac rangeOfString:@"utf-8"].length > 0)
101 self->flags.acceptUTF8 = 1;
104 /* process user-agent */
106 self->userAgent = [[_request headerForKey:@"user-agent"] copy];
107 ua = [self->userAgent cString];
109 /* no user-agent, eg telnet */
115 if ((tmp = strstr(ua, "Opera"))) {
116 /* Opera (can fake to be MSIE or Netscape) */
117 self->browser = WEUA_Opera;
119 /* go to next space */
120 while (!isspace(*tmp) && (*tmp != '\0')) tmp++;
122 while (isspace(*tmp) && (*tmp != '\0')) tmp++;
124 self->browserMajorVersion = atoi(tmp);
125 if ((tmp = index(tmp, '.'))) {
127 self->browserMinorVersion = atoi(tmp);
130 else if (strstr(ua, "NeonConnection") != NULL ||
131 strstr(ua, "ZIDEStore") != NULL ||
132 strstr(ua, "ZideLook-Codeon") != NULL) {
133 self->browser = WEUA_ZideLook;
134 self->browserMinorVersion = 0;
135 self->browserMajorVersion = 0;
137 else if ((tmp = strstr(ua, "Safari/"))) {
138 /* Hm, Safari says it is a Mozilla/5.0 ? */
140 self->browser = WEUA_Safari;
141 tmp += 7; /* skip "Safari/" */
142 combinedVersion = atoi(tmp);
143 /* well, don't know how this is supposed to work? 100=v1.1 */
144 if (combinedVersion == 100 /* 100 is v1.1 */) {
145 self->browserMajorVersion = 1;
146 self->browserMinorVersion = 1;
149 /* watch for upcoming versions ... */
150 self->browserMajorVersion = combinedVersion / 100;
153 else if (strstr(ua, "Outlook-Express/")) {
154 /* Outlook Express 5.5 mailbox access via http */
155 self->browser = WEUA_MSOutlookExpress;
157 else if (strstr(ua, "Outlook Express/")) {
158 /* Outlook Express 5.0 mailbox access via http */
159 self->browser = WEUA_MSOutlookExpress;
161 else if (strstr(ua, "Microsoft-Outlook/")) {
162 /* Outlook 2002 mailbox access via http */
163 self->browser = WEUA_MSOutlook;
165 else if (strstr(ua, "Microsoft HTTP Post")) {
166 /* Outlook 2000 with WebPublishing Assistent */
167 self->browser = WEUA_MSWebPublisher;
169 else if (strstr(ua, "Entourage/10")) {
170 /* Entourage MacOSX 10.1.4 */
171 self->browser = WEUA_Entourage;
173 else if ((tmp = strstr(ua, "MSIE"))) {
174 /* Internet Explorer */
175 self->browser = WEUA_IE;
177 /* go to next space */
178 while (!isspace(*tmp) && (*tmp != '\0')) tmp++;
180 while (isspace(*tmp) && (*tmp != '\0')) tmp++;
182 self->browserMajorVersion = atoi(tmp);
183 if ((tmp = index(tmp, '.'))) {
185 self->browserMinorVersion = atoi(tmp);
188 else if ((tmp = strstr(ua, "Konqueror"))) {
189 /* Konqueror (KDE2 FileManager) */
190 self->browser = WEUA_Konqueror;
192 if ((tmp = index(tmp, '/'))) {
194 self->browserMajorVersion = atoi(tmp);
195 if ((tmp = index(tmp, '.'))) {
197 self->browserMinorVersion = atoi(tmp);
201 else if ((tmp = strstr(ua, "Netscape6"))) {
203 self->browser = WEUA_Netscape;
205 if ((tmp = index(tmp, '/'))) {
207 self->browserMajorVersion = atoi(tmp);
208 if ((tmp = index(tmp, '.'))) {
210 self->browserMinorVersion = atoi(tmp);
214 else if (strstr(ua, "Lynx")) {
216 self->browser = WEUA_Lynx;
218 else if (strstr(ua, "Links")) {
220 self->browser = WEUA_Links;
222 else if (strstr(ua, "gnome-vfs")) {
224 self->browser = WEUA_GNOMEVFS;
226 else if (strstr(ua, "cadaver")) {
227 /* Cadaver DAV browser */
228 self->browser = WEUA_CADAVER;
230 else if (strstr(ua, "GoLive")) {
232 self->browser = WEUA_GOLIVE;
234 else if (strstr(ua, "Darwin") != NULL && strstr(ua, "fetch/") != NULL) {
235 /* MacOSX 10.0 DAV FileSystem */
236 self->browser = WEUA_MACOSX_DAVFS;
238 else if (strstr(ua, "Darwin") != NULL && strstr(ua, "WebDAVFS/") != NULL) {
239 /* MacOSX DAV FileSystem */
240 self->browser = WEUA_MACOSX_DAVFS;
242 else if (strstr(ua, "OmniWeb")) {
244 self->browser = WEUA_OmniWeb;
246 else if (strstr(ua, "Evolution")) {
248 self->browser = WEUA_Evolution;
250 else if (strstr(ua, "Soup/")) {
251 /* SOUP (GNOME WebDAV library) */
252 self->browser = WEUA_SOUP;
254 else if (strstr(ua, "amaya")) {
256 self->browser = WEUA_Amaya;
258 else if (strstr(ua, "NetNewsWire/")) {
260 self->browser = WEUA_NetNewsWire;
262 else if (strstr(ua, "Dillo")) {
264 self->browser = WEUA_Dillo;
266 else if (strstr(ua, "Java")) {
268 self->browser = WEUA_JavaSDK;
270 else if (strstr(ua, "Python-urllib")) {
271 /* Python URL module */
272 self->browser = WEUA_PythonURLLIB;
274 else if (strstr(ua, "xmlrpclib.py/")) {
275 /* Python XML-RPC module */
276 self->browser = WEUA_xmlrpclib_py;
278 else if (strstr(ua, "Emacs")) {
280 self->browser = WEUA_Emacs;
282 else if (strstr(ua, "iCab")) {
284 self->browser = WEUA_iCab;
286 else if (strstr(ua, "Wget")) {
288 self->browser = WEUA_Wget;
290 else if (strstr(ua, "DAVAccess")) {
291 /* Apple MacOSX 10.2.1 / iCal 1.0 DAV Access Framework */
292 self->browser = WEUA_AppleDAVAccess;
294 else if (strstr(ua, "DAVKit/")) {
295 /* some iCal 1.x DAV Access Framework, report as Apple DAV access */
296 self->browser = WEUA_AppleDAVAccess;
298 else if (strstr(ua, "Microsoft Data Access Internet Publishing Provider")) {
300 self->browser = WEUA_WebFolder;
302 else if (strstr(ua, "curl")) {
304 self->browser = WEUA_CURL;
306 else if (strstr(ua, "Mozilla")) {
307 /* other Netscape browser */
308 if (strstr(ua, "Mozilla/5")) {
309 self->browser = WEUA_Mozilla;
310 self->browserMajorVersion = 5;
312 else if (strstr(ua, "Mozilla/4")) {
313 self->browser = WEUA_Netscape;
314 self->browserMajorVersion = 4;
317 NSLog(@"%s: Unknown Mozilla Browser: user-agent='%@'",
318 __PRETTY_FUNCTION__, self->userAgent);
321 else if (strstr(ua, "Morgul")) {
322 self->browser = WEUA_Morgul;
324 else if (strstr(ua, "CFNetwork/1.1")) {
325 self->browser = WEUA_CFNetwork;
327 else if (strstr(ua, "Kung-Log/")) {
328 self->browser = WEUA_KungLog;
330 else if (strstr(ua, "ecto")) {
331 self->browser = WEUA_Ecto;
333 else if (strstr(ua, "NewsFire")) {
334 self->browser = WEUA_NewsFire;
336 else if (strstr(ua, "SOPE/")) {
337 self->browser = WEUA_SOPE;
340 /* unknown browser */
341 self->browser = WEUA_UNKNOWN;
343 if (self->userAgent) {
344 NSLog(@"%s: Unknown WebClient: user-agent='%@'",
345 __PRETTY_FUNCTION__, self->userAgent);
351 if (strstr(ua, "Windows") != NULL || strstr(ua, "WinNT") != NULL)
352 self->os = WEOS_WINDOWS;
353 else if (strstr(ua, "Linux"))
354 self->os = WEOS_LINUX;
355 else if (strstr(ua, "Mac"))
356 self->os = WEOS_MACOS;
357 else if (strstr(ua, "SunOS"))
358 self->os = WEOS_SUNOS;
360 self->os = defaultOS;
364 if (strstr(ua, "sun4u"))
365 self->cpu = WECPU_SPARC;
366 else if (strstr(ua, "i686") || strstr(ua, "i586"))
367 self->cpu = WECPU_IX86;
368 else if (strstr(ua, "PowerPC") || strstr(ua, "ppc") || strstr(ua, "PPC"))
369 self->cpu = WECPU_PPC;
370 else if (self->os == WEOS_WINDOWS)
371 /* assume ix86 if OS is Windows .. */
372 self->cpu = WECPU_IX86;
374 self->cpu = defaultCPU;
380 [self->userAgent release];
386 - (NSString *)userAgent {
387 return self->userAgent;
390 - (NSString *)userAgentType {
391 switch (self->browser) {
392 case WEUA_IE: return @"IE";
393 case WEUA_Netscape: return @"Netscape";
394 case WEUA_Lynx: return @"Lynx";
395 case WEUA_Links: return @"Links";
396 case WEUA_Opera: return @"Opera";
397 case WEUA_Amaya: return @"Amaya";
398 case WEUA_Emacs: return @"Emacs";
399 case WEUA_Wget: return @"Wget";
400 case WEUA_WebFolder: return @"WebFolder";
401 case WEUA_DAVFS: return @"DAVFS";
402 case WEUA_MACOSX_DAVFS: return @"MacOSXDAVFS";
403 case WEUA_CADAVER: return @"Cadaver";
404 case WEUA_GOLIVE: return @"GoLive";
405 case WEUA_Mozilla: return @"Mozilla";
406 case WEUA_OmniWeb: return @"OmniWeb";
407 case WEUA_iCab: return @"iCab";
408 case WEUA_Konqueror: return @"Konqueror";
409 case WEUA_Dillo: return @"Dillo";
410 case WEUA_JavaSDK: return @"Java";
411 case WEUA_PythonURLLIB: return @"Python-urllib";
412 case WEUA_AppleDAVAccess: return @"AppleDAVAccess";
413 case WEUA_MSWebPublisher: return @"MSWebPublisher";
414 case WEUA_CURL: return @"CURL";
415 case WEUA_Evolution: return @"Evolution";
416 case WEUA_SOUP: return @"SOUP";
417 case WEUA_MSOutlook: return @"MSOutlook";
418 case WEUA_MSOutlookExpress: return @"MSOutlookExpress";
419 case WEUA_GNOMEVFS: return @"GNOME-VFS";
420 case WEUA_ZideLook: return @"ZideLook";
421 case WEUA_Safari: return @"Safari";
422 case WEUA_Entourage: return @"Entourage";
423 case WEUA_NetNewsWire: return @"NetNewsWire";
424 case WEUA_xmlrpclib_py: return @"xmlrpclib.py";
425 case WEUA_Morgul: return @"Morgul";
426 case WEUA_KungLog: return @"KungLog";
427 case WEUA_Ecto: return @"Ecto";
428 case WEUA_NewsFire: return @"NewsFire";
429 default: return @"unknown";
434 case WEOS_WINDOWS: return @"Windows";
435 case WEOS_LINUX: return @"Linux";
436 case WEOS_MACOS: return @"MacOS";
437 case WEOS_SUNOS: return @"SunOS";
438 default: return @"unknown";
443 case WECPU_IX86: return @"ix86";
444 case WECPU_SPARC: return @"sparc";
445 case WECPU_PPC: return @"ppc";
446 default: return @"unknown";
450 - (unsigned char)majorVersion {
451 return self->browserMajorVersion;
453 - (unsigned char)minorVersion {
454 return self->browserMinorVersion;
457 /* browser capabilities */
459 - (BOOL)isJavaScriptBrowser {
460 switch (self->browser) {
473 - (BOOL)isVBScriptBrowser {
474 switch (self->browser) {
483 - (BOOL)isFastTableBrowser {
484 switch (self->browser) {
496 return (self->browserMajorVersion >= 6)
504 - (BOOL)isCSS2Browser {
505 switch (self->browser) {
506 case WEUA_IE: return (self->browserMajorVersion >= 5) ? YES : NO;
507 case WEUA_Netscape: return (self->browserMajorVersion >= 6) ? YES : NO;
508 case WEUA_Opera: return (self->browserMajorVersion >= 4) ? YES : NO;
509 case WEUA_Mozilla: return YES;
510 case WEUA_Safari: return YES;
511 case WEUA_Konqueror: return NO;
516 - (BOOL)isCSS1Browser {
517 switch (self->browser) {
518 case WEUA_IE: return (self->browserMajorVersion >= 4) ? YES : NO;
519 case WEUA_Netscape: return (self->browserMajorVersion >= 4) ? YES : NO;
520 case WEUA_Opera: return (self->browserMajorVersion >= 4) ? YES : NO;
521 case WEUA_Safari: return YES;
522 case WEUA_Konqueror: return NO;
527 - (BOOL)ignoresCSSOnFormElements {
528 if (self->browser == WEUA_Safari) /* Safari always displays Aqua buttons */
531 return [self isCSS1Browser] ? NO : YES;
534 - (BOOL)isXULBrowser {
535 if (self->browser == WEUA_Safari)
537 if ((self->browser == WEUA_Netscape) && (self->browserMajorVersion >= 6))
539 if (self->browser == WEUA_Mozilla)
544 - (BOOL)isTextModeBrowser {
545 if (self->browser == WEUA_Lynx) return YES;
546 if (self->browser == WEUA_Links) return YES;
547 if (self->browser == WEUA_Emacs) return YES;
551 - (BOOL)isIFrameBrowser {
552 if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
555 /* as suggested in OGo bug #634 */
556 if ((self->browser == WEUA_Mozilla) && (self->browserMajorVersion >= 5))
563 if (self->browser == WEUA_Wget) return YES;
564 if (self->browser == WEUA_JavaSDK) return YES;
565 if (self->browser == WEUA_PythonURLLIB) return YES;
568 - (BOOL)isDAVClient {
569 if (self->browser == WEUA_WebFolder) return YES;
570 if (self->browser == WEUA_DAVFS) return YES;
571 if (self->browser == WEUA_MACOSX_DAVFS) return YES;
572 if (self->browser == WEUA_CADAVER) return YES;
573 if (self->browser == WEUA_GOLIVE) return YES;
574 if (self->browser == WEUA_AppleDAVAccess) return YES;
575 if (self->browser == WEUA_Evolution) return YES;
576 if (self->browser == WEUA_SOUP) return YES;
577 if (self->browser == WEUA_MSOutlook) return YES;
578 if (self->browser == WEUA_MSOutlookExpress) return YES;
579 if (self->browser == WEUA_GNOMEVFS) return YES;
580 if (self->browser == WEUA_ZideLook) return YES;
581 if (self->browser == WEUA_Entourage) return YES;
582 if (self->browser == WEUA_Morgul) return YES;
586 - (BOOL)isXmlRpcClient {
587 if (self->browser == WEUA_xmlrpclib_py) return YES;
588 if (self->browser == WEUA_KungLog) return YES;
589 if (self->browser == WEUA_Ecto) return YES;
592 - (BOOL)isBLogClient {
593 if (self->browser == WEUA_KungLog) return YES;
594 if (self->browser == WEUA_Ecto) return YES;
598 - (BOOL)doesSupportCSSOverflow {
599 if (![self isCSS1Browser])
601 if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
607 - (BOOL)doesSupportDHTMLDragAndDrop {
608 if (![self isJavaScriptBrowser])
610 if (self->os != WEOS_WINDOWS)
612 if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
617 - (BOOL)doesSupportXMLDataIslands {
618 if ((self->browser == WEUA_IE) && (self->browserMajorVersion >= 5))
623 - (BOOL)doesSupportUTF8Encoding {
624 if (self->flags.acceptUTF8)
625 /* explicit UTF-8 support signaled in HTTP header */
628 switch (self->browser) {
635 /* browser so new, that they always supported UTF-8 ... */
638 if (self->browserMajorVersion >= 5)
640 return NO; // TODO: find out, whether IE 4 gurantees UTF-8 support
648 - (BOOL)isInternetExplorer {
649 return self->browser == WEUA_IE ? YES : NO;
651 - (BOOL)isInternetExplorer5 {
652 return (self->browser == WEUA_IE) && (self->browserMajorVersion == 5)
657 return self->browser == WEUA_Netscape ? YES : NO;
659 - (BOOL)isNetscape6 {
660 return (self->browser == WEUA_Netscape) && (self->browserMajorVersion == 6)
665 return self->browser == WEUA_Lynx ? YES : NO;
668 return self->browser == WEUA_Opera ? YES : NO;
671 return self->browser == WEUA_Amaya ? YES : NO;
674 return self->browser == WEUA_Emacs ? YES : NO;
677 return self->browser == WEUA_Wget ? YES : NO;
679 - (BOOL)isWebFolder {
680 return self->browser == WEUA_WebFolder ? YES : NO;
683 return self->browser == WEUA_Mozilla ? YES : NO;
686 return self->browser == WEUA_OmniWeb ? YES : NO;
689 return self->browser == WEUA_iCab ? YES : NO;
691 - (BOOL)isKonqueror {
692 return self->browser == WEUA_Konqueror ? YES : NO;
697 - (BOOL)isWindowsBrowser {
698 return self->os == WEOS_WINDOWS ? YES : NO;
700 - (BOOL)isLinuxBrowser {
701 return self->os == WEOS_LINUX ? YES : NO;
703 - (BOOL)isMacBrowser {
704 return self->os == WEOS_MACOS ? YES : NO;
706 - (BOOL)isSunOSBrowser {
707 return self->os == WEOS_SUNOS ? YES : NO;
709 - (BOOL)isUnixBrowser {
717 - (BOOL)isX11Browser {
718 if ([self isTextModeBrowser])
720 if (![self isUnixBrowser])
727 - (id)copyWithZone:(NSZone *)_zone {
728 return [self retain];
733 - (NSString *)description {
736 s = [NSMutableString stringWithFormat:@"<%@[0x%08X]:",
737 NSStringFromClass([self class]), self];
739 //[s appendFormat:@" ua='%@'", self->userAgent];
740 [s appendFormat:@" type=%@ v%i.%i>",
741 [self userAgentType],
742 self->browserMajorVersion, self->browserMinorVersion];
743 [s appendFormat:@" os=%@", [self os]];
744 [s appendFormat:@" cpu=%@", [self cpu]];
746 if ([self isFastTableBrowser]) [s appendString:@" fast-tbl"];
747 if ([self isCSS1Browser]) [s appendString:@" css1"];
748 if ([self isCSS2Browser]) [s appendString:@" css2"];
749 if ([self isXULBrowser]) [s appendString:@" xul"];
750 if ([self isTextModeBrowser]) [s appendString:@" text"];
751 if ([self isRobot]) [s appendString:@" robot"];
752 if ([self isJavaScriptBrowser]) [s appendString:@" js"];
753 if ([self isVBScriptBrowser]) [s appendString:@" vb"];
755 [s appendString:@">"];
759 @end /* WEClientCapabilities */
761 static NSString *ClientCapsCacheKey = @"WEClientCapabilties";
763 @implementation WORequest(ClientCapabilities)
765 - (WEClientCapabilities *)clientCapabilities {
767 WEClientCapabilities *ccaps;
768 NSMutableDictionary *md;
770 if ((ua = [self userInfo]) == nil) {
771 ccaps = [WEClientCapabilities alloc];
772 if ((ccaps = [ccaps initWithRequest:self]) == nil)
774 ccaps = [ccaps autorelease];
776 ua = [[NSDictionary alloc] initWithObjects:&ccaps
777 forKeys:&ClientCapsCacheKey
779 [self setUserInfo:ua];
784 if ((ccaps = [ua objectForKey:ClientCapsCacheKey]))
787 ccaps = [WEClientCapabilities alloc];
788 if ((ccaps = [ccaps initWithRequest:self]) == nil)
790 ccaps = [ccaps autorelease];
792 md = [ua mutableCopy];
793 [md setObject:ccaps forKey:ClientCapsCacheKey];
796 [self setUserInfo:ua];
801 @end /* WORequest(ClientCapabilities) */
803 static NSString *WEClientDetectorFormName = @"WEClientDetect";
805 @implementation JSClientCapabilityDetector
807 - (id)initWithName:(NSString *)_name
808 associations:(NSDictionary *)_config
809 template:(WOElement *)_c
811 if ((self = [super initWithName:_name associations:_config template:_c])) {
812 self->formName = OWGetProperty(_config, @"formName");
813 self->clientCaps = OWGetProperty(_config, @"clientCaps");
819 [self->formName release];
820 [self->clientCaps release];
824 - (NSString *)_formNameInContext:(WOContext *)_ctx {
826 return [self->formName stringValueInComponent:[_ctx component]];
830 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
831 if (![_ctx isInForm]) {
833 logWithFormat:@"WARNING: you must use %@ inside a form !",
834 NSStringFromClass([self class])];
838 if (![[[_ctx request] clientCapabilities] isJavaScriptBrowser])
839 /* only works on JavaScript browsers ... */
842 [_response appendContentString:@"<input type='hidden' name='"];
843 [_response appendContentString:WEClientDetectorFormName];
844 [_response appendContentString:@"' value='browserConfig' />"];
846 [_response appendContentString:@"<script language='JavaScript'>\n"];
847 [_response appendContentString:@"<!-- hide\n"];
849 [_response appendContentString:@"// -->\n"];
850 [_response appendContentString:@"</script>"];
853 @end /* JSClientCapabilityDetector */
856 Netscape 4.76, Windows NT 4
857 'Mozilla/4.76 [en] (WinNT; U)'
859 Netscape 6, Windows NT 4
860 'Mozilla/5.0 (Windows; U; WinNT4.0; en-US; m18) Gecko/20001108 Netscape6/6.0'
862 Netscape Navigator 3.01[de], MacOS 8.1
863 'Mozilla/3.01 [de]-C-MACOS8 (Macintosh; I; PPC)'
865 Netscape Communicator 4.51, SuSE Linux 6.1
866 'Mozilla/4.51 [en] (X11; I; Linux 2.2.13 i686)'
868 Mozilla M17, Windows NT 4
869 'Mozilla/5.0 (Windows; U; WinNT4.0; en-US; m17) Gecko/20000807'
871 Internet Explorer 5.5, Windows NT 4
872 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0)'
874 Internet Explorer 3.0.1, MacOS 8.1
875 'Mozilla/3.0 (compatible; MSIE 3.0.1; Mac_PowerPC; Mac OS8)'
877 Internet Explorer 5.0, MacOS 8.1
878 'Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC)'
880 Internet Explorer 5.0, SPARC Solaris 2.6 (trex)
881 'Mozilla/4.0 (compatible; MSIE 5.0; SunOS 5.6 sun4u; X11)'
883 Konqueror/2.0, SuSE Linux 7.0
884 'Mozilla/5.0 (compatible; Konqueror/2.0; X11); Supports MD5-Digest; Supports gzip encoding'
886 Lynx, SuSE Linux 6.1 (marvin)
887 'Lynx/2.8rel.2 libwww-FM/2.14'
889 Lynx, SPARC Solaris 2.6 (trex)
890 'Lynx/2.7 libwww-FM/2.14'
892 Opera 4.02, Windows NT 4
893 'Mozilla/4.73 (Windows NT 4.0; U) Opera 4.02 [en]'
895 Opera 5.0, Windows NT 4
896 'Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0) Opera 5.0 [en]'
898 Amaya 4.0, Windows NT 4
899 'amaya/V4.0 libwww/5.3.1'
901 XEmacs, SuSE Linux 6.1
902 'Emacs-W3/4.0pre.39 URL/p4.0pre.39 (i686-pc-linux; X11)'
904 XEmacs, SuSE Linux 7.2
905 'Emacs-W3/4.0pre.46 URL/p4.0pre.46 (i386-suse-linux; X11)'
910 Windows 'WebFolder' NT4
911 'Microsoft Data Access Internet Publishing Provider Cache Manager'
912 'Mozilla/2.0 (compatible; MS FrontPage 4.0)'
915 Windows 98 IE 5 WebFolders
916 'Microsoft Data Access Internet Publishing Provider DAV'
919 'OmniWeb/3.0.2 OWF/1999C'
921 Links, SuSE Linux 6.1 (marvin)
922 'Links (0.95; Linux 2.2.13 i686)'
928 fetch/1.0 Darwin/1.3.7 (Power Macintosh)
931 WebDAVFS/1.0 Darwin/5.1 (Power Macintosh)
934 WebDAVFS/1.2.1 (01218000) Darwin/6.1 (Power Macintosh)
937 'cadaver/0.17.0 neon/0.12.0-dev'
940 'GoLive/5. 0 [] (Windows 98; RATBERT)'
943 - (very) small X11 web browser
952 Apple MacOSX 10.2.1 / iCal 1.0 DAV Access Framework
955 Outlook 2000 on W2K with M$ Web Publishing Assistent
956 'Microsoft HTTP Post (RFC1867)'
958 CURL program (libcurl)
959 'curl/7.9.8 (i686-suse-linux) libcurl 7.9.8 (OpenSSL 0.9.6g) (ipv6 enabled)'
961 Evolution 1.0.8 with Exchange Connector (WebDAV)
964 Outlook 2002 on W2K (HotMail HTTP access)
965 'Microsoft-Outlook/10.0 (TmstmpExt)'
967 Outlook Express 5.5 on W2K (HotMail HTTP access)
968 'Outlook-Express/5.5 (MSIE 5.5; Windows NT 5.0; Q312461; T312461; TmstmpExt)'
970 Outlook Express 6.0 on W2K (HotMail HTTP access)
971 'Outlook-Express/6.0 (MSIE 6.0; Windows NT 5.0; Q312461; T312461; TmstmpExt)'
973 Nautilus (GNOME Virtual Filesystem)
976 Konqueror 3.0.3 (SuSE 8.1)
977 - does not send a user-agent in webdav:// mode !
980 'neon/0.23.5 NeonConnection 0.0'
982 Safari v74 (MacOSX 10.2)
983 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/74 (KHTML, like Gecko) Safari/74'
984 - why does it say Mozilla/5.0 ??
986 Evolution 1.4.0 with Exchange Connector 1.4.0 (SuSE 8.2)
989 Mozilla Firebird 0.6 (MacOSX 10.2)
990 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6'
992 SOUP (Evo OGo Connector by Anders)
995 Entourage/X (Entourage WebDAV 10.1.4, MacOSX)
996 'Entourage/10.0 (Mac_PowerPC; DigExt; TmstmpExt)'
998 Some unknown iCal.app
1001 NetNewsWire full version:
1002 'NetNewsWire/1.0.5 (Mac OS X; http://ranchero.com/netnewswire/)'
1004 NetNewsWire lite version:
1005 'NetNewsWire/1.0.3 (Mac OS X; Lite; http://ranchero.com/netnewswire/)'
1008 'xmlrpclib.py/1.0.0 (by www.pythonware.com)'
1010 Windows 2000 IE 6 WebFolders
1011 'Microsoft Data Access Internet Publishing Provider DAV 1.1'
1013 Morgul, Windows WebDAV client
1016 Apple iSync v122 / CoreFoundation Network
1019 Kung-Log (WebServicesCore)
1020 'Kung-Log/1.3 (Macintosh; U; PPC Mac OS X) WebServicesCore'
1022 Ecto (WebServicesCore)
1023 'ecto (Macintosh; U; PPC Mac OS X) WebServicesCore'