fe4bb30d726e39e894d4e48fdfcd782a17826b16
[WebKit-https.git] / WebCore / khtml / ecma / kjs_navigator.cpp
1 // -*- c-basic-offset: 2 -*-
2 /*
3  *  This file is part of the KDE libraries
4  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
5  *  Copyright (c) 2000 Daniel Molkentin (molkentin@kde.org)
6  *  Copyright (c) 2000 Stefan Schimanski (schimmi@kde.org)
7  *  Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public
11  *  License as published by the Free Software Foundation; either
12  *  version 2 of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25 #include "kjs_navigator.h"
26
27 #include "AtomicString.h"
28 #include "CookieJar.h"
29 #include "Frame.h"
30 #include "Language.h"
31 #include "Node.h"
32 #include "PlugInInfoStore.h"
33 #include "kjs_binding.h"
34
35 using namespace WebCore;
36
37 namespace KJS {
38
39     class PluginBase : public JSObject {
40     public:
41         PluginBase(ExecState *exec);
42         virtual ~PluginBase();
43         
44         void refresh(bool reload);
45
46         static Vector<PluginInfo*> *plugins;
47         static Vector<MimeClassInfo*> *mimes;
48
49     private:
50         static int m_refCount;
51     };
52
53
54     class Plugins : public PluginBase {
55     public:
56         Plugins(ExecState *exec) : PluginBase(exec) {};
57         virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
58         JSValue *getValueProperty(ExecState *, int token) const;
59         virtual const ClassInfo* classInfo() const { return &info; }
60         static const ClassInfo info;
61         enum { Length, Refresh };
62     private:
63         static JSValue *indexGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
64         static JSValue *nameGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
65     };
66
67     class MimeTypes : public PluginBase {
68     public:
69         MimeTypes(ExecState *exec) : PluginBase(exec) { };
70         virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
71         JSValue *getValueProperty(ExecState *, int token) const;
72         virtual const ClassInfo* classInfo() const { return &info; }
73         static const ClassInfo info;
74         enum { Length };
75     private:
76         static JSValue *indexGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
77         static JSValue *nameGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
78     };
79
80     class Plugin : public PluginBase {
81     public:
82         Plugin(ExecState *exec, PluginInfo *info) : PluginBase(exec), m_info(info) { }
83         virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
84         JSValue *getValueProperty(ExecState *, int token) const;
85         virtual const ClassInfo* classInfo() const { return &info; }
86         static const ClassInfo info;
87         enum { Name, Filename, Description, Length };
88     private:
89         static JSValue *indexGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
90         static JSValue *nameGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
91
92         PluginInfo *m_info;
93     };
94
95     class MimeType : public PluginBase {
96     public:
97         MimeType( ExecState *exec, MimeClassInfo *info ) : PluginBase(exec), m_info(info) { }
98         virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
99         JSValue *getValueProperty(ExecState *, int token) const;
100         virtual const ClassInfo* classInfo() const { return &info; }
101         static const ClassInfo info;
102         enum { Type, Suffixes, Description, EnabledPlugin };
103     private:
104         MimeClassInfo *m_info;
105     };
106
107 } // namespace
108
109 #include "kjs_navigator.lut.h"
110
111 namespace KJS {
112
113 const ClassInfo Plugins::info = { "PluginArray", 0, &PluginsTable, 0 };
114 const ClassInfo MimeTypes::info = { "MimeTypeArray", 0, &MimeTypesTable, 0 };
115 const ClassInfo Plugin::info = { "Plugin", 0, &PluginTable, 0 };
116 const ClassInfo MimeType::info = { "MimeType", 0, &MimeTypeTable, 0 };
117
118 Vector<PluginInfo*> *KJS::PluginBase::plugins = 0;
119 Vector<MimeClassInfo*> *KJS::PluginBase::mimes = 0;
120 int KJS::PluginBase::m_refCount = 0;
121
122 const ClassInfo Navigator::info = { "Navigator", 0, &NavigatorTable, 0 };
123 /*
124 @begin NavigatorTable 13
125   appCodeName   Navigator::AppCodeName  DontDelete|ReadOnly
126   appName       Navigator::AppName      DontDelete|ReadOnly
127   appVersion    Navigator::AppVersion   DontDelete|ReadOnly
128   language      Navigator::Language     DontDelete|ReadOnly
129   userAgent     Navigator::UserAgent    DontDelete|ReadOnly
130   platform      Navigator::Platform     DontDelete|ReadOnly
131   plugins       Navigator::_Plugins     DontDelete|ReadOnly
132   mimeTypes     Navigator::_MimeTypes   DontDelete|ReadOnly
133   product       Navigator::Product      DontDelete|ReadOnly
134   productSub    Navigator::ProductSub   DontDelete|ReadOnly
135   vendor        Navigator::Vendor       DontDelete|ReadOnly
136   cookieEnabled Navigator::CookieEnabled DontDelete|ReadOnly
137   javaEnabled   Navigator::JavaEnabled  DontDelete|Function 0
138 @end
139 */
140 KJS_IMPLEMENT_PROTOFUNC(NavigatorFunc)
141
142 Navigator::Navigator(ExecState *exec, Frame *p)
143   : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()), m_frame(p) { }
144
145 bool Navigator::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
146 {
147   return getStaticPropertySlot<NavigatorFunc, Navigator, JSObject>(exec, &NavigatorTable, this, propertyName, slot);
148 }
149
150 JSValue *Navigator::getValueProperty(ExecState *exec, int token) const
151 {
152   String userAgent = m_frame->userAgent();
153   switch (token) {
154   case AppCodeName:
155     return jsString("Mozilla");
156   case AppName:
157     // If we find "Mozilla" but not "(compatible, ...)" we are a real Netscape
158     if (userAgent.find("Mozilla") >= 0 && userAgent.find("compatible") == -1)
159       return jsString("Netscape");
160     if (userAgent.find("Microsoft") >= 0 || userAgent.find("MSIE") >= 0)
161       return jsString("Microsoft Internet Explorer");
162     return jsUndefined();
163   case AppVersion:
164     // We assume the string is something like Mozilla/version (properties)
165     return jsString(userAgent.substring(userAgent.find('/') + 1));
166   case Product:
167     // When acting normal, we pretend to be "Gecko".
168     if (userAgent.find("Mozilla/5.0") >= 0 && userAgent.find("compatible") == -1)
169         return jsString("Gecko");
170     // When spoofing as IE, we use jsUndefined().
171     return jsUndefined();
172   case ProductSub:
173     return jsString("20030107");
174   case Vendor:
175     return jsString("Apple Computer, Inc.");
176   case Language:
177     return jsString(defaultLanguage());
178   case UserAgent:
179     return jsString(userAgent);
180   case Platform:
181     if (userAgent.find("Win", 0, false) >= 0)
182       return jsString("Win32");
183     if (userAgent.find("Macintosh", 0, false) >= 0 || userAgent.find("Mac_PowerPC", 0, false) >= 0)
184       return jsString("MacPPC");
185     // FIXME: What about Macintosh Intel?
186     return jsString("X11");
187   case _Plugins:
188     return new Plugins(exec);
189   case _MimeTypes:
190     return new MimeTypes(exec);
191   case CookieEnabled:
192     return jsBoolean(cookiesEnabled());
193   }
194   return 0;
195 }
196
197 /*******************************************************************/
198
199 PluginBase::PluginBase(ExecState *exec)
200   : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype() )
201 {
202     if (!plugins) {
203         plugins = new Vector<PluginInfo*>;
204         mimes = new Vector<MimeClassInfo*>;
205         
206         // read configuration
207         PlugInInfoStore c;
208         unsigned pluginCount = c.pluginCount();
209         for (unsigned n = 0; n < pluginCount; n++) {
210             PluginInfo* plugin = c.createPluginInfoForPluginAtIndex(n);
211             if (!plugin) 
212                 continue;
213             
214             plugins->append(plugin);
215             if (!plugin->mimes)
216                 continue;
217             
218             Vector<MimeClassInfo*>::iterator end = plugin->mimes.end();
219             for (Vector<MimeClassInfo*>::iterator itr = plugin->mimes.begin(); itr != end; itr++)
220                 mimes->append(*itr);
221         }
222     }
223
224     m_refCount++;
225 }
226
227 PluginBase::~PluginBase()
228 {
229     m_refCount--;
230     if ( m_refCount==0 ) {
231         deleteAllValues(*plugins);
232         delete plugins;
233         deleteAllValues(*mimes);
234         delete mimes;
235         plugins = 0;
236         mimes = 0;
237     }
238 }
239
240 void PluginBase::refresh(bool reload)
241 {
242     deleteAllValues(*plugins);
243     delete plugins;
244     deleteAllValues(*mimes);
245     delete mimes;
246     plugins = 0;
247     mimes = 0;
248     refreshPlugins(reload);
249 }
250
251
252 /*******************************************************************/
253
254 /*
255 @begin PluginsTable 2
256   length        Plugins::Length         DontDelete|ReadOnly
257   refresh       Plugins::Refresh        DontDelete|Function 0
258 @end
259 */
260 KJS_IMPLEMENT_PROTOFUNC(PluginsFunc)
261
262 JSValue *Plugins::getValueProperty(ExecState *exec, int token) const
263 {
264   assert(token == Length);
265   return jsNumber(plugins->size());
266 }
267
268 JSValue *Plugins::indexGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
269 {
270     return new Plugin(exec, plugins->at(slot.index()));
271 }
272
273 JSValue *Plugins::nameGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
274 {
275     AtomicString atomicPropertyName = propertyName;
276     Vector<PluginInfo*>::iterator end = plugins->end();
277     for (Vector<PluginInfo*>::iterator itr = plugins->begin(); itr != end; itr++) {
278         PluginInfo *pl = *itr;
279         if (pl->name == atomicPropertyName)
280             return new Plugin(exec, pl);
281     }
282     return jsUndefined();
283 }
284
285 bool Plugins::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
286 {
287     const HashEntry* entry = Lookup::findEntry(&PluginsTable, propertyName);
288     if (entry) {
289       if (entry->attr & Function)
290         slot.setStaticEntry(this, entry, staticFunctionGetter<PluginsFunc>);
291       else
292         slot.setStaticEntry(this, entry, staticValueGetter<Plugins>);
293       return true;
294     } else {
295         // plugins[#]
296         bool ok;
297         unsigned int i = propertyName.toUInt32(&ok);
298         if (ok && i < plugins->size()) {
299             slot.setCustomIndex(this, i, indexGetter);
300             return true;
301         }
302
303         // plugin[name]
304         AtomicString atomicPropertyName = propertyName;
305         Vector<PluginInfo*>::iterator end = plugins->end();
306         for (Vector<PluginInfo*>::iterator itr = plugins->begin(); itr != end; itr++) {
307             if ((*itr)->name == atomicPropertyName) {
308                 slot.setCustom(this, nameGetter);
309                 return true;
310             }
311         }
312     }
313
314     return PluginBase::getOwnPropertySlot(exec, propertyName, slot);
315 }
316
317 /*******************************************************************/
318
319 /*
320 @begin MimeTypesTable 1
321   length        MimeTypes::Length       DontDelete|ReadOnly
322 @end
323 */
324
325 JSValue *MimeTypes::getValueProperty(ExecState *exec, int token) const
326 {
327   assert(token == Length);
328   return jsNumber(plugins->size());
329 }
330
331 JSValue *MimeTypes::indexGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
332 {
333     return new MimeType(exec, mimes->at(slot.index()));
334 }
335
336 JSValue *MimeTypes::nameGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
337 {
338     AtomicString atomicPropertyName = propertyName;
339     Vector<MimeClassInfo*>::iterator end = mimes->end();
340     for (Vector<MimeClassInfo*>::iterator itr = mimes->begin(); itr != end; itr++) {
341         MimeClassInfo *m = (*itr);
342         if (m->type == atomicPropertyName)
343             return new MimeType(exec, m);
344     }
345     return jsUndefined();
346 }
347
348 bool MimeTypes::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
349 {
350     const HashEntry* entry = Lookup::findEntry(&MimeTypesTable, propertyName);
351     if (entry) {
352       slot.setStaticEntry(this, entry, staticValueGetter<Plugins>);
353       return true;
354     } else {
355         // mimeTypes[#]
356         bool ok;
357         unsigned int i = propertyName.toUInt32(&ok);
358         if (ok && i < mimes->size()) {
359             slot.setCustomIndex(this, i, indexGetter);
360             return true;
361         }
362
363         // mimeTypes[name]
364         AtomicString atomicPropertyName = propertyName;
365         Vector<MimeClassInfo*>::iterator end = mimes->end();
366         for (Vector<MimeClassInfo*>::iterator itr = mimes->begin(); itr != end; itr++) {
367             if ((*itr)->type == atomicPropertyName) {
368                 slot.setCustom(this, nameGetter);
369                 return true;
370             }
371         }
372     }
373
374     return PluginBase::getOwnPropertySlot(exec, propertyName, slot);
375 }
376
377
378 /************************************************************************/
379
380 /*
381 @begin PluginTable 4
382   name          Plugin::Name            DontDelete|ReadOnly
383   filename      Plugin::Filename        DontDelete|ReadOnly
384   description   Plugin::Description     DontDelete|ReadOnly
385   length        Plugin::Length          DontDelete|ReadOnly
386 @end
387 */
388
389 JSValue *Plugin::getValueProperty(ExecState *exec, int token) const
390 {
391     switch (token) {
392     case Name:
393         return jsString(m_info->name);
394     case Filename:
395         return jsString(m_info->file);
396     case Description:
397         return jsString(m_info->desc);
398     case Length: 
399         return jsNumber(m_info->mimes.size());
400     default:
401         assert(0);
402         return jsUndefined();
403     }
404 }
405
406 JSValue *Plugin::indexGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
407 {
408     Plugin *thisObj = static_cast<Plugin *>(slot.slotBase());
409     return new MimeType(exec, thisObj->m_info->mimes.at(slot.index()));
410 }
411
412 JSValue *Plugin::nameGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
413 {
414     Plugin *thisObj = static_cast<Plugin *>(slot.slotBase());
415     AtomicString atomicPropertyName = propertyName;
416     Vector<MimeClassInfo*>::iterator end = thisObj->m_info->mimes.end();
417     for (Vector<MimeClassInfo*>::iterator itr = thisObj->m_info->mimes.begin(); itr != end; itr++) {
418         MimeClassInfo *m = (*itr);
419         if (m->type == atomicPropertyName)
420             return new MimeType(exec, m);
421     }
422     return jsUndefined();
423 }
424
425
426 bool Plugin::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
427 {
428     const HashEntry* entry = Lookup::findEntry(&PluginTable, propertyName);
429     if (entry) {
430         slot.setStaticEntry(this, entry, staticValueGetter<Plugin>);
431         return true;
432     } else {
433         // plugin[#]
434         bool ok;
435         unsigned int i = propertyName.toUInt32(&ok);
436         if (ok && i < m_info->mimes.size()) {
437             slot.setCustomIndex(this, i, indexGetter);
438             return true;
439         }
440
441         // plugin["name"]
442         AtomicString atomicPropertyName = propertyName;
443         Vector<MimeClassInfo*>::iterator end = m_info->mimes.end();
444         for (Vector<MimeClassInfo*>::iterator itr = m_info->mimes.begin(); itr != end; itr++) {
445             if ((*itr)->type == atomicPropertyName) {
446                 slot.setCustom(this, nameGetter);
447                 return true;
448             }
449         }
450     }
451
452     return PluginBase::getOwnPropertySlot(exec, propertyName, slot);
453 }
454
455 /*****************************************************************************/
456
457 /*
458 @begin MimeTypeTable 4
459   type          MimeType::Type          DontDelete|ReadOnly
460   suffixes      MimeType::Suffixes      DontDelete|ReadOnly
461   description   MimeType::Description   DontDelete|ReadOnly
462   enabledPlugin MimeType::EnabledPlugin DontDelete|ReadOnly
463 @end
464 */
465
466 JSValue *MimeType::getValueProperty(ExecState *exec, int token) const
467 {
468     switch (token) {
469     case Type:
470         return jsString(m_info->type);
471     case Suffixes:
472         return jsString(m_info->suffixes);
473     case Description:
474         return jsString(m_info->desc);
475     case EnabledPlugin: {
476         ScriptInterpreter *interpreter = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
477         Frame *frame = interpreter->frame();
478         if (frame && frame->pluginsEnabled())
479             return new Plugin(exec, m_info->plugin);
480         else
481             return jsUndefined();
482     }
483     default:
484         return jsUndefined();
485     }
486 }
487
488 bool MimeType::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
489 {
490     return getStaticValueSlot<MimeType, PluginBase>(exec, &MimeTypeTable, this, propertyName, slot);
491 }
492
493 JSValue *PluginsFunc::callAsFunction(ExecState *exec, JSObject *, const List &args)
494 {
495     PluginBase(exec).refresh(args[0]->toBoolean(exec));
496     return jsUndefined();
497 }
498
499 JSValue *NavigatorFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &)
500 {
501   if (!thisObj->inherits(&KJS::Navigator::info))
502     return throwError(exec, TypeError);
503   Navigator *nav = static_cast<Navigator *>(thisObj);
504   // javaEnabled()
505   return jsBoolean(nav->frame()->javaEnabled());
506 }
507
508 } // namespace