    /**
       Copyright (C) 1995-2011 Opera Software ASA. All rights reserved.

       THIS FILE CONTAINS DOCUMENTATION DESCRIBING HOW TO USE THE INTERFACE
       ("API") TO JSPLUGIN, THE MODULAR JAVASCRIPT PLUGIN TECHNOLOGY FOR
       THE OPERA 11 BROWSER LAUNCHED BY OPERA SOFTWARE ASA ("OPERA"). THE
       API TOGETHER WITH DOCUMENTATION AND EXAMPLE CODE IS PUBLICISED BY
       OPERA, AND OPERA IS WILLING TO PERMIT USE OF IT BY YOU ("LICENSEE"),
       ONLY UPON THE CONDITION THAT YOU ACCEPT ALL OF THE TERMS CONTAINED
       IN A SEPARATE API LICENSE AGREEMENT ("AGREEMENT"). PLEASE READ THE
       TERMS AND CONDITIONS OF THIS LICENSE CAREFULLY. BY READING, COPYING
       OR USING THE API IN ANY WAY, YOU ACCEPT THE TERMS AND CONDITIONS OF
       THIS AGREEMENT.  IF YOU ARE NOT WILLING TO BE BOUND, YOU ARE NOT
       ALLOWED TO STUDY THIS API OR MAKE USE OF IT IN ANY WAY.
    */

# HOWTO write an Opera Native JavaScript Extension

## Introduction

Native JavaScript Extensions are provided as a way to interface with the native environment from from the JavaScript environment. A possible use is for set top box manufacturers to control their hardware (eg tv tuners) from an HTML user interface. Other uses could be to create file objects and other functionality that is not included in JavaScript.

Or to quote the internal design draft:

[Native JavaScript Extensions] provide DOM-like functionality on objects that are not part of DOM or JavaScript; these objects may be system-dependent, unsafe, obscure, or otherwise not desirable to include in Opera in general.

## How does it work?

In the current implementation, the directory "jsplugins" under the Opera binary directory is scanned for .dll (W*ndows) files at startup. Under U**X, ~/.opera/jsplugins is scanned for .so files. If the library exports the symbol jsplugin_capabilities (see header file for details), the library is kept loaded, and the plugin is registered.

The plugin can then receive requests to do its stuff. These requests are given via callbacks that have been set during initialization.

## Initialization

To the plugin:

- the plugin exported function jsplugin_capabilities is called when Opera starts up and scans the plugin directory. The function gets the Opera callbacks in the second of its arguments. Keep this for later use.

From the plugin:

- jsplugin_capabilities should fill in a `struct jsplugin_cap` and send it back in `result`. Its fields are:
  - `global_names`: a NULL terminated array of names that the plugin responds to.
  - `global_getter`: responds to requests for the plugin to get one of the names above. See Getters and setters.
  - `global_setter`: responds to requests for the plugin to set one of the names above. See Getters and setters.
  - `init` and `destroy`: initialization and destruction functions for the plugin itself.

`js_plugin_capabilities` should return 0 on success and non-zero otherwise.

## Calling back

Function and regular objects are created in Opera's ecmascript engine via callbacks. The arguments to these callbacks include:

- `refobj`: used for setting up the environment for the object. You get this in most calls. It can also be called `global_context` (eg in `jsplugin_document_init`).
- `getter/setter`: used to get and set names (properties/functions) on the object.
- `f_call`: used for giving the native function to be called when the javascript function is called.
- `constructor`: the constructor for the object.
- `f_signature`: what arguments the function takes. See the About function signatures section.
- `destructor`: the destructor for the object.
- `result`: here you get the object in question.

## About function signatures

Function signatures indicate what arguments a javascript function takes. Basically, one can combine "s" (string), "n" (number), "b" (boolean) and "-" (any object) as one needs.

So, "snb" will make the function take (string, number, boolean) as arguments. If more arguments are passed than is specified in the signature, they are treated as the last type. Thus, a signature of "n" makes the function accept (number, number, number ...) The function signatures actually represents the requested argument conversion, so the "-" character represents no conversion and needs to be used where an object argument is expected. This meens it's possible to write a function that takes an argument "-", that could be of any type and the type checking is done in the function implementation.

It's up to the native implementation to check that the number and type of arguments is meaningful. The number of arguments can usually be found as an argc argument, and the type can be checked in the `type` member of the `struct jsplugin_value`.

## Extending the OBJECT element

Extending the OBJECT element is straightforward, and bears many similarities to creating a custom JavaScript extension. Some notable differences are:

- `jsplugin_cap.object_types` and `jsplugin_cap.handle_object` have to be filled in (see below)
- `jsplugin_cap.global_{getter,setter}` shouldn't be filled in

### The MIME types array

`jsplugin_cap.object_types` is the equivalent to `jsplugin_cap.global_names`, but for OBJECT extensions. Like its colleague, it's a NULL terminated array, but in this case of MIME types that the OBJECT plugin is able to handle.

See the example code for -- examples.

### Handling of object requests

During initialization, one also has to set the field `jsplugin_cap.handle_object`.

When a custom OBJECT is found in the html and the plugin has the right permissions set (see the section Giving permissions to a plugin), this callback will be called.

As parameters, the callback gets a number of parameters:

- a pointer to a global context (see The global context)
- a pointer to the OBJECT object. This can be used to identify what OBJECT is being referred to, and to save plugin private data (see Plugin private data
- the attribute count and the attributes: one can iterate over the attribute list to find out what attributes were given in the html. Eg: `<OBJECT TYPE="application/tve-trigger" ID="triggerReceiverObj"></OBJECT>` gives `attrs_count == 2` and two items in the `attrs` array.
- `getter` and `setter`: these can be used to respond to getname and putname requests to the object. They behave similarly to the getters and setters of javascript plugin objects. See Getters and setters.
- a destructor that will be called when the object is garbage collected.
- two notification callbacks, inserted and removed. these will be called when the OBJECT is inserted and removed from the DOM structure, respectively. Note that this is distinctly different from that the OBJECT is created and destroyed.

It should return one of the JSP_OBJECT_* status types.

## Giving permissions to a plugin

Plugin permissions are used to determine what server may serve content that instansiates and executes code contained in javascript and OBJECT plugins. The default value is that content from no server may access no javascript or OBJECT plugins whatsoever.

To ease this somewhat boring (but very secure) set of default restrictions, plugin permissions can be declared in the `jsplugins.ini` ini file. It is looked for in the same directory as the plugins themselves. This roughly means ~/.opera/jsplugins/ under U**X-like platforms, and `opera_exe_dir/jsplugins/` under W*NDOWS.

### The format

The file should contain a list of plugin permissions on the form `plugin_id: protocol, server, port`, where:

- plugin_id is the file name of the plugin without the path, including its .so/.dll extension
- server is the name or ip address of the server allowed to serve content that uses the plugin in question. There is a syntax for describing that all hosts in a domain should be allowed: `[ALL]`. See the examples
- port is the port number that content is allowed to be served from. 0 (zero, nought) represents the default port, and should be given in all cases where the protocol's default port is used and not explicitly given in the URL. (Note: this means that if you give "http" as the protocol and then give 80 as the port, then you have to always give the protocol in the URL or the content will be blocked.)

An example jsplugins.ini could be:

    triggerreceiver.so: http, myserver.company.com, 0
    videoplayer.so: http, myserver.company.com, 0
    videoplayer.so: http, myserver2.company.com, 8080
    videoplayer.so: file, localhost, 0
    videoplayer.so: http, [ALL].corporation.com, 0

This will allow two of the example plugins via http to be instantiated in content from myserver.company.com on the default port for http. videoplayer.so will also be allowed in content from myserver2.company.com served via http on port 8080, and in content coming via file from localhost.

In addition, the last line indicates that all hosts under the corporation.com domain will be allowed to serve content that instantiates the videoplayer plugin.

### Getting more advanced

There is also a more advanced way of handling permissions, and that is that the plugin itself handles the security permissions, which can be necessary for complex security schemes. If the plugin sets the `jsplugin_cap::allow_access` callback and the keyword `CALLBACK` is in the protocol field of one of the plugin's lines in `jsplugins.ini`, the `allow_access` callback will be called to determine whether the plugin should be allowed to be instantiated or not in a particular document.

    videoplayer.so: CALLBACK

will make the videoplayer's security be handled by itself. If there are multiple lines for a certain plugin where one line states CALLBACK, the behaviour is undefined.

The callback gets the protocol, the hostname of the accessing host and the port number as arguments. It should return non-zero to grant access.

### Comments, whitespace and strictness

There can be comments in the `jsplugins.ini` file, but only on lines for themselves. Comment lines start with # .

Eg

    # this line is a comment

Whitespace is allowed both before the ";" on comment lines and before and in between fields on the permissions lines.

Lines that do not adhere to this (in some ways rather strict) format will be considered invalid and will be discarded.

## The global context

The global context is often given as a parameter to functions in the plugin, and the plugin often has to pass it back into Opera. It can be viewed as a token or a reference to the javascript global context. It enables Opera to create the plugin in the right context, regarding global environment, execution permissions etc.

The plugin cannot do anything with the global context. Just pass it back when required and you'll be fine. ;-)

## Plugin private data

`jsplugin_obj.plugin_private` is a pointer that the plugin can use to store things that it needs to keep in between function calls (its context, basically). The struct `jsplugin_obj` is passed in as a parameter to most functions in the plugin.

Plugin private data has to be allocated and deallocated by the plugin itself. Good places for allocation are eg in the global getters for jsplugin objects (or whereever needed and there exists a `jsplugin_obj`) and in `handle_object` for OBJECT plugins. Deallocation is best performed in the respective plugin instance's destructor.

## Initialization and destruction

A plugin gets to know when a document that is allowed to instantiate the plugin gets created and destroyed. These are useful hooks if the plugin needs to prepare something (for example some global data) when it can be initialized and destroy it when the document is destroyed. The plugin will get calls to `jsplugin_cap::init` and `jsplugin_cap::destroy` to signal these events.

## Getters and setters

Getters and setters occur in a number of places in the javascript plugin api:

- a getter and setter has to be filled in `jsplugin_cap.global_getter` and `jsplugin_cap.global_setter` if the plugin should be able to answer to any requests at all (this applies to custom javascript objects, extension to the OBJECT element can get away without these)
- on the other hand, `jsplugin_cap.handle_object` has to give a getter and a setter for looking up / setting attributes on the element.
- a jsplugin object also has to give a getter and setter for its local names, eg `VideoPlayer.id`.

Note: The getters/setters are quite commonly also being referred to as getname/putname in this documentation. This is what is used in the EcmaScript standard, for example.

Getters and setters are nothing magical. They are used to look up names and, if the names exist, to get or set their values (or call the functions, should they be such creatures). So, reasonable behaviour for a getter is typically to compare the string that is being looked up to the functions/properties that it knows it wants to support, and then create and return either a function object (that will be called from the javascript interpreter) or a javascript value.

When you return a string via the `jsplugin_value.u.string`, the string is copied on the Opera side, and it will be garbage collected duly. However, if you have allocated any memory to construct the string within the plugin itself, you have the responsibility to deallocate it yourself.

When a value is successfully found and returned from a getter, you can return either with the code `JSP_GET_VALUE` or with `JSP_GET_VALUE_CACHE`. If you use the latter, then the property will not be looked up again for the lifetime of the object, but will be cached on the Opera side. This may be useful for performance reasons.

The best documentation on how to do this is probably the code itself. Please have a look at the code in the `examples` directory in this distribution.

## String handling

Most of the time, the API implemented by the plugin does not expect strings to contain null bytes. In this case, string handling is simple: `jsplugin_value.type` will be set to `JSP_TYPE_STRING`, and their value will be stored as a null-terminated string in `jsplugin_value.u.string`. This is true both for values sent to Opera from the plugin and for values sent from Opera to the plugin.

However, it is possible in javascript to have null bytes in the middle of a string. This is sometimes used to store binary data. This is handled differently for strings sent to Opera and strings sent from Opera.

Strings sent from Opera that may contain null bytes will still have their `jsplugin_value.type` field set to `JSP_TYPE_STRING`. The plugin needs to read the `jsplugin_value.u.len` field, which gives the length of the string in bytes, to know if the string extends beyond the first null byte encountered.

To send a string containing null bytes to Opera, the plugin must set `jsplugin_value.type` to `JSP_TYPE_STRING_WITH_LENGTH`, store the string data in `jsplugin_value.u.string` and store the length of the string, in bytes, in `jsplugin_value.u.len`. If `jsplugin_value.type` is set to `JSP_TYPE_STRING`, Opera will ignore the value of`jsplugin_value.u.len`, and will truncate the string at the first null byte.

## Asynchronous operations

It is possible to perform asynchronous getters and function calls which will suspend the ES execution allowing the program to continue as normal. Once the return value is ready the plugin can call opera_callbacks->resume() with a reference object and the execution will continue. This results in the getter or function to be called again and the real value can be returned.

Distinguishing a restart from a normal get or call is done by checking the type of the result parameter. This is set to `JSP_TYPE_UNDEFINED` for normal calls or `JSP_TYPE_NULL` for restarts. When suspending execution the getter or function can set an object in the result parameter. This object will be available when the getter or function is restarted, in which case result will have the type `JSP_TYPE_OBJECT`.

Async getters must return `JSP_GET_DELAYED` while function calls must return `JSP_CALL_DELAYED` to suspend execution.

## Miscellaneous tips

You can write plugins in C++. But remember that the default linkage of a C++ compiled file is C++, so you'll have to put an `export "C"` in front of the plugin's `jsplugin_capabilities` function.