Showing posts with label PAW. Show all posts
Showing posts with label PAW. Show all posts

Saturday, December 19, 2015

Chatting with Binary Web Sockets

This is a follow up article to Chatting with Web Sockets.
Since version 0.97 beta, PAW Server supports binary Web Sockets. Before that only text base Web Sockets were supported.

Binary Web Sockets have the benefit (as the name implies) that binary Blobs (Binary Large Objects) can be exchanged. That offers the possibility to exchange binary data. This blog post shows how to use binary Web Sockets to build a simple (multi-) media chat client by using these new capabilities.

Bellow is a screenshot of the new chat window which also allows to drag and drop (media) files to send them to connected clients. There are two drop areas, the button titled Drop / Select and the message output area. In addition files can be selected by pressing the Drop / Select button.

Chat Window

Supported file types depend on the used browser, but normally audio, video, text and html files should work.

The setup is almost identical to the one described inside the former post Chatting with Web Sockets.
Only the ZIP file including HTML/CSS and JavaScript files are different. You'll find a link to the ZIP file below that post.

So to make sure Web Sockets are setup correctly follow the following steps from the post Chatting with Web Sockets:
  1. Configuring the Web Socket Handler
  2. Web Socket Config File
  3. The BeanShell Script
After the configuration is finished, the only thing left is to extract the ZIP file into a folder (e.g. chat2) of your choice inside the [PAW_HOME]/html folder (usually /sdcard/paw) and to call that page from a browser.

You can now try to connect to the web page (e.g. http://<ip>:8080/chat2/) with multiple browsers and see if the chat is working.

Have fun and merry Xmas :)

Links


Sunday, December 6, 2015

Extending Handlers with BeanShell

This post will show how to extend an existing handler by using BeanShell.
Since PAW 0.96 BeanShell can be used to write handlers (and filters). In earlier versions of PAW handlers and filters had to be provided as Java class file, so a Java development environment was needed. By the use of BeanShell handlers and filters can now be developed directly on an Android device. This is especially handy when developing handler and filters for testing.

PAW Standard Handler Chain

I’ll briefly recap what handlers are good for.
Handlers form the processing chain on HTTP requests. Handler are organized in a list that is processed until a handler processing the request is found. If a handler signals that it can handle the request, the handler will process the request and the list of handlers is no longer processed.

In the example we will extend the BasicAuthHandler which handles the basic authentication to protect a web resource (most often a directory).
The handler will be extended in the way, that it will only request credentials if pages are called from external, localhost request should not need to authenticate.

The standard BasicAuthHandler does not provide this functionality. It always asks for credentials, regardless where the request came from.

Since PAW 0.96 there is a new handler called CallBshHandler which accepts a BeanShell file to act as a handler.

The BeanShell file has the following base structure:

/*
    Variables: server, prefix, handler
*/
init() {

}

/*
    Variables: server, prefix, handler, request
*/
respond() {

}

There are the two methods init() and respond(). Both methods return true on success and false on failure. The init() method receives the server, prefix and handler variables. The server and prefix variables are needed to get configuration parameters specified inside the conf/handler.xml file. The handler variable holds a reference to the calling CallBshHandler  instance. This instance is needed to persist settings (between init() and response()) methods. This is necessary, because init() and response() are not called within the same BeanShell interpreter instance (to make the handler thread safe). To persists objects within the handler, the methods save() and load() are provided. The example will show how these methods are used.

Extending the current BasicAuthHandler will be done in three steps:
  1. Disable the BasicAuthHandler
  2. Create the new handler
  3. Configure the new  handler

Disable the BasicAuthHandler

To disabling the current BasicAuthHandler, find the following handler in the conf/handler.xml file and change the  status property to inactive
<handler status="inactive">
    <name>Basic Auth Handler</name>
   …
</hadler>

Create the New Handler

We will now build a handler that calls the standard BasicAuthHandler only on external requests. Local requests, which have the IP number 127.0.0.1 or ::1 will not be processed and so no credentials will be requested.

To build the new handler, create a directory handler inside the PAW installation folder (paw/handler). Inside that folder create a file called authHandler.bsh with the following content:

import org.paw.handler.BasicAuthHandler;

LOCALHOST = "127.0.0.1";
LOCALHOST_V6 = "::1";

/*
    Variables: server, prefix, handler
*/
init() {
    authHandler = new BasicAuthHandler(); 
    handler.save("authHandler", authHandler);

    return authHandler.init(server, prefix);

}

/*
    Variables: server, prefix, handler, request
*/
respond() {
    ip = request.sock.getInetAddress().getHostAddress();

    if(ip.equals(LOCALHOST) || ip.equals(LOCALHOST_V6)) {
        return false;
    }

    authHandler = handler.load("authHandler");
    return authHandler.respond(request);
}

The code is straightforward. Inside the init() method the BasicAuthHandler is instantiated. That instance is saved within the calling handler by calling handler.save().
The last line of the init() method returns the result of the call to init() of the instantiated BasicAuthHandler class.

If the init() method returns true, the handler will be added to the list of handlers and the respond()method will be called on each request.

When the respond() method is called it first gets the requestor’s IP number and assigns it to the variable ip. If the variable contains a localhost IP (127.0.0.1 or ::1) the method returns false, which indicates that the handler will not handle the request.
In that case no credentials are requested and the handler chain is further processed.

If the request is not initiated by a localhost address, the respond() method of the BasicAuthHandler instance is called and the return value of that method is returned.


Configure the New Handler

To configure the new handler, just place the following handler definition below or above the original BasicAuthHandler definition of the conf/hander.xml file:

<handler status="active">
    <name>BeanShell auth handler</name>
    <description>Auth handler that allows local access</description>
    <removable>true</removable>
    <id>bshAuth</id>
    <files/>
    <params>
      <param name="bshAuth.class" value="org.paw.handler.CallBshHandler" />
      <param name="bshAuth.script" value="[PAW_HOME]/handler/authHandler.bsh" />
      <param name="bshAuth.confdir" value="[PAW_HOME]/webconf/auth" />
    </params>
  </handler>

The parameters describe the class (org.paw.handler.CallBshHandler) and script ([PAW_HOME]/handler/authHandler.bsh) to use. The third parameter called confdir is the standard configuration parameter used by the BasicAuthHandler. The BeanShell handler passes this parameter when calling the BasicAuthHander.init() method from its init() method.

Because the new handler calls the standard handler, the Directory Protection settings from within PAW’s web interface also apply to the new handler.

On next startup of the server the new handler should be active. If the startup fails, increase the log level, restart the server and have a look at the log file.

Testing the Handler

To test the handler, I’ve created a directory test within the html folder (html/test). For the at folder, directory protection has been setup using the Directory Protection page of the web interface.
The localhost connection was tested by using ADB’s TCP forward parameter (adb forward tcp:8080 tcp:8080).

When testing with an IP number, authentication is required:

$ telnet 192.168.178.79 8080
Trying 192.168.178.79...
Connected to 192.168.178.79.
Escape character is '^]'.
GET /test/ HTTP/1.0

HTTP/1.0 401 Unauthorized
WWW-Authenticate: basic realm="Bsh Auth Test"
Date: Sun, 06 Dec 2015 09:05:38 GMT
Server: PAW Server 0.97-android (Brazil/2.0)
Connection: close
Content-Length: 34
Content-Type: text/html

Missing http header: AuthorizationConnection closed by foreign host.

On a localhost request, no authentication is needed and the directory listing is displayed:

$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /test/ HTTP/1.0

HTTP/1.0 200 OK
Set-Cookie: cookie=7th5kto9f4nrf1a5r8pdse; PATH=/
Date: Sun, 06 Dec 2015 09:08:32 GMT
Server: PAW Server 0.97-android (Brazil/2.0)
Connection: close
Content-Length: 99
Content-Type: text/html

<title>Directory Listing</title>
<h1>Directory Listing</h1>
<a href=..><b>parent directory</b></a>
Connection closed by foreign host.

Saturday, October 3, 2015

PAW - New Tags

Since PAW Server 0.96 BeanShell tag handling in XHTML files has been improved. In addition PHP like tags are now supported.
In older PAW versions it was a bit cumbersome to write XHTML pages because BeanSHell and HTML could not be mixed. The following code would not have worked:

<bsh>if(i > 0) {</bsh>
<h3>TEST</h3>
<bsh>}</bsh>

This code now works in the new PAW version, because PAW does no longer execute BeanShell blocks separately but does build  complete BeanShell script representing the page that is executed as a whole.

The old tags <bsh> ... </bsh> still do work, but in addition PHP like <?bsh ... ?> tags are available.
Here is a short example:

<?bsh if(i > 0) { ?>
<h3>TEST</h3>
<?bsh } ?>

To make it easier to output BeanShell variables inside HTML code easier the short print tag <?= ... ?>  is now available:

<?bsh i = 7; { ?>
<b>Value of i = </b> <?=i ?>
<?bsh } ?>

Debugging

Sometimes BeanShell error output in XHTML pages might be hard to read and it sometimes makes development more complicated than it should be.

A BeanShell error output that is visible inside the HTML source looks like this:

<!--
BeanShell Error:

bsh.EvalError: Sourced file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : Attempt to resolve method: getProximity() on undefined variable or class name: sensorListener : at Line: 6 : in file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : sensorListener .getProximity ( ) 

-->

Now that the whole page is executed as one entity there is the possibility to show the generated code inside the HTML page source when an error occurred.
By default this feature is disabled (not everyone should see your code), but while developing it's a good idea to turn it on.

To enable the enhanced debug output, change the the value of the bsh.debug property inside the paw/con/handler.xml from false to true and restart the server.

<param name="bsh.debug" value="true" />

The above sample error message is now enhanced with the generated BeanShell code.

<!--
BeanShell Error:

bsh.EvalError: Sourced file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : Attempt to resolve method: getProximity() on undefined variable or class name: sensorListener : at Line: 6 : in file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : sensorListener .getProximity ( ) 

-->

<!--
Generated BeanShell Code:

  1    $$.print("<html>\n<body>\n");
  2    // Imports
  3    import de.fun2code.android.pawserver.AndroidInterface;
  4    import android.content.Context;
  5    import android.hardware.Sensor;
  6    sensorListener = AndroidInterface.getSensorListener();
* 7    proximity = sensorListene.getProximity();

-->

If possible the erroneous line is marked with an asterisk (*). This should make finding the error much easier.

Tuesday, September 22, 2015

Digest Authentication

Although the PAW Server configuration does not include Digest Authentication by default, this authentication scheme is available and can be configured inside the paw/conf/handler.xml configuration file.

To enable Digest Authentication, add the following lines to  the paw/conf/handler.xml file just after the opening <handlers> tag:

  <handler status="active">
    <name>Digest Handler</name>
    <description>Digest authentication handler.</description>
    <removable>true</removable>
    <id>authDigest</id>
    <files/>
    <params>
      <param name="authDigest.class" value="sunlabs.brazil.handler.DigestAuthHandler" />
      <param name="authDigest.prefix" value="/" />
      <param name="authDigest.realm" value="Protected" />
      <param name="authDigest.credentials" value="[PAW_HOME]/webconf/auth/digest.conf" />
    </params>
  </handler>

This configuration protects the whole web site, if you would only like to protect a single directory, you can change the prefix parameter.

Now create a file called paw/webconf/auth/digest.conf with the following content:

#---------------------------------------------------------
# Digest Authenticatin configuration
#---------------------------------------------------------
# Format:
# username=plain password
#
# Instead of the plain password, HA1 can be used:
# md5(user:realm:pass)
#
# username=HA1
#---------------------------------------------------------
user=test

The sample user is called user, with the password test.
It is recommended to build the HA1 hash for security reasons.

For the changes to take effect, restart the server.

Saturday, August 15, 2015

Advanced PAW Server - Pre-Release 1

PAW's documentation is far from perfect and I often get questions from users how things work. To make life for users and me easier I decided to write an eBook how to use PAW's API to write dynamic web applications.

This is the first pre-release of Advanced PAW Server.




It is not complete and surely contains a lot of bugs and typos.
Nevertheless I hope it is already useful at this point.

Have fun :)

The eBook is available in PDF format.

Here is the download Link:
https://goo.gl/6BDgno

Wednesday, December 10, 2014

PAW - Using JavaMail

I got a question (hello Guy) regarding sending mails via PAW Server.
In this use case an Arduio Uno sends HTTP request to PAW which then sends a mail via SMTP to a mail relay.

 ---------                 ---------------
| Arduino | ---- HTTP --> | Android / PAW | ---- SMTP --> 
 ---------                 ---------------
So far for the setup seems quite easy.
Unfortunately (as so often) this is not as easy as it seems. The Android API does not include means to send mails via SMTP. Something like JavaMail is not included.
This post will show how to use JavaMail together with PAW to implement the above use case.
You'll find a Short and a Long Version. The Short Version contains only the necessary downloads and scripts to get things running.
For those interested in technical detail there is the Long Version which will explain things in more detail.
There is a pitfall when using Gmail. So in case you are a Gmail user, please read Using Gmail in addition.

Short Version

Download this paw_javamail.zip ZIP file from Google Drive and extract it to your PAW installation folder (normally /sdcard/paw) inside the webconf/dex folder.
The ZIP file contains the JavaMail libraries from the javamail-android project together with an utility library to make sending of mails via PAW easier.

After a restart of PAW Server everything should be setup to send mails from the BeanShell console.

Here is a test script:

useDexClasses();

import de.fun2code.paw.mail.*;

// Construct a mail class that holds all the server settings
mail = new Mail("smtp.gmail.com", 587, "user@gmail.com", 
      "password", Mail.TransportType.TLS);

// Send an SMTP message including attachments
mail.sendSmtp("sender@gmail.com", "recipient@whatever.com",
              "Test subject", "Test message ...", new File[] { new File("/sdcard/image1.jpg"), new File("/sdcard/image2.jpg") });


First we create a mail object that holds the SMTP server, authentication and connection settings.
The connection are in this example set to TLS, but could also be SSL or PLAIN.
In this case Gmail ist used but could be any other provider.

The sendSmtp method implements the sending of the mail message and takes sender, recipient, subject, body message and an attachment File array as parameter.
If no attachments should be added, just pass null as parameter.

In case of Gmail you'll have to take additional steps to get this working, please read Using Gmail below.

Using Gmail

When using Gmail, the following Exception is likely to occur:

javax.mail.AuthenticationFailedException

The reason for this is that Google does not allow third party apps to access Gmail by default.
In my case I got a mail from Google which included the following link to lower my Gmail security:

https://www.google.com/settings/security/lesssecureapps

After lowering security, everything worked as expected.

Long Version

Let's get a bit into detail ...

Why is it necessary to use the files form the javamail-android project and why is a separate utility class needed for sending mails?

My first take on JavaMail was to download the JavaMail JAR file from the official Oracle web site and use it within PAW. For JAR files to work on Android devices they have to be converted into Dalvic Executable (DEXed) format. For more info about DEXing, you can have a look at the following blog post: PAW - Dynamic DEX Class Loading

Not all classes can bed converted into DEX format, some just don't work. That's the case with the Activation classes needed by JavaMail. That's why the official libraries cannot be used.
Here comes the javamail-android project to the rescue which provides DEXable JavaMail libraries.
These are the library included inside the  paw_javamail.zip ZIP file.

Inside the ZIP file as well comes a  DEXed version of the de.fun2code.paw.mail.Mail class which implements the sending of SMTP messages. Why do we need that class, couldn't we have just put all that code insde a BeanShell script?

In principle yes, but BeanShell on Android does not have the possibility to compile all (inner) classes. That's just not working for the authentication part of JavaMail. So that's why there is this precompiled additional class, which in addition also has the advantage of being faster than the equivalent BeanShell code.

Below is the complete de.fun2code.paw.mail.Mail class which uses plain JavaMail.


package de.fun2code.paw.mail;

import java.io.File;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

/**
 * Class that contains methods to send SMTP messages via JavaMail
 */
public class Mail {
 public static enum TransportType  {
  PLAIN, TLS, SSL
 };
 
 private TransportType transport;
 private String smtpServer;
 private int smtpPort;
 private String username;
 private String password;
 
 /**
  * The constructor takes the basic connection parameters
  * 
  * @param smtpServer  SMTP server name
  * @param smtpPort  SMTP server name
  * @param username  authentication user name
  * @param password  authentication password
  * @param transport  transport type: PLAIN, TLS or SSL
  */
 public Mail(String smtpServer, int smtpPort, String username,
   String password, TransportType transport) {
  this.smtpServer = smtpServer;
  this.smtpPort = smtpPort;
  this.username = username;
  this.password = password;
  this.transport = transport;
 }

 /**
  * Sends a SMTP mail message
  * 
  * @param from     sender name
  * @param to     recipient name
  * @param subject    mail subject
  * @param messageText   body text
  * @param attachments   attachments to attach
  * @throws MessagingException
  */
 public void sendSmtp(String from, String to,
   String subject, String messageText, File[] attachments) throws MessagingException {

  String strPort = String.valueOf(smtpPort);
  
  // Fill basic properties
  Properties props = new Properties();
  props.put("mail.smtp.host", smtpServer);
  props.put("mail.smtp.auth", "true");
  props.put("mail.smtp.port", strPort);
  
  // Add connection properties
  switch(transport) {
   case TLS:
    props.put("mail.smtp.starttls.enable", "true");
    break;
   case SSL:
    System.out.println("Using SSL ...");
    props.put("mail.smtp.socketFactory.port", strPort);
    props.put("mail.smtp.socketFactory.class",
      "javax.net.ssl.SSLSocketFactory");
    break;
   case PLAIN:
    break;
  }
  

  // Create the session
  Session session = Session.getInstance(props,
    new javax.mail.Authenticator() {
     protected PasswordAuthentication getPasswordAuthentication() {
      return new PasswordAuthentication(username, password);
     }
    });

  try {
   // Create MimeMessage
   Message message = new MimeMessage(session);

   // Set from header
   message.setFrom(new InternetAddress(from));

   // Set to header
   message.setRecipients(Message.RecipientType.TO,
     InternetAddress.parse(to));

   // Add subject
   message.setSubject(subject);
   
   // Add attachments if available
   if(attachments != null) {
    Multipart multipart = new MimeMultipart();
    
    // The body message
    MimeBodyPart textPart = new MimeBodyPart();
    textPart.setText(messageText, "utf-8");
    multipart.addBodyPart(textPart);
    
    for(File file : attachments) {
     MimeBodyPart messageBodyPart = new MimeBodyPart();
           DataSource source = new FileDataSource(file.getAbsoluteFile());
           messageBodyPart.setDataHandler(new DataHandler(source));
           messageBodyPart.setFileName(file.getName());
           multipart.addBodyPart(messageBodyPart);
    }
    
    message.setContent(multipart);
   }
   else {
    // Add the body message
    message.setText(messageText);
   }

   // Send the message
   Transport.send(message);

  } catch(MessagingException e) {
   throw e;
  }
  
 }

}


Wednesday, September 18, 2013

Chatting with Web Sockets

Web Sockets enable direct socket connections between a web browser and a web server.
Newer versions of PAW support text based Web Sockets. This post shows how to build a small Web Sockets based chat server.

If you have ever tried coding a web based chat server you have surely noticed that the task is not as easy as it might seem at the first look. You have to deal with sessions and have to synchronize clients and so forth. That’s one of the reasons why I never did that ;).
We will see that with Web Sockets there are only a few lines of code necessary on the server side.

I will not go into much detail when it comes to the HTML part, this is standard and everybody can google that.
What I will explain in detail is the PAW setup and the server side BeanShell script included in implementing the chat server.

Configuring the Web Socket Handler

To enable Web Socket support for your PAW server, we have to insert and configure the Web Socket handler inside the handler.xml file. The file is located inside the conf folder of your PAW installation directory . The installation directory is normally /sdcard/paw. Inside the handler.xml file the installation directory is referenced as [PAW_HOME].

The handler can be places right in front of the configuration file inside the <handlers>...</handlers>
tag:

<handler status="active">
    <name>WebSocket Handler</name>
    <description>WebSocket Handler</description>
    <removable>true</removable>
    <id>websocket</id>
    <files/>
    <params>
      <param name="websocket.class" value="org.paw.handler.android.websocket.WebSocketHandler" />
      <param name="websocket.basedir" value="[PAW_HOME]" />
      <param name="websocket.config" value="[PAW_HOME]/webconf/websocket.conf" />
    </params>
  </handler>

There are two important parameters in that handler definition… basedir and config.

Let’s start with config. The parameter config specifies the location of the Web Socket definition file. This file defines rules that describe which BeanShell script (or Java class) to call if a Web Socket connection requesting a specific protocol comes along.

A Web Socket communication can specify a protocol to use, which makes it possible for the server to react differently even if listening to the same port.
A common protocol type is chat which the client sends to the server within the header when the connection is established. You can also define your own protocol, it’s just a text.

In our example the web browser will send a different protocol for each chat room which makes it possible for the server to distinguish them. So if a chat room is called talk, the protocol will be chat.talk.

The other parameter basedir defines the base directory of the BeanShell scripts which are defined inside the Web Socket configuration file.

In the next step, we’ll create the Web Socket config file.

Web Socket Config File

As defined in the handler definition, create a file called [PAW_HOME]/webconf/websocket.conf with the following content:

# Format:
# Protocol:Bsh script (.bsh extension) or class name
#
chat.*:html/websocket/websocket_chat.bsh

That’s it, actually quite simple. I’ll quickly explain the syntax.
The parameters are devided by colons.

First parameter is the protocol which is defined as a regular expression. So in our case the server will call the script html/websocket/websocket_chat.bsh for all protocols starting with chat. Now you already know the second parameter which is the BeanShell script to call.

Actually you can also use a Java class (or performance reasons) but this will not be handled inside this post. More about how to get this working with Java classes can be found inside the PAW Functions section of the PAW web interface.

The next step is to create the BeanShell script.

The BeanShell Script

Before creating the script, some infos in advance.
The handler sets some variables before it calls the script. These variables are action, message, sockets and socket.
The action variable tells us something about the state of the communication. Possible values are connect, disconnect  or text. The state important for us is text because it indicated that a text message has been sent by a client.

If text is set, there is also a variable called message which contains the message itself.

Let’s now have a look at the code, because I think will make things clearer.
Create a file called [PAW_HOME]/html/websocket/websocket_chat.bsh
 with the following content:

import de.fun2code.android.pawserver.websocket.WebSocketMessage;

if(action.equals("text")) {
    for(sock : sockets) {
        try {
            WebSocketMessage.sendMessage(message, sock);
        }
        catch(e) {
          sock.close();
        }
    }
}

That’s the complete server side code. First thing that is checked is if the action variable is set to text which indicates that a message text is available inside the message variable.

If a message is present the code iterates over the sockets collection. The sockets collection contains all client socket connections that have the same protocol.
The socket collections are grouped by Web Socket protocol names, so we are sure that all sockets inside the collection belong to the same chat room.
As mentioned above, the web browser sends different Web Socket protocol names for each chat room (chat.>chatroom>).

So all that is left is to send the incoming message to all connected client. This is done by the following line:

 WebSocketMessage.sendMessage(message, sock);

The try/catch block is there to close a socket if something goes wrong.

One variable that is not present in the code and therefore was not handled until now is the socket variable. This variable contains the socket of the client that delivered the message.

The HTML File

The only thing that is missing is now the HTML file that is responsible for opening the Web Socket connection from the web browser. This is actually a XHTML file because it contains some additional BeanShell code.

The file can be downloaded from the link below. Just copy it into the [PAW_HOME]/html/websocket/ directory.
Now you can start your browser and call the XHTML file by inserting the following address into your browser’s address bar:

http://<ip>:<port>/websocket/chat.xhtml

Web Socket Chat

If everything goes well, the Web Socket chat server should be up and running.
In case of questions, write a comment or send me a mail.

Happy coding :)

Links

XHTML File: websocket_chat_xhtml.zip

Monday, September 16, 2013

PAW - Build Your Own Server


A lot of people have been asking about the PAW source code.
PAW is not Open Source, so (for the time being) you cannot get the source.

Nevertheless … it is now possible for developers to build their own PAW based apps for private and educational purposes. If you plan to use PAW in a commercial product, please drop me a line.

To make this easy, the PAW source code has been restructured.
A sample project along with documentation and a sample APK can be downloaded form the links listed below.
The process of creating a PAW based app should quite easy. Please read the linked documentation for detailed instructions.

 … happy coding! :)

Links:

Documentation: Build_Own_PAW_Server.pdf
Eclipse Project: BuildOwnPawServer.zip
Sample APK: BuildOwnPawServer.apk

Sunday, December 30, 2012

PAW - Using other Languages with CGI

This post is about using other languages apart from BeanShell and PHP. PAW includes a CGI Handler to execute scripts by using the Common Gateway Protocol (CGI). This handler is also used by the PHP plugin to call the CGI version of PHP. The handler is defined inside the file PAW_HOME/conf/handler.XML. Instead of using PHP we will use Perl to create a simple web page.

Finding the Executable Path

First thing to do is to install the SL4A and Perl APK from the Android Scripting Project: http://code.google.com/p/android-scripting/downloads/list After installing the APKs and extracting Perl it's time to find out where the Perl executable is located. One way to do it is to execute the Perl interpreter and to use a terminal emulator and run the ps command. In the case of Perl the executable is located here: /data/data/com.googlecode.perlforandroid/files/perl/perl

CGI Configuration

Now it's time to edit the PAW handler configuration. Open the file PAW_HOME/conf/handler.XML and add the following lines below the Basic Auth Handler configuration:
 <handler status="active">
    <name>Perl CGI  Handler</name>
    <description>Perl CGI  Handler</description>
    <removable>true</removable>
    <id>perlCgiHandler</id>
    <files />
    <params>
      <param name="perlCgiHandler.class" value="org.paw.handler.AndroidCgiHandler" />
      <param name="perlCgiHandler.root" value="[PAW_HOME]/html" />
      <param name="perlCgiHandler.suffix" value=".pl" />
      <param name="perlCgiHandler.runwith" value="/data/data/com.googlecode.perlforandroid/files/perl/perl" />
      <param name="perlCgiHandler.sl4a" value="true" />
      <param name="perlCgiHandler.ENV_TMPDIR" value="[PAW_HOME]/tmp" />
    </params>
  </handler>
Let's have a look at the parameters. The class parameter defines the handler to use. In our case this is the CGI Handler. The next parameter is the root parameter which specifies the directory the scripts are located. Subdirectories are also included. The suffix parameter defines the filename extension for the scripts. The runwith parameter is the most important one, it defines the location of the CGI binary. If the sl4a is set to true the environment variables AP_HOST and AP_PORT are set. Because this information is read from logcat entries, SL4A should be started right before the startup of PAW. Otherwise it might not possible for the handler to extract the SL4A configuration. The last parameter sets the TMPDIR environment variable. All parameters starting with ENV_ are used to set environment variables. Now the PAW configuration is complete and we can start to write a test CGI script.

The CGI Script

We will create a test CGI script inside the PAW_HOME/html directory called test.pl. The test script looks like this:
print "Content-type: text/html\n\n";

print "Hello world!\n";
After starting PAW and entering the URL http://<ip-address>:8080/test.pl into the address bar of the browser the following text should be displayed:
Hello world!

Conclusion

The Android Scripting Project offers many more interpreters. It should be possible use many of them together with PAW, as long as you can get them to work from the command line.

Monday, June 25, 2012

Tinkering with PAW

This blog post is about using Tinkerforge modules together with PAW Server for Android.
As an example a volume control for Android is build.



The Setup
The following image shows the components needed to build the volume control.

Component Overview

The LCD and Poti Bricklets are connected to the Master Brick which is connected via USB to a PC running the brickd (Brick Daemon).
The Poti is used to control the volume of the phone. The values will be displayed on the LCD.

Below is an image of the  setup in action.

Complete Setup


Tinkeforge Classes
Tinkerforge offers a set of language bindings which also includes a Java JAR package.
Because PAW needs DEXed classes the Tinkerforge JAR file has to be converted into DEX format.

To make live easy, here is the link: Tinkerforge_dex.jar

To make the file usable for PAW, copy it int the /sdcard/paw/webconf/dex folder and restart the server.

Inside the Beanshell Console of the PAW web interface you can run the following code to check if the file has been loaded.

print(server.props.get("serviceContext").getDexClassLoader());

For me, the output looks like this:
dalvik.system.DexClassLoader[/mnt/sdcard/paw/webconf/dex/webapp_dex.jar:/mnt/sdcard/paw/webconf/dex/Tinkerforge_dex.jar]

If the output includes the Tinkerforge_dex.jar file, everything should be ok.


Bricklet UIDs
In order to talk to the right Bricklets (LCD and Poti) the UID of these components is needed.
Inside the scripts provided in this post, you have to exchange the connection IP address and Bricklet UIDs accroding to your setup.

To find out the UIDs we can ask the Master Brick obout its configuration.

useDexClasses();

import com.tinkerforge.IPConnection;

// Change IP address!
host = "10.0.0.13";
port = 4223;

ipcon = new IPConnection(host, port); // Can throw IOException

ipcon.enumerate(new IPConnection.EnumerateListener() {
    public void enumerate(String uid, String name, short stackID, boolean isNew) {
        if(isNew) {
            $$.print("Name: " + name);
            $$.print(" | UID: " + uid);
            print(" | Stack ID:" + stackID);
        }
    }
});

Thread.sleep(1000);
ipcon.destroy();

With my setup the output looks like this:
Name: Master Brick 1.0 | UID: apaYNJF7xmN | Stack ID:1
Name: Rotary Poti Bricklet 1.0 | UID: 9BY | Stack ID:2
Name: LCD 20x4 Bricklet 1.0 | UID: 9dj | Stack ID:3


Volume Control Script
One note  about the script...
The script uses polling which is not ideal, actually listeners should be used.
Polling is used for the sake of simplicity.

After we have connected the components and found out the UIDs we can run the volume control script.
Remember to change the IP number and the UIDs.

useDexClasses();

import android.media.AudioManager;
import android.content.Context;
import de.fun2code.android.pawserver.PawServerService;

import com.tinkerforge.IPConnection;
import com.tinkerforge.BrickletRotaryPoti;
import com.tinkerforge.BrickletLCD20x4;

r = new Runnable() { public void run() {

    MAX_LABEL = "Max Volume: ";
    DEGREE_LABEL = "Degree: ";
    VOLUME_LABEL = "Volume: ";

    service = server.props.get("serviceContext");
    audioMgr = service.getSystemService(Context.AUDIO_SERVICE);
    maxVol = audioMgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);


    /*
      UID and IP settings ... these have to be changed!
    */
    host = "10.0.0.13";
    port = 4223;
    UID_LCD = "9dj";
    UID_ROP = "9BY";

    ipcon = null;

    lastVol = -1;
    lcdFirst = true;

    while(true) {
        try {
            // Make sure we have a valid connection
            if(ipcon == null) {
                ipcon = new IPConnection(host, port);
                rop = new BrickletRotaryPoti(UID_ROP);
                ipcon.addDevice(rop);

                lcd = new BrickletLCD20x4(UID_LCD);
                ipcon.addDevice(lcd);
        
                lcd.backlightOn();
            }

            if(lcd.isButtonPressed((short) 0)) {
                break;
            }

            deg = rop.getPosition();
            pos = deg + 150;
            vol = pos * maxVol / 300;
            
            if(lastDeg != deg) {
                if(lcdFirst) {
                    lcd.clearDisplay();
                    lcd.writeLine((short) 0, (short)0, MAX_LABEL + maxVol);
                    lcd.writeLine((short) 1, (short)0, DEGREE_LABEL + deg);
                    lcd.writeLine((short) 2, (short)0, VOLUME_LABEL + vol);
                    lcdFirst = false;
                }
                else {
                    lcd.writeLine((short) 0, (short) MAX_LABEL.length(), "" + maxVol + "  ");
                    lcd.writeLine((short) 1, (short) DEGREE_LABEL.length(), "" + deg + "  ");
                    lcd.writeLine((short) 2, (short) VOLUME_LABEL.length(), "" + vol + "  ");
                }
            }

            if(lastVol != vol) {
                audioMgr.setStreamVolume(AudioManager.STREAM_MUSIC, vol, 0);
            }

            lastDeg = deg;
            lastVol = vol;
        }
        catch(e) { }

        // Wait 100 millis until we poll again
        Thread.sleep(100);
    }

    lcd.clearDisplay();
    lcd.writeLine((short) 0, (short) 0, "Bye bye ...");
    Thread.sleep(1000);
    lcd.clearDisplay();
    lcd.backlightOff();

    ipcon.destroy();
    ​
}};

t = new Thread(r);
t.start();

Some notes about the script:
  • If button 0 of the LCD is pressed, the script will terminate.
  • The Android AudioManager is used to control the music stream volume.
The below picture shows how the display looks like on the LCD.

LCD Output


Android restarts the PAW service from time to time (for whatever reason). So if the scripts stops working just restart it again.
You can also put the script (name is something  like S_tf_volume.bsh) inside the /sdcard/paw/etc/init/1 folder to make sure it's run each time the servers starts up.

Hope this was interesting ... have fun :)

Thursday, January 26, 2012

Changing the PirateBox Location

This post gives a quick overview what has to be done to move the PirateBox installation to a different directory.

By default the PirateBox HTML files are located in the directory /sdcard/paw/html/app/plugins/piratebox_plugin/html and uploaded files are stored in the folder uploads inside the HTML directory.

I'll demonstrate what to do to move the PirateBox to a different directory (in my example /sdcard/piratebox_ext). You can of course also use a directory on an external SD card.

Copying the HTML Directory
First thing to do ist to create the new folder /sdcard/pireatebox_ext.
Now copy the directory /sdcard/paw/html/app/plugins/piratebox_plugin/html to the new location /sdcard/pireatebox_ext.

As a next step we will edit the PAW server configuration.

Changing the PAW Configuration

The configuration file used for PirateBox is named handlers.xml and it's located inside the /sdcard/paw/html/app/plugins/piratebox_plugin/conf directory.
Edit this file and replace each occurence of /sdcard/paw/html/app/plugins/piratebox_plugin with /sdcard/piraebox_ext.

Changing the Web Pages
Last step to do is to edit the files list.xhtml and pb.xhtml inside the /sdcard/piratebox_ext/html directory.
In each file there is one line that defines the upload directory.
Again, change each occurence of /sdcard/paw/html/app/plugins/piratebox_plugin to /sdcard/piraebox_ext.


That's it ... on next startup the new PirateBox location should be used.

Thursday, December 22, 2011

NFC - NDEF Support

NDEF messages are the standard way to write information to NFC tags on Android.
The latest version of PAW (0.84) has support for text, URI, smart poster and mime media NDEF messages.
The classes and their methods are described in the PAW Functions documentation within the PAW web application.
NFC support is now also available in PAW Runtime.
To show how the new functionality can be used (and to give you the possibility to play with NFC tags), a NFC reader/writer plugin is available for PAW. This plugin is also available in the newest add-on package for PAW Runtime.

Here are some screenshots...

Plugin

NFC Plugin
Plugin requesting NFC Tag

Runtime

PAW Runtime with NFC Reader/Writer
Runtime version


This will be the last update of PAW this year and possibly the last blog entry.
To all of you ... Merry Christmas and a Happy New Year :)

Thursday, December 1, 2011

PirateBox on Android

A while ago psundegroud created the thread [TUT]Roll Your Own PirateBox! PirateBoxMobile. At that time my only rooted device was an old Samsung Galaxy I7500 running Android 1.6. We managed to get this working. The two main issues were that WiFi Tether was needed, which didn't run on all Android devices and that only Ad-Hoc mode was available. The missing Infrastructure mode prevented most Androids from seeing the PirateBox hotspot.

Note: This post is somewhat outdated. The current state of the PirateBox can be found here: PirateBox Reloaded

Meanwhile I have a rooted Notion Ink Adam running AdamComb v0.3. So I tried to get PirateBox running by using the built in tether app. Built in tethering uses Infrastructure mode, which solves above mentioned problem.

On my Adam this is really working fine and I hope that it will also run on other Android units.
I'll divide the post in two parts. The first part describes the technical details, so if someone has problems in getting this to work this might be helpful for further testing.

Along with setting up the scripts I have also written a plugin for PAW which should make setup really easy.
If you are not interested in the technical details you can right jump to the Installing the Plugin section.

Techical Details

Setting up the PirateBox during boot is done by PAW startup scripts.

The main tasks of these scripts are:
  • Killing dnsmasq and restarting it with changed parameters, so that DNS requests always respond with the IP of the Android device.
  • Configuring iptables so that requests to port 80 are redirected to the port PAW is listening on, because PAW can not operate on privileged ports.
  • Change the PAW configuration to use the PirateBox Handler, which ensures that all unknown request are forwarded to the base URL (piratebox.org/).

The startup scripts are located in the subfolders 0 and 1 of the directory /sdcard/paw/etc/init. These folders represent PAW runlevels. Runlevel 0 is before the server starts and after server shutdown and 1 is after server start and before the server shuts down. Scripts beginning with S_ will be called on startup and scripts starting with K_ will be run at shutdown.

So here is a short summary what these scripts are doing.

0/S_PirateBox.bsh:
  • Checks if tethering is running. If not none of the steps below will be performed.
  • Kills the "original" dnsmasq process and starts a new one.
  • Executes iptables commands to get port redirection working.
  • Replaces the original PAW configuration with the PirateBox configuration.

1/S_SpirateBox.bsh:
  • Checks if tethering is running. If not none of the steps below will be performed.
  • Restores the original PAW configuration.
  • Displays a PirateBox notification.
  • Sets the max upload limit to 200MB.

1/K_S_SpirateBox.bsh:
  • Clears the PirateBox notification.
  • Kills dnsmasq process.
  • Stops tetherig and restarts WiFi.

0/K_S_SpirateBox.bsh:
  • Removes iptables rules for port redirection.

If you run into problems have a look at these scripts and try to run the commands inside the scripts individually.


Installing the Plugin

PAW Plug-in Menu
Installing the plugin is easy. I've put it on the PAW plugin page, so you'll find it within the PAW web application or you can direct download it from the PAW Plugin Page.
After download extract the ZIP file to the /sdcard/paw/html/app/plugins directory of your Android device.
Now after re-entering the PAW web application, the PirateBox plugin should be visible in the Plugins menu.

If the plugin setup screen shows a warning in red, the installation is likely to fail, because some prerequisites are missing.
If no warnings are displayed, press the Install button. You can also try to setup a PirateBox Access Point (AP) automatically. I'm not sure, if this is working on all devices. If it's not working, please create an AP manually.
To uninstall the plugin, press the Uninstall button.

PirateBox Plugin

It is important to note, that PirateBox will only be started if tethering is active before PAW starts up.
Otherwise the normal PAW configuration will be applied. So you can choose between these two configurations.

I hope that's not just working on my Adam but on many other devices as well.

Screenshost
Here are some screenshots from my setup...

PirateBox Startup

Connected to PirateBox

PirateBox on Nexus One
PirateBox in Chromium

Video

Here is a video that shows the PirateBox in action...



Update

Since version 0.3 of the plugin, PirateBox is also working on rooted Galaxy Nexus devices running Ice Cream Sandwich.
Here is a video...


Thursday, November 24, 2011

PHP Plug-in Update

My cross compiled version of the PHP CGI was not working so well and I didn't manage to fix it.

Fortunately Klaas Biker informed me that Iulian Virtejanu has cross compiled a PHP CGI version that seems to work significantly better.
Here is Iulian's blog entry: PHP and Lighttpd for Android

Iulian gave me the permission to use it in PAW, so I have updated the PHP Plug-in to version 0.3.

There is one known issue:

system(...) does not work.
It is because system('pwd') actually invokes a hardcoded /bin/sh -c 'pwd' - and /bin/sh is not available on Android.
Iulian has submitted a bug report to PHP: https://bugs.php.net/bug.php?id=60081

If you find more bugs, please let me know. I will forward them.

Monday, October 31, 2011

Building PHP from Scratch

This post by Rahul Amaram describes how to build PHP for Android from scratch and how it can later be used within PAW.
I've added links to the needed files at the end of the post.

Thanks to Rahul for putting this together!

Here is Rahul's documentation...



It is suggested to use a VM for compilation so that you can take snapshots at regular intervals. Also as per google recommendation, it is suggested to use a VM with at least 8 GB RAM/swap and 12 GB of free hard disk.

Install Ubuntu 10.04 64-bit (select username as "joschi") on a VM.

After booting ubuntu, login as joschi.

Download and extract android-php

$ cd
$ wget -c "http://paw-android.fun2code.de/download/android-php.zip"
$ sudo apt-get install unzip
$ unzip android-php.zip

First initialize build environment. For donut, java 5 is needed. Also compiling with gcc/g++ 4.4 was throwing errors during compilation. Therefore we use gcc/g++ 4.3 for compilation.

$ sudo apt-get install python-software-properties
$ sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu hardy main multiverse"
$ sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu hardy-updates main multiverse"
$ sudo apt-get update
$ sudo apt-get install sun-java5-jdk


$ sudo apt-get install git-core gnupg flex bison gperf build-essential \
zip curl zlib1g-dev libc6-dev lib32ncurses5-dev ia32-libs \
x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev \
libgl1-mesa-dev g++-multilib mingw32 tofrodos python-markdown \
libxml2-utils


$ sudo apt-get install g++-4.3-multilib

Download Android source
This will be about 3 GB.

$ mkdir ~/bin
$ PATH=~/bin:$PATH
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo
$ chmod a+x ~/bin/repo


$ mkdir ~/android-donut-src
$ cd ~/android-donut-src
$ repo init -u https://android.googlesource.com/platform/manifest -b android-1.6_r2
$ repo sync

It is a good idea to take snapshot of the VM here.

Build Android

$ cd /usr/bin
$ sudo ln -sf cpp-4.3 cpp
$ sudo ln -sf g++-4.3 g++
$ sudo ln -sf gcc-4.3 gcc
$ sudo ln -sf gcov-4.3 gcov
$ sudo ln -sf cpp-4.3 x86_64-linux-gnu-cpp
$ sudo ln -sf g++-4.3 x86_64-linux-gnu-g++
$ sudo ln -sf gcc-4.3 x86_64-linux-gnu-gcc


$ cd ~/android-donut-src
$ source build/envsetup.sh
$ lunch generic-eng
$ make -j4

It is a good idea to take another snapshot of the VM here.

Next build android-php. The patch is applied in order to avoid the error "undefined reference to `__sync_fetch_and_add_4'" during compilation.

$ cd ~/android-php
$ rm -rf ~/android-donut-src/bionic/libc/include/
$ unzip -d ~/android-donut-src/bionic/libc/ bionic_libc_include.zip
$ patch php-5.3.6/ext/standard/php_crypt_r.c < ~/sync_fetch_and_add.patch
$ ./build_php_5.3.sh

Finally copy php-5.3.6/sapi/cgi/php-cgi to /mnt/sdcard/paw/html/app/plugins/php_plugin/bin/ on your android phone (be sure to backup the existing php-cgi file), and install PHP using the PAW Web App.

References:



Files:
android-php.zip
sync_fetch_and_add.patch