Added support for the Textamerica API.

Added support fot posts titles via the MetaWeblog API.
LifeBlogger is now using Apache's XML-RPC library.
This commit is contained in:
Erik C. Thauvin 2005-04-14 10:53:33 +00:00
parent 3134321d29
commit cb53098f59
18 changed files with 505 additions and 2041 deletions

View file

@ -37,6 +37,15 @@
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/xmlrpc-1.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntryProperties />
</component>
</module>

View file

@ -11,7 +11,7 @@
</buildFile>
<buildFile url="file://$PROJECT_DIR$/webstart.xml">
<additionalClassPath />
<antReference name="Local Ant" />
<antReference name="Apache Ant version 1.6.2" />
<customJdkName value="" />
<maximumHeapSize value="128" />
<properties />

View file

@ -19,6 +19,7 @@
<jar href="commons-net-1.3.0.jar"/>
<jar href="sqlite.jar"/>
<jar href="thinlet.jar"/>
<jar href="xmlrpc-1.1.jar"/>
<nativelib href="sqlite_jni.dll"/>
</resources>
<application-desc main-class="net.thauvin.lifeblogger.LifeBlogger"/>

View file

@ -1,6 +1,6 @@
# Project
proj.name=LifeBlogger
proj.version=0.1.2
proj.version=0.2
proj.package=net.thauvin.lifeblogger
proj.run=${proj.package}.LifeBlogger

BIN
lib/xmlrpc-1.1.jar Normal file

Binary file not shown.

View file

@ -1,8 +0,0 @@
I am placing this code in the Public Domain. Do with it as you will.
This software comes with no guarantees or warranties but with
plenty of well-wishing instead!
Please visit <a href="http://iharder.net/xmlizable">http://iharder.net/base64</a>
periodically to check for updates or to contribute improvements.
Robert Harder
rob@iharder.net

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/*
* @(#)LifeBlogger.java
*
* Copyright (c) 2004, Erik C. Thauvin (http://www.thauvin.net/erik/)
* Copyright (c) 2005, Erik C. Thauvin (http://www.thauvin.net/erik/)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -55,29 +55,30 @@ import javax.imageio.ImageIO;
import javax.swing.*;
import org.apache.xmlrpc.Base64;
/**
* The <code>LifeBlogger</code> class uploads/posts Lifeblog's favorite data to a blog.
*
* @author <a href="http://www.thauvin.net/erik/">Erik C. Thauvin</a>
* @author <a href="http://www.thauvin.net/erik/">Erik C. Thauvin</a>
* @version $Revision$, $Date$
*
* @created Jul 19, 2004
* @since 1.0
* @created April 13, 2005
* @since 1.0
*/
public class LifeBlogger extends AntiAliasedThinlet
{
private static final String DRIVER = "SQLite.JDBCDriver";
private static final String PREFS =
System.getProperty("user.home") + File.separator + ReleaseInfo.getProject() + ".properties";
private static final String PREFS = System.getProperty("user.home") + File.separator + ReleaseInfo.getProject() +
".properties";
private static final String JDBC_PREFIX = "jdbc:sqlite:/";
private static final String DATABASE = "\\DataBase\\NokiaLifeblogDataBase.db";
private static final String DEFAULT_ACTION = "mw";
private static final String MIME_JPG = "image/jpeg";
private static final String MIME_3GP = "video/3gpp";
private final Properties _prefs = new Properties();
private File _homeDir = new File(System.getProperty("user.home") + "\\My Documents\\NokiaLifeblogData");
private String _action;
private File _homeDir = new File(System.getProperty("user.home") + "\\My Documents\\NokiaLifeblogData");
private final Properties _prefs = new Properties();
/**
* Creates a new LifeBlogger object.
@ -163,18 +164,6 @@ public class LifeBlogger extends AntiAliasedThinlet
}
}
/**
* Sets the blog action.
*
* @param action The action
*/
public final void setAction(String action)
{
_action = action;
_prefs.put("via", _action);
savePrefs();
}
/**
* Displays the about dialog.
*/
@ -200,9 +189,9 @@ public class LifeBlogger extends AntiAliasedThinlet
/**
* Populates the table rows.
*
* @param thinlet The Thinlet object.
* @param table The table to populate.
* @param buttonsPanel The panel containing the buttons/label to update.
* @param thinlet The Thinlet object.
* @param table The table to populate.
* @param buttonsPanel The panel containing the buttons/label to update.
*
* @throws Exception If an error occurs while populate the table.
*/
@ -320,7 +309,7 @@ public class LifeBlogger extends AntiAliasedThinlet
/**
* Performs the blog action.
*
* @param table The table containing the selected item to perform the action on.
* @param table The table containing the selected item to perform the action on.
*
* @throws Exception If an error occurs while performing the action.
*/
@ -342,6 +331,10 @@ public class LifeBlogger extends AntiAliasedThinlet
{
ftpDialog(info[1]);
}
else if ("ta".equals(_action))
{
taDialog(info[1], info[2]);
}
else
{
mwDialog(info[1], info[2]);
@ -371,8 +364,8 @@ public class LifeBlogger extends AntiAliasedThinlet
/**
* Preforms the FTP action.
*
* @param dialog The FTP dialog,
* @param ftpPanel The panel contaning the FTP data.
* @param dialog The FTP dialog,
* @param ftpPanel The panel contaning the FTP data.
*
* @throws IOException If an error occurs while performing the action.
*/
@ -401,16 +394,14 @@ public class LifeBlogger extends AntiAliasedThinlet
{
_prefs.put("host", host);
_prefs.put("login", login);
_prefs.put("password", Base64.encodeBytes(password.getBytes(), Base64.DONT_BREAK_LINES));
_prefs.put("password", new String(Base64.encode(password.getBytes())));
_prefs.put("path", path);
savePrefs();
closeDialog(dialog);
final LifeFTP ftp =
new LifeFTP(this, host, login, password, path, filename,
new File(getString(find(ftpPanel, "file"), "text")));
final LifeFTP ftp = new LifeFTP(this, host, login, password, path, filename,
new File(getString(find(ftpPanel, "file"), "text")));
ftp.start();
}
}
@ -418,8 +409,8 @@ public class LifeBlogger extends AntiAliasedThinlet
/**
* Preforms the MetaWeblog action.
*
* @param dialog The MetaWeblog dialog,
* @param mwPanel The panel contaning the MetaWeblog data.
* @param dialog The MetaWeblog dialog,
* @param mwPanel The panel contaning the MetaWeblog data.
*
* @throws IOException If an error occurs while performing the action.
*/
@ -456,14 +447,14 @@ public class LifeBlogger extends AntiAliasedThinlet
{
_prefs.put("mw-host", host);
_prefs.put("mw-login", login);
_prefs.put("mw-password", Base64.encodeBytes(password.getBytes(), Base64.DONT_BREAK_LINES));
_prefs.put("mw-password", new String(Base64.encode(password.getBytes())));
_prefs.put("mw-id", blogID);
if (_prefs.getProperty("blog-host") == null)
{
_prefs.put("blog-host", host);
_prefs.put("blog-login", login);
_prefs.put("blog-password", Base64.encodeBytes(password.getBytes(), Base64.DONT_BREAK_LINES));
_prefs.put("blog-password", new String(Base64.encode(password.getBytes())));
_prefs.put("blog-id", blogID);
}
@ -471,35 +462,22 @@ public class LifeBlogger extends AntiAliasedThinlet
closeDialog(dialog);
final LifeMediaObject mw =
new LifeMediaObject(this, host, blogID, login, password, filename,
String.valueOf(getProperty(find(mwPanel, "file"), "mtype")),
new File(getString(find(mwPanel, "file"), "text")));
final LifeMediaObject mw = new LifeMediaObject(this, host, blogID, login, password, filename,
String.valueOf(getProperty(find(mwPanel, "file"), "mtype")),
new File(getString(find(mwPanel, "file"), "text")));
mw.start();
}
}
/**
* Preforms the post to blog action.
*
* @param dialog The post dialog,
* @param blogPanel The panel contaning the post data.
*
* @throws IOException If an error occurs while performing the action.
*/
public final void post(Object dialog, Object blogPanel)
throws IOException
{
post(dialog, blogPanel, false);
}
/**
* Displays the post to blog dialog.
*
* @param url The URL pointing to the location of the media object.
* @param filename DOCUMENT ME!
* @param url The URL pointing to the location of the media object.
* @param filename The file name.
* @param metaWeblog The metaWeblog flag.
*/
public final void postDialog(String url, String filename)
public final void postDialog(String url, String filename, boolean metaWeblog)
{
try
{
@ -507,10 +485,25 @@ public class LifeBlogger extends AntiAliasedThinlet
setString(find(post, "host"), "text", _prefs.getProperty("blog-host", ""));
setString(find(post, "blogid"), "text", _prefs.getProperty("blog-id", ""));
setString(find(post, "login"), "text", _prefs.getProperty("blog-login", ""));
setString(find(post, "password"), "text", new String(Base64.decode(_prefs.getProperty("blog-password", ""))));
setString(find(post, "password"), "text",
new String(Base64.decode(_prefs.getProperty("blog-password", "").getBytes())));
setString(find(post, "entry"), "text",
"<img src=\"" + url + "\" alt=\"" + filename +
"\">\r<p>via <a href=\"http://www.thauvin.net/erik/lifeblogger/\">LifeBlogger</a></p>");
if (metaWeblog)
{
setBoolean(find(post, "title"), "visible", true);
setBoolean(find(post, "titleFld"), "visible", true);
setString(post, "text", getString(post, "text") + " (MetaWeblog API)");
}
else
{
setBoolean(find(post, "title"), "visible", false);
setBoolean(find(post, "titleFld"), "visible", false);
setString(post, "text", getString(post, "text") + " (Blogger API)");
}
add(post);
}
catch (Exception e)
@ -522,7 +515,7 @@ public class LifeBlogger extends AntiAliasedThinlet
/**
* Previews a JPEG image.
*
* @param table The data table.
* @param table The data table.
*
* @throws Exception If an error occurs while previewing the image.
*/
@ -540,7 +533,7 @@ public class LifeBlogger extends AntiAliasedThinlet
if ((info[1] != null) && MIME_JPG.equals(info[2]))
{
// Retrieve the jpg image
// Retrieve the jpg image
final BufferedImage in = ImageIO.read(new File(info[1]));
final int maxDim = 200;
@ -589,21 +582,89 @@ public class LifeBlogger extends AntiAliasedThinlet
/**
* Preforms the publish to blog action.
*
* @param dialog The post dialog,
* @param blogPanel The panel contaning the post data.
* @param dialog The post dialog,
* @param blogPanel The panel contaning the post data.
*
* @throws IOException If an error occurs while performing the action.
*/
public final void publish(Object dialog, Object blogPanel)
throws IOException
public void publish(Object dialog, Object blogPanel)
throws IOException
{
post(dialog, blogPanel, true);
final String host = getString(find(blogPanel, "host"), "text");
final String blogID = getString(find(blogPanel, "blogid"), "text");
final String login = getString(find(blogPanel, "login"), "text");
final String password = getString(find(blogPanel, "password"), "text");
final String entry = getString(find(blogPanel, "entry"), "text");
final Object fileFld = find(blogPanel, "file");
final String file = getString(fileFld, "text");
final String fileType = (String) getProperty(fileFld, "mime");
final String title;
final Object titleFld = find(blogPanel, "title");
if (getBoolean(titleFld, "visible"))
{
title = getString(titleFld, "text");
}
else
{
title = null;
}
if (host.length() <= 0)
{
alert("Please specify a XML-RPC URL.");
}
else if (login.length() <= 0)
{
alert("Please specify a login name.");
}
else if (password.length() <= 0)
{
alert("Please specify a password.");
}
else if (entry.length() <= 0)
{
alert("Please specify a post entry.");
}
else if (blogID.length() <= 0)
{
alert("Please specify a blog ID.");
}
else
{
_prefs.put("blog-host", host);
_prefs.put("blog-login", login);
_prefs.put("blog-password", new String(Base64.encode(password.getBytes())));
_prefs.put("blog-id", blogID);
savePrefs();
closeDialog(dialog);
final LifePost post = new LifePost(this, host, blogID, login, password, title,
getString(find(blogPanel, "entry"), "text"), file, fileType);
post.start();
}
}
/**
* Sets the blog action.
*
* @param action The action
*/
public final void setAction(String action)
{
_action = action;
_prefs.put("via", _action);
savePrefs();
}
/**
* Toggles the given button based on the specified table selection.
*
* @param table The table.
* @param table The table.
* @param button The button.
*/
public final void toggleButton(Object table, Object button)
@ -614,8 +675,8 @@ public class LifeBlogger extends AntiAliasedThinlet
/**
* Updates the table data.
*
* @param thinlet The Thinlet object.
* @param table The table to update.
* @param thinlet The Thinlet object.
* @param table The table to update.
* @param buttonsPanel The panel containing the buttons/label to update.
*/
public final void updateTable(Thinlet thinlet, Object table, Object buttonsPanel)
@ -737,7 +798,7 @@ public class LifeBlogger extends AntiAliasedThinlet
setString(find(ftp, "host"), "text", _prefs.getProperty("host", ""));
setString(find(ftp, "login"), "text", _prefs.getProperty("login", "anonymous"));
setString(find(ftp, "path"), "text", _prefs.getProperty("path", ""));
setString(find(ftp, "password"), "text", new String(Base64.decode(_prefs.getProperty("password", ""))));
setString(find(ftp, "password"), "text", new String(Base64.decode(_prefs.getProperty("password", "").getBytes())));
add(ftp);
requestFocus(find(ftp, "host"));
}
@ -758,7 +819,7 @@ public class LifeBlogger extends AntiAliasedThinlet
setString(find(mw, "filename"), "text", file.substring(file.lastIndexOf('\\') + 1));
setString(find(mw, "host"), "text", _prefs.getProperty("mw-host", ""));
setString(find(mw, "login"), "text", _prefs.getProperty("mw-login", ""));
setString(find(mw, "password"), "text", new String(Base64.decode(_prefs.getProperty("mw-password", ""))));
setString(find(mw, "password"), "text", new String(Base64.decode(_prefs.getProperty("mw-password", "").getBytes())));
setString(find(mw, "blogid"), "text", _prefs.getProperty("mw-id", ""));
add(mw);
requestFocus(find(mw, "host"));
@ -769,61 +830,6 @@ public class LifeBlogger extends AntiAliasedThinlet
}
}
/**
* Preforms the post/publish to blog action.
*
* @param dialog The post dialog,
* @param blogPanel The panel contaning the post data.
* @param publish Set to <code>true</code> to publish the post, <code>false</code> otherwise.
*
* @throws IOException If an error occurs while performing the action.
*/
private void post(Object dialog, Object blogPanel, boolean publish)
throws IOException
{
final String host = getString(find(blogPanel, "host"), "text");
final String blogID = getString(find(blogPanel, "blogid"), "text");
final String login = getString(find(blogPanel, "login"), "text");
final String password = getString(find(blogPanel, "password"), "text");
final String entry = getString(find(blogPanel, "entry"), "text");
if (host.length() <= 0)
{
alert("Please specify a XML-RPC URL.");
}
else if (login.length() <= 0)
{
alert("Please specify a login name.");
}
else if (password.length() <= 0)
{
alert("Please specify a password.");
}
else if (entry.length() <= 0)
{
alert("Please specify a post entry.");
}
else if (blogID.length() <= 0)
{
alert("Please specify a blog ID.");
}
else
{
_prefs.put("blog-host", host);
_prefs.put("blog-login", login);
_prefs.put("blog-password", Base64.encodeBytes(password.getBytes(), Base64.DONT_BREAK_LINES));
_prefs.put("blog-id", blogID);
savePrefs();
closeDialog(dialog);
final LifePost post =
new LifePost(this, host, blogID, login, password, getString(find(blogPanel, "entry"), "text"), publish);
post.start();
}
}
// Saves the properties.
private void savePrefs()
{
@ -854,4 +860,39 @@ public class LifeBlogger extends AntiAliasedThinlet
}
}
}
// Display the Textamerica dialog
private void taDialog(String file, String mimeType)
{
if ((!mimeType.equals(MIME_JPG)) && (!mimeType.equals(MIME_3GP)))
{
alert("This media type is not supported by Textamerica.");
return;
}
try
{
final Object post = parse("post.xml");
setString(find(post, "host"), "text", _prefs.getProperty("blog-host", "http://xml.api.textamerica.com/"));
setString(find(post, "blogid"), "text", _prefs.getProperty("blog-id", ""));
setString(find(post, "login"), "text", _prefs.getProperty("blog-login", ""));
setString(find(post, "password"), "text",
new String(Base64.decode(_prefs.getProperty("blog-password", "").getBytes())));
final Object fileFld = find(post, "file");
setString(fileFld, "text", file);
putProperty(fileFld, "mime", ((mimeType == MIME_JPG) ? "JPG" : "3GP"));
setBoolean(find(post, "title"), "visible", true);
setBoolean(find(post, "titleFld"), "visible", true);
setString(post, "text", getString(post, "text") + " (Textamerica API)");
add(post);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

View file

@ -136,7 +136,7 @@ public class LifeFTP extends LifeBlog
else
{
getThinlet().closeDialog(getDialog());
getThinlet().postDialog(getPath() + (getPath().endsWith("/") ? "" : "/") + getFilename(), getFilename());
getThinlet().postDialog(getPath() + (getPath().endsWith("/") ? "" : "/") + getFilename(), getFilename(), false);
}
ftp.logout();

View file

@ -45,11 +45,10 @@ import java.net.URLConnection;
/**
* The <code>LifeMediaObject</code> class posts a new media object via the metaWeblog.newMediaObject XML-RPC method.
*
* @author <a href="http://www.thauvin.net/erik/">Erik C. Thauvin</a>
* @author <a href="http://www.thauvin.net/erik/">Erik C. Thauvin</a>
* @version $Revision$, $Date$
*
* @created Jul 21, 2004
* @since 1.0
* @since 1.0
*/
public class LifeMediaObject extends LifeBlog
{
@ -59,14 +58,14 @@ public class LifeMediaObject extends LifeBlog
/**
* Creates a new LifeMediaObject 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 filename The name of the object to store.
* @param mimeType The object's MIME type.
* @param file The file to store.
* @param thinlet The Thinlet instance.
* @param url The XML-RPC URL endpoint.
* @param blogID The blog ID.
* @param login The login username.
* @param password The login password.
* @param filename The name of the object to store.
* @param mimeType The object's MIME type.
* @param file The file to store.
*
* @throws IOException If an error occurs while creating the object.
*/
@ -87,147 +86,18 @@ public class LifeMediaObject extends LifeBlog
*/
public final void run()
{
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
Base64.OutputStream out = null;
getThinlet().add(getDialog());
try
{
getThinlet().add(getDialog());
final URL url = new URL(getHost());
if (!"http".equalsIgnoreCase(url.getProtocol()))
{
throw new IOException("Unsupported URL protocol: " + url.getProtocol());
}
final File tmpFile = File.createTempFile(ReleaseInfo.getProject(), ".b64");
tmpFile.deleteOnExit();
fis = new FileInputStream(getFile());
fos = new FileOutputStream(tmpFile);
bos = new BufferedOutputStream(fos);
out = new Base64.OutputStream(bos, Base64.ENCODE | Base64.DONT_BREAK_LINES);
final byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) > 0)
{
out.write(buf, 0, len);
}
fis.close();
final StringBuffer start =
new StringBuffer("<?xml version=\"1.0\"?><methodCall><methodName>metaWeblog.newMediaObject</methodName><params><param><value><string>").append(_blogID)
.append("</string></value></param><param><value><string>")
.append(getLogin())
.append("</string></value></param><param><value><string>")
.append(getPassword())
.append("</string></value></param><param><value><struct><member><name>bits</name><value><base64>");
final StringBuffer end =
new StringBuffer("</base64></value></member><member><name>name</name><value><string>").append(getFilename())
.append("</string></value></member><member><name>type</name><value><string>")
.append(_mimeType)
.append("</string></value></member></struct></value></param></params></methodCall>");
final URLConnection urlConn = url.openConnection();
urlConn.setDoInput(true);
urlConn.setDoOutput(true);
urlConn.setUseCaches(false);
urlConn.setRequestProperty("Content-Length",
String.valueOf(start.length() + tmpFile.length() + end.length()));
urlConn.setRequestProperty("Content-Type", "text/xml");
final DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream());
dos.write(start.toString().getBytes());
dos.flush();
fis = new FileInputStream(tmpFile);
while ((len = fis.read(buf)) > 0)
{
dos.write(buf, 0, len);
dos.flush();
}
fis.close();
dos.write(end.toString().getBytes());
dos.flush();
dos.close();
final LifeRPCResponse xmlrpc = new LifeRPCResponse(urlConn.getInputStream());
if (xmlrpc.isValidResponse())
{
getThinlet().closeDialog(getDialog());
getThinlet().postDialog(xmlrpc.getResponse(), getFilename());
}
else
{
alert(xmlrpc.getResponse());
}
}
catch (IOException e)
{
final String url = LifeRPC.metaWeblogNewMediaObject(getHost(), _blogID, getLogin(), getPassword(),
getFilename(), _mimeType, getFile());
getThinlet().closeDialog(getDialog());
getThinlet().handleException(e);
getThinlet().postDialog(url, getFilename(), true);
}
finally
catch (Exception e)
{
if (fis != null)
{
try
{
fis.close();
}
catch (IOException ignore)
{
; // Do nothing
}
}
if (bos != null)
{
try
{
bos.close();
}
catch (IOException ignore)
{
; // Do nothing
}
}
if (fos != null)
{
try
{
fos.close();
}
catch (IOException ignore)
{
; // Do nothing
}
}
if (out != null)
{
try
{
out.close();
}
catch (IOException ignore)
{
; // Do nothing
}
}
alert(e.getMessage());
}
}
}

View file

@ -36,50 +36,51 @@
*/
package net.thauvin.lifeblogger;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
/**
* The <code>LifePost</code> class posts a new blog entry using the blogger.newPost() XML-RPC method.
*
* @author <a href="http://www.thauvin.net/erik/">Erik C. Thauvin</a>
* @author <a href="http://www.thauvin.net/erik/">Erik C. Thauvin</a>
* @version $Revision$, $Date$
*
* @created Jul 21, 2004
* @since 1.0
* @since 1.0
*/
public class LifePost extends LifeAction
{
private final String _blogEntry;
private final String _blogID;
private final boolean _publish;
private final String _entry;
private final String _file;
private final String _fileType;
private final String _title;
/**
* 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.
* @param publish DOCUMENT ME!
* @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 title The post's title, if any.
* @param description The blog description's text/description.
* @param file The file location, if any.
* @param fileType The file type, if any.
*
* @throws IOException If an error occurs while creating the object.
*/
public LifePost(LifeBlogger thinlet, String url, String blogID, String login, String password, String blogEntry,
boolean publish)
public LifePost(LifeBlogger thinlet, String url, String blogID, String login, String password, String title,
String description, String file, String fileType)
throws IOException
{
super(thinlet, url, login, password);
_blogEntry = blogEntry;
_entry = description;
_blogID = blogID;
_publish = publish;
_title = title;
_file = file;
_fileType = fileType;
}
/**
@ -89,122 +90,39 @@ public class LifePost extends LifeAction
*/
public final void run()
{
getThinlet().add(getDialog());
try
{
getThinlet().add(getDialog());
final String response;
final URL url = new URL(getHost());
if (!"http".equalsIgnoreCase(url.getProtocol()))
if (_file.length() != 0)
{
throw new IOException("Unsupported URL protocol: " + url.getProtocol());
response = LifeRPC.taEntryUpdate(getHost(), _blogID, getLogin(), getPassword(), _title, _entry, _file,
_fileType);
}
final StringBuffer request =
new StringBuffer("<?xml version=\"1.0\"?><methodCall><methodName>blogger.newPost</methodName><params><param><value><string>0a6afffffffaffffffb8ffffff8569474cffffffc778500c03ffffffecffffff876116565a27283bffffffda56</string></value></param><param><value><string>").append(_blogID)
.append("</string></value></param><param><value><string>")
.append(getLogin())
.append("</string></value></param><param><value><string>")
.append(getPassword())
.append("</string></value></param><param><value><string>")
.append(textToXML(_blogEntry))
.append("</string></value></param><param><value><boolean>")
.append(String.valueOf(_publish))
.append("</boolean></value></param></params></methodCall>");
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();
//System.out.println(request);
final LifeRPCResponse xmlrpc = new LifeRPCResponse(urlConn.getInputStream());
if (xmlrpc.isValidResponse())
else if (_title != null)
{
//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);
response = LifeRPC.metaWeblogNewPost(getHost(), _blogID, getLogin(), getPassword(), _title, _entry);
}
else
{
alert(xmlrpc.getResponse());
response = LifeRPC.bloggerNewPost(getHost(), _blogID, getLogin(), getPassword(), _entry);
}
getThinlet().setIcon(getThinlet().find(getDialog(), "iconlbl"), "icon",
getThinlet().getIcon("/icon/info.gif"));
getThinlet().setString(getThinlet().find(getDialog(), "message"), "text",
"Post successful. (ID " + response + ')');
getThinlet().setBoolean(getThinlet().find(getDialog(), "closebtn"), "enabled", true);
}
catch (IOException e)
catch (Exception e)
{
getThinlet().closeDialog(getDialog());
getThinlet().handleException(e);
alert(e.getMessage());
}
}
/**
* 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 ("&lt;");
}
// Convert ampersand
else if (ch == '&')
{
return ("&amp;");
}
// High/Low-ASCII character
else if ((ch >= 128) || (ch < 32))
{
c = (int) ch;
return ("&#" + c + ';');
}
// 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 XML
html.append(charToXML(text.charAt(i)));
}
// Return XML string
return html.toString();
}
}

View file

@ -0,0 +1,256 @@
/*
* @(#)LifeRPC.java
*
* Copyright (C) 2005 by Erik C. Thauvin (erik@thauvin.net)
* 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 org.apache.xmlrpc.Base64;
import org.apache.xmlrpc.XmlRpcClient;
import java.io.*;
import java.util.Hashtable;
import java.util.Vector;
/**
* The <code>LifeRPC</code> class implements the blogger.newPost, metaWeblog.newPost, metaWeblog.newMediaObject and
* ta.Entry.Update XML-RPC methods.
*
* @author Erik C. Thauvin
* @version $Revision$, $Date$
* @created Apr 13, 2005
* @since 1.0
*/
public class LifeRPC
{
/**
* Disables the default constructor.
*
* @throws UnsupportedOperationException if the constructor is called.
*/
private LifeRPC()
throws UnsupportedOperationException
{
throw new UnsupportedOperationException("Illegal constructor call.");
}
/**
* Implements the blogger.newPost XML-RPC call.
*
* @param url The XML-RPC URL endpoint.
* @param blogID The blog ID.
* @param login The login username.
* @param password The login password.
* @param description The blog description's text/description.
*
* @return The post ID.
*
* @throws Exception If an error occurred while posting.
*/
public static String bloggerNewPost(String url, String blogID, String login, String password, String description)
throws Exception
{
final XmlRpcClient xmlrpc = new XmlRpcClient(url);
final Vector params = new Vector(0);
// Set the API key
params.add("0a6afffffffaffffffb8ffffff8569474cffffffc778500c03ffffffecffffff876116565a27283bffffffda56");
params.add(blogID);
params.add(login);
params.add(password);
params.add(description);
// Set the publish flag
params.add(Boolean.valueOf(true));
return ((String) xmlrpc.execute("blogger.newPost", params));
}
/**
* Implements blogger.newPost XML-RPC call.
*
* @param url The XML-RPC URL endpoint.
* @param blogID The blog ID.
* @param login The login username.
* @param password The login password.
* @param filename The name of the object to store.
* @param mimeType The object's MIME type.
* @param file The file to store.
*
* @return The URL of the new media object.
*
* @throws Exception If an error occurred while upload the new media object.
*/
public static String metaWeblogNewMediaObject(String url, String blogID, String login, String password,
String filename, String mimeType, File file)
throws Exception
{
final XmlRpcClient xmlrpc = new XmlRpcClient(url);
final Vector params = new Vector(0);
final InputStream is = new FileInputStream(file);
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
final BufferedInputStream bufferedInputStream = new BufferedInputStream(is);
final byte[] bytes = new byte[1024];
int len = 0;
while ((len = bufferedInputStream.read(bytes)) > 0)
{
byteArrayOutputStream.write(bytes, 0, len);
}
is.close();
bufferedInputStream.close();
params.add(blogID);
params.add(login);
params.add(password);
final Hashtable media = new Hashtable(0);
media.put("name", filename);
media.put("type", mimeType);
media.put("bits", byteArrayOutputStream.toByteArray());
params.add(media);
final Hashtable response = (Hashtable) xmlrpc.execute("metaWeblog.newMediaObject", params);
return ((String) response.get("url"));
}
/**
* Implements the metaWeblog.newPost XML-RPC call.
*
* @param url The XML-RPC URL endpoint.
* @param blogID The blog ID.
* @param login The login username.
* @param password The login password.
* @param title The blog description's title.
* @param description The blog description's text/description.
*
* @return The post ID.
*
* @throws Exception If an error occurred while posting.
*/
public static String metaWeblogNewPost(String url, String blogID, String login, String password, String title,
String description)
throws Exception
{
final XmlRpcClient xmlrpc = new XmlRpcClient(url);
final Vector params = new Vector(0);
params.add(blogID);
params.add(login);
params.add(password);
final Hashtable blogEntry = new Hashtable(0);
blogEntry.put("title", title);
blogEntry.put("description", description);
params.add(blogEntry);
// Set the publish flag
params.add(Boolean.valueOf(true));
return ((String) xmlrpc.execute("metaWeblog.newPost", params));
}
/**
* Implements the metaWeblog.newPost XML-RPC call.
*
* @param url The XML-RPC URL endpoint.
* @param blogID The blog ID.
* @param login The login username.
* @param password The login password.
* @param title The blog description's title.
* @param description The blog description's text/description.
* @param file The file location.
* @param fileType The file type.
*
* @return The post ID.
*
* @throws Exception If an error occurred while posting.
*/
public static String taEntryUpdate(String url, String blogID, String login, String password, String title,
String description, String file, String fileType)
throws Exception
{
final XmlRpcClient xmlrpc = new XmlRpcClient(url);
final Vector params = new Vector(0);
final InputStream is = new FileInputStream(file);
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
final BufferedInputStream bufferedInputStream = new BufferedInputStream(is);
final byte[] bytes = new byte[1024];
int len = 0;
while ((len = bufferedInputStream.read(bytes)) > 0)
{
byteArrayOutputStream.write(bytes, 0, len);
}
is.close();
bufferedInputStream.close();
final byte[] encodedBytes = Base64.encode(byteArrayOutputStream.toByteArray());
// Set the API key
params.add("TA113805");
params.add(login);
params.add(password);
params.add(blogID);
// Set the entry ID
params.add("0");
params.add(title);
params.add(description);
// Set the category ID
params.add("0");
params.add(new String(encodedBytes));
params.add(fileType);
return ((String) xmlrpc.execute("ta.entry.Update", params));
}
}

View file

@ -1,174 +0,0 @@
/*
* @(#)LifeRPCResponse.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 thinlet.Thinlet;
import java.io.IOException;
import java.io.InputStream;
/**
* The <code>LifeRPCResponse</code> class uses the Thinlet DOM parser to process a XML-RCP response.
*
* @author <a href="http://www.thauvin.net/erik/">Erik C. Thauvin</a>
* @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 <code>true</code> is the response is valid, <code>false</code> 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);
if (string == null)
{
_response = getDOMText(value);
}
else
{
_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
}
}
}
}

View file

@ -1,5 +1,5 @@
/* Created by JReleaseInfo AntTask from Open Source Competence Group */
/* Creation date Sun Feb 06 00:48:16 PST 2005 */
/* Creation date Thu Apr 14 03:27:19 PDT 2005 */
package net.thauvin.lifeblogger;
import java.util.Date;
@ -12,28 +12,28 @@ import java.util.Date;
public class ReleaseInfo {
/** buildDate (set during build process to 1107679696812L). */
private static Date buildDate = new Date(1107679696812L);
/** buildDate (set during build process to 1113474439925L). */
private static Date buildDate = new Date(1113474439925L);
/**
* Get buildDate (set during build process to Sun Feb 06 00:48:16 PST 2005).
* Get buildDate (set during build process to Thu Apr 14 03:27:19 PDT 2005).
* @return Date buildDate
*/
public static final Date getBuildDate() { return buildDate; }
/**
* Get buildNumber (set during build process to 5).
* Get buildNumber (set during build process to 1).
* @return int buildNumber
*/
public static final int getBuildNumber() { return 5; }
public static final int getBuildNumber() { return 1; }
/** version (set during build process to "0.1.2"). */
private static String version = new String("0.1.2");
/** version (set during build process to "0.2"). */
private static String version = new String("0.2");
/**
* Get version (set during build process to "0.1.2").
* Get version (set during build process to "0.2").
* @return String version
*/
public static final String getVersion() { return version; }

View file

@ -7,6 +7,7 @@
<menu text="Blog" mnemonic="0">
<checkboxmenuitem name="ftp" text="Via FTP" group="via" mnemonic="4" action="setAction(this.name)"/>
<checkboxmenuitem name="mw" text="Via MetaWeblog" group="via" mnemonic="4" action="setAction(this.name)"/>
<checkboxmenuitem name="ta" text="Via Textamerica" group="via" mnemonic="4" action="setAction(this.name)"/>
</menu>
<menu text="Help" mnemonic="0">
<menuitem text="About" action="about()" icon="/icon/about.gif" mnemonic="0"/>

View file

@ -1,16 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<dialog name="dialog" icon="/icon/icon.gif" text="Post to Your Blog (Blogger API)" modal="false" columns="1" gap="4" top="4" left="4" bottom="4" right="4">
<dialog name="dialog" icon="/icon/icon.gif" text="Post to Your Blog" modal="false" columns="1" gap="4" top="4" left="4" bottom="4" right="4">
<panel name="blog" columns="2" halign="right" gap="4" weightx="1">
<label text="RPC URL:"/><textfield name="host" start="0" end="1000"/>
<label text="Blog ID:"/><textfield name="blogid"/>
<label text="Login:"/><textfield name="login"/>
<label text="Password:"/><passwordfield name="password"/>
<label text="Title: " name="titleFld" visible="false"/><textfield name="title" visible="false"/>
<label valign="top" text="Post:"/>
<textarea name="entry" width="300" height="150" weightx="1" weighty="1"/>
<textfield name="file" visible="false" editable="false"/>
</panel>
<panel columns="2" halign="right" gap="4">
<button name="cancelbtn" text="Cancel" icon="/icon/exit.gif" action="closeDialog(dialog)"/>
<!-- <button name="sendbtn" text="Post" icon="/icon/go.gif" action="post(dialog, blog)"/> -->
<button name="sendbtn" text="Post" icon="/icon/go.gif" action="publish(dialog, blog)"/>
</panel>
</dialog>

View file

@ -68,7 +68,7 @@ End If
</tr>
<tr>
<td valign="top" width="219"><p>LifeBlogger allows you to post your <a href="http://www.nokia.com/lifeblog/">Nokia Lifeblog</a> favorites to your blog.</p>
<p>Your images, text notes and videos can now be effortlessly posted to your blog using FTP <span class="Grey10px">(<a href="http://www.blogger.com/">Blogger</a>, etc.)</span> or via the MetaWeblog API <span class="Grey10px">(<a href="http://www.movabletype.org/">Movable Type</a>, <a href="http://radio.userland.com/">Radio UserLand</a>, etc.)</span> <a href="http://www.russellbeattie.com/notebook/1007954.html" class="Grey10px">[More...]</a></p>
<p>Your images, text notes and videos can now be effortlessly posted to your blog using FTP <span class="Grey10px">(<a href="http://www.blogger.com/">Blogger</a>, etc.)</span> or via the MetaWeblog API <span class="Grey10px">(<a href="http://www.movabletype.org/">Movable Type</a>, <a href="http://radio.userland.com/">Radio UserLand</a>, etc.)</span>, or via the <a href="http://www.textamerica.com/">Textamercia</a> API. <a href="http://www.russellbeattie.com/notebook/1007954.html" class="Grey10px">[More...]</a></p>
<p>LifeBlogger makes extensive use of various <strong>open source libraries</strong>, including:</p>
<ul>
<li><a href="http://www.thinlet.com/">Thinlet</a></li>
@ -76,7 +76,7 @@ End If
<li><a href="http://www.roxes.com/produkte/rat.html">Roxes Ant Tasks</a></li>
<li><a href="http://jakarta.apache.org/commons/net/">Commons Net</a></li>
<li><a href="http://www.ch-werner.de/javasqlite/">JavaSQLite</a></li>
<li><a href="http://iharder.sourceforge.net/base64/">Base64</a></li>
<li><a href="http://ws.apache.org/xmlrpc/">Apache XML-RPC</a></li>
</ul>
<p><br>
</p></td>