diff --git a/LifeBlogger.iws b/LifeBlogger.iws
index e61240a..66c9b0e 100644
--- a/LifeBlogger.iws
+++ b/LifeBlogger.iws
@@ -71,7 +71,7 @@
-
+
@@ -112,7 +112,7 @@
-
+
@@ -131,7 +131,7 @@
-
+
@@ -140,7 +140,7 @@
-
+
@@ -149,14 +149,14 @@
-
+
-
+
@@ -165,7 +165,7 @@
-
+
@@ -179,7 +179,7 @@
-
+
@@ -188,7 +188,7 @@
-
+
@@ -209,9 +209,9 @@
-
-
+
+
@@ -243,20 +243,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -285,6 +271,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -364,7 +364,7 @@
-
+
@@ -521,18 +521,9 @@
-
-
-
-
-
-
-
-
-
-
+
@@ -541,7 +532,7 @@
-
+
@@ -550,14 +541,14 @@
-
+
-
+
@@ -566,7 +557,7 @@
-
+
@@ -580,7 +571,7 @@
-
+
@@ -589,11 +580,20 @@
-
+
+
+
+
+
+
+
+
+
+
diff --git a/src/net/thauvin/lifeblogger/LifeAction.java b/src/net/thauvin/lifeblogger/LifeAction.java
new file mode 100644
index 0000000..46faff1
--- /dev/null
+++ b/src/net/thauvin/lifeblogger/LifeAction.java
@@ -0,0 +1,143 @@
+/*
+ * @(#)LifeAction.java
+ *
+ * Copyright (C) 2004 by Erik C. Thauvin (erik@thauvin.net)
+ * All rights reserved.
+ *
+ * $Id$
+ *
+ */
+package net.thauvin.lifeblogger;
+
+import java.awt.*;
+
+import java.io.IOException;
+
+
+/**
+ * The LifeAction
class provides the base functionality for all actions.
+ *
+ * @author Erik C. Thauvin
+ * @version $Revision$, $Date$
+ *
+ * @created Jul 24, 2004
+ * @since 1.0
+ */
+public abstract class LifeAction extends Thread
+{
+ /**
+ * The Thinlet instance.
+ */
+ private final LifeBlogger _thinlet;
+
+ /**
+ * The Transfer dialog.
+ */
+ private final Object _dialog;
+
+ /**
+ * The host name.
+ */
+ private final String _host;
+
+ /**
+ * The login name.
+ */
+ private final String _login;
+
+ /**
+ * The password.
+ */
+ private final String _password;
+
+ /**
+ * Creates a new LifeAction object.
+ *
+ * @param thinlet The Thinlet instance.
+ * @param host The host.
+ * @param login The login name.
+ * @param password The password.
+ *
+ * @throws IOException If an error occurs while creating the object.
+ */
+ protected LifeAction(LifeBlogger thinlet, String host, String login, String password)
+ throws IOException
+ {
+ _thinlet = thinlet;
+ _host = host;
+ _login = login;
+ _password = password;
+ _dialog = _thinlet.parse("transfer.xml");
+ }
+
+ /**
+ * Performs the action.
+ *
+ * @see Thread#run()
+ */
+ public abstract void run();
+
+ /**
+ * Returns the Transfer dialog.
+ *
+ * @return The dialog.
+ */
+ protected final Object getDialog()
+ {
+ return _dialog;
+ }
+
+ /**
+ * Returns the host name.
+ *
+ * @return The host.
+ */
+ protected final String getHost()
+ {
+ return _host;
+ }
+
+ /**
+ * Returns the login name.
+ *
+ * @return The login.
+ */
+ protected final String getLogin()
+ {
+ return _login;
+ }
+
+ /**
+ * Returns the password.
+ *
+ * @return The password.
+ */
+ protected final String getPassword()
+ {
+ return _password;
+ }
+
+ /**
+ * Returns the Thinlet instance.
+ *
+ * @return The Thinlet.
+ */
+ protected final LifeBlogger getThinlet()
+ {
+ return _thinlet;
+ }
+
+ /**
+ * Displays an alert message.
+ *
+ * @param message The message to display.
+ */
+ protected final void alert(String message)
+ {
+ Toolkit.getDefaultToolkit().beep();
+
+ getThinlet().setIcon(getThinlet().find(getDialog(), "iconlbl"), "icon", getThinlet().getIcon("/icon/error.gif"));
+ getThinlet().setString(getThinlet().find(getDialog(), "message"), "text", message);
+ getThinlet().setBoolean(getThinlet().find(getDialog(), "closebtn"), "enabled", true);
+ }
+}
diff --git a/src/net/thauvin/lifeblogger/LifePost.java b/src/net/thauvin/lifeblogger/LifePost.java
new file mode 100644
index 0000000..d7e49b2
--- /dev/null
+++ b/src/net/thauvin/lifeblogger/LifePost.java
@@ -0,0 +1,221 @@
+/*
+ * @(#)LifeMediaObject.java
+ *
+ * Copyright (c) 2004, Erik C. Thauvin (http://www.thauvin.net/erik/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the authors nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ */
+package net.thauvin.lifeblogger;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import java.net.URL;
+import java.net.URLConnection;
+
+
+/**
+ * The LifePostObject
class posts a new blog entry using the blogger.newPost() XML-RPC method.
+ *
+ * @author Erik C. Thauvin
+ * @version $Revision$, $Date$
+ *
+ * @created Jul 21, 2004
+ * @since 1.0
+ */
+public class LifePost extends LifeAction
+{
+ private final String _blogEntry;
+ private final String _blogID;
+
+ /**
+ * Creates a new LifePost object.
+ *
+ * @param thinlet The Thinlet instance.
+ * @param url The MetaWeblog XML-RPC URL.
+ * @param blogID The blog ID.
+ * @param login The MetaWeblog login username.
+ * @param password The MetaWeblog login password.
+ * @param blogEntry The blog entry.
+ *
+ * @throws IOException If an error occurs while creating the object.
+ */
+ public LifePost(LifeBlogger thinlet, String url, String blogID, String login, String password, String blogEntry)
+ throws IOException
+ {
+ super(thinlet, url, login, password);
+
+ _blogEntry = blogEntry;
+ _blogID = blogID;
+ }
+
+ /**
+ * Performs the action.
+ *
+ * @see Thread#run()
+ */
+ public final void run()
+ {
+ try
+ {
+ getThinlet().add(getDialog());
+
+ final URL url = new URL(getHost());
+
+ if (!"http".equalsIgnoreCase(url.getProtocol()))
+ {
+ throw new IOException("Unsupported URL protocol: " + url.getProtocol());
+ }
+
+ final StringBuffer request =
+ new StringBuffer("blogger.newPost0a6afffffffaffffffb8ffffff8569474cffffffc778500c03ffffffecffffff876116565a27283bffffffda56").append(_blogID)
+ .append("")
+ .append(getLogin())
+ .append("")
+ .append(getPassword())
+ .append("")
+ .append(textToXML(_blogEntry))
+ .append("false");
+ final URLConnection urlConn = url.openConnection();
+ urlConn.setDoInput(true);
+ urlConn.setDoOutput(true);
+ urlConn.setUseCaches(false);
+ urlConn.setRequestProperty("Content-Length", String.valueOf(request.length()));
+ urlConn.setRequestProperty("Content-Type", "text/xml");
+
+ final DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream());
+ dos.write(request.toString().getBytes());
+ dos.flush();
+ dos.close();
+
+ final LifeRPCResponse xmlrpc = new LifeRPCResponse(urlConn.getInputStream());
+
+ if (xmlrpc.isValidResponse())
+ {
+ //getThinlet().closeDialog(getDialog());
+ getThinlet().setIcon(getThinlet().find(getDialog(), "iconlbl"), "icon",
+ getThinlet().getIcon("/icon/info.gif"));
+ getThinlet().setString(getThinlet().find(getDialog(), "message"), "text",
+ "Post successful. (ID " + xmlrpc.getResponse() + ')');
+ getThinlet().setBoolean(getThinlet().find(getDialog(), "closebtn"), "enabled", true);
+ }
+ else
+ {
+ alert(xmlrpc.getResponse());
+ }
+ }
+ catch (IOException e)
+ {
+ getThinlet().closeDialog(getDialog());
+ getThinlet().showException(e);
+ }
+ }
+
+ /**
+ * Converts a character to XML entity.
+ *
+ * @param ch The character to convert.
+ *
+ * @return The converted string.
+ */
+ private String charToXML(char ch)
+ {
+ final int c;
+
+ // Convert left bracket
+ if (ch == '<')
+ {
+ return ("<");
+ }
+
+ // Convert left bracket
+ else if (ch == '>')
+ {
+ return (">");
+ }
+
+ // Convert ampersand
+ else if (ch == '&')
+ {
+ return ("&");
+ }
+
+ // High-ASCII character
+ else if (ch >= 128)
+ {
+ c = (int) ch;
+
+ return ("" + c + ';');
+ }
+
+ // Convert double quote
+ else if (ch == '"')
+ {
+ return (""");
+ }
+
+ // Convert single quote
+ else if (ch == '\'')
+ {
+ return ("'");
+ }
+
+ // No conversion
+ else
+ {
+ // Return character as string
+ return (String.valueOf(ch));
+ }
+ }
+
+ /**
+ * Converts a text string to XML entities.
+ *
+ * @param text The string to convert.
+ *
+ * @return The converted string.
+ */
+ private String textToXML(String text)
+ {
+ final StringBuffer html = new StringBuffer();
+
+ // Loop thru each characters of the text
+ for (int i = 0; i < text.length(); i++)
+ {
+ // Convert character to HTML/XML
+ html.append(charToXML(text.charAt(i)));
+ }
+
+ // Return HTML/XML string
+ return html.toString();
+ }
+}
diff --git a/src/net/thauvin/lifeblogger/LifeRPCResponse.java b/src/net/thauvin/lifeblogger/LifeRPCResponse.java
new file mode 100644
index 0000000..de25b54
--- /dev/null
+++ b/src/net/thauvin/lifeblogger/LifeRPCResponse.java
@@ -0,0 +1,164 @@
+/*
+ * @(#)LifeRPCResponse.java
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the authors nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ */
+package net.thauvin.lifeblogger;
+
+import thinlet.Thinlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * The LifeRPCResponse
class uses the Thinlet DOM parser to process a XML-RCP response.
+ *
+ * @author Erik C. Thauvin
+ * @version $Revision$, $Date$
+ *
+ * @created Jul 21, 2004
+ * @since 1.0
+ */
+public class LifeRPCResponse extends Thinlet
+{
+ private final InputStream _inputStream;
+ private String _response;
+
+ /**
+ * Creates a new LifeRPCResponse object.
+ *
+ * @param inputStream The input stream.
+ */
+ public LifeRPCResponse(InputStream inputStream)
+ {
+ _inputStream = inputStream;
+ }
+
+ /**
+ * Returns the XML-RPC response/fault string.
+ *
+ * @return The response string.
+ */
+ public final String getResponse()
+ {
+ return _response;
+ }
+
+ /**
+ * Parses and validates the XML-RPC response.
+ *
+ * @return true
is the response is valid, false
if it is a fault.
+ *
+ * @throws IOException If an error occurs while processing the response.
+ */
+ public final boolean isValidResponse()
+ throws IOException
+ {
+ try
+ {
+ final Object dom = parseDOM(_inputStream);
+ final Object params = getDOMNode(dom, "params", 0);
+
+ if (params != null)
+ {
+ final Object param = getDOMNode(params, "param", 0);
+ final Object value = getDOMNode(param, "value", 0);
+ final Object struct = getDOMNode(value, "struct", 0);
+
+ if (struct == null)
+ {
+ final Object string = getDOMNode(value, "string", 0);
+
+ _response = getDOMText(string);
+ }
+ else
+ {
+ final Object member = getDOMNode(struct, "member", 0);
+ final Object url = getDOMNode(member, "value", 0);
+ final Object string = getDOMNode(url, "string", 0);
+
+ if (string == null)
+ {
+ _response = getDOMText(url);
+ }
+ else
+ {
+ _response = getDOMText(string);
+ }
+ }
+
+ return true;
+ }
+ else
+ {
+ final Object fault = getDOMNode(dom, "fault", 0);
+ final Object value = getDOMNode(fault, "value", 0);
+ final Object struct = getDOMNode(value, "struct", 0);
+ Object member = getDOMNode(struct, "member", 0);
+
+ if (getDOMCount(struct, "member") > 1)
+ {
+ member = getDOMNode(struct, "member", 1);
+ }
+
+ final Object error = getDOMNode(member, "value", 0);
+ final Object string = getDOMNode(error, "string", 0);
+
+ if (string != null)
+ {
+ _response = getDOMText(string);
+ }
+ else
+ {
+ throw new IOException("Could not parse the XML-RPC error response.");
+ }
+
+ return false;
+ }
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ finally
+ {
+ try
+ {
+ _inputStream.close();
+ }
+ catch (IOException ignore)
+ {
+ ; // Do nothing
+ }
+ }
+ }
+}
diff --git a/src/net/thauvin/lifeblogger/post.xml b/src/net/thauvin/lifeblogger/post.xml
new file mode 100644
index 0000000..2b71bcb
--- /dev/null
+++ b/src/net/thauvin/lifeblogger/post.xml
@@ -0,0 +1,15 @@
+
+
\ No newline at end of file
diff --git a/src/net/thauvin/lifeblogger/preview.xml b/src/net/thauvin/lifeblogger/preview.xml
new file mode 100644
index 0000000..18006ef
--- /dev/null
+++ b/src/net/thauvin/lifeblogger/preview.xml
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/www/images/banner.gif b/www/images/banner.gif
new file mode 100644
index 0000000..99e4c42
Binary files /dev/null and b/www/images/banner.gif differ
diff --git a/www/images/get_java.gif b/www/images/get_java.gif
new file mode 100644
index 0000000..a5a44ad
Binary files /dev/null and b/www/images/get_java.gif differ
diff --git a/www/images/shot3.gif b/www/images/shot3.gif
new file mode 100644
index 0000000..50bcbc9
Binary files /dev/null and b/www/images/shot3.gif differ