diff --git a/apps/syndie/java/build.xml b/apps/syndie/java/build.xml index af20fcf58a686dfe19328eb2c67e5d0e9b61bac4..59b11223f56beb366f4230db4ceffc39106a9686 100644 --- a/apps/syndie/java/build.xml +++ b/apps/syndie/java/build.xml @@ -19,7 +19,7 @@ <target name="jar" depends="builddep, compile"> <jar destfile="./build/syndie.jar" basedir="./build/obj" includes="**/*.class"> <manifest> - <attribute name="Main-Class" value="net.i2p.syndie.CLI" /> + <attribute name="Main-Class" value="net.i2p.syndie.CLIPost" /> <attribute name="Class-Path" value="i2p.jar" /> </manifest> </jar> diff --git a/apps/syndie/java/src/net/i2p/syndie/Archive.java b/apps/syndie/java/src/net/i2p/syndie/Archive.java index 43bb47402bfeb3ff56085e85762618ef6c769265..0487cabe1f682bffa1c30e92e66e6a1042976b73 100644 --- a/apps/syndie/java/src/net/i2p/syndie/Archive.java +++ b/apps/syndie/java/src/net/i2p/syndie/Archive.java @@ -6,6 +6,7 @@ import java.text.*; import net.i2p.I2PAppContext; import net.i2p.data.*; import net.i2p.syndie.data.*; +import net.i2p.util.Log; /** * Store blog info in the local filesystem. @@ -25,6 +26,7 @@ import net.i2p.syndie.data.*; */ public class Archive { private I2PAppContext _context; + private Log _log; private File _rootDir; private File _cacheDir; private Map _blogInfo; @@ -42,6 +44,7 @@ public class Archive { public Archive(I2PAppContext ctx, String rootDir, String cacheDir) { _context = ctx; + _log = ctx.logManager().getLog(Archive.class); _rootDir = new File(rootDir); if (!_rootDir.exists()) _rootDir.mkdirs(); @@ -69,12 +72,11 @@ public class Archive { if (bi.verify(_context)) { info.add(bi); } else { - System.err.println("Invalid blog (but we're storing it anyway): " + bi); - new Exception("foo").printStackTrace(); - info.add(bi); + _log.error("BlogInfo is invalid: " + bi); + meta.delete(); } } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error loading the blog", ioe); } } } @@ -110,8 +112,7 @@ public class Archive { } public boolean storeBlogInfo(BlogInfo info) { if (!info.verify(_context)) { - System.err.println("Not storing the invalid blog " + info); - new Exception("foo!").printStackTrace(); + _log.warn("Not storing invalid blog " + info); return false; } boolean isNew = true; @@ -130,10 +131,11 @@ public class Archive { FileOutputStream out = new FileOutputStream(blogFile); info.write(out); out.close(); - System.out.println("Blog info written to " + blogFile.getPath()); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Blog info written to " + blogFile.getPath()); return true; } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error writing out info", ioe); return false; } } @@ -174,8 +176,9 @@ public class Archive { entry = getCachedEntry(entryDir); if ( (entry == null) || (!entryDir.exists()) ) { if (!extractEntry(entries[j], entryDir, info)) { - System.err.println("Entry " + entries[j].getPath() + " is not valid"); - new Exception("foo!!").printStackTrace(); + if (_log.shouldLog(Log.ERROR)) + _log.error("Entry " + entries[j].getPath() + " is not valid"); + entries[j].delete(); continue; } entry = getCachedEntry(entryDir); @@ -183,12 +186,13 @@ public class Archive { String tags[] = entry.getTags(); for (int t = 0; t < tags.length; t++) { if (!rv.contains(tags[t])) { - System.out.println("Found a new tag in cached " + entry.getURI() + ": " + tags[t]); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Found a new tag in cached " + entry.getURI() + ": " + tags[t]); rv.add(tags[t]); } } } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error listing tags", ioe); } } // end iterating over the entries @@ -220,7 +224,7 @@ public class Archive { return ce; return null; } catch (IOException ioe) { - ioe.printStackTrace(); + _log.warn("Error reading cached entry... deleting cache elements"); } File files[] = entryDir.listFiles(); @@ -262,8 +266,8 @@ public class Archive { entry = getCachedEntry(entryDir); if ((entry == null) || !entryDir.exists()) { if (!extractEntry(entries[i], entryDir, info)) { - System.err.println("Entry " + entries[i].getPath() + " is not valid"); - new Exception("foo!!!!").printStackTrace(); + _log.error("Entry " + entries[i].getPath() + " is not valid"); + entries[i].delete(); continue; } entry = getCachedEntry(entryDir); @@ -274,8 +278,8 @@ public class Archive { entry.load(new FileInputStream(entries[i])); boolean ok = entry.verifySignature(_context, info); if (!ok) { - System.err.println("Keyed entry " + entries[i].getPath() + " is not valid"); - new Exception("foo!!!!!!").printStackTrace(); + _log.error("Keyed entry " + entries[i].getPath() + " is not valid"); + entries[i].delete(); continue; } @@ -294,16 +298,18 @@ public class Archive { for (int j = 0; j < tags.length; j++) { if (tags[j].equals(tag)) { rv.add(entry); - System.out.println("cached entry matched requested tag [" + tag + "]: " + entry.getURI()); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("cached entry matched requested tag [" + tag + "]: " + entry.getURI()); break; } } } else { - System.out.println("cached entry is ok and no id or tag was requested: " + entry.getURI()); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("cached entry is ok and no id or tag was requested: " + entry.getURI()); rv.add(entry); } } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error listing entries", ioe); } } return rv; @@ -322,11 +328,11 @@ public class Archive { BlogInfo info = getBlogInfo(uri); if (info == null) { - System.out.println("no blog metadata for the uri " + uri); + _log.error("no blog metadata for the uri " + uri); return false; } if (!container.verifySignature(_context, info)) { - System.out.println("Not storing the invalid blog entry at " + uri); + _log.error("Not storing the invalid blog entry at " + uri); return false; } else { //System.out.println("Signature is valid: " + container.getSignature() + " for info " + info); @@ -341,7 +347,7 @@ public class Archive { container.setCompleteSize(data.length); return true; } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error storing", ioe); return false; } } @@ -422,7 +428,7 @@ public class Archive { out.write(DataHelper.getUTF8(_index.toString())); out.flush(); } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error writing out the index"); } } } diff --git a/apps/syndie/java/src/net/i2p/syndie/ArchiveIndexer.java b/apps/syndie/java/src/net/i2p/syndie/ArchiveIndexer.java index 3deb3d1c7bc0965174e0dc45636fc715352a2ef8..a22b31436c101e16125dcc10b2d9d1bb84c4514f 100644 --- a/apps/syndie/java/src/net/i2p/syndie/ArchiveIndexer.java +++ b/apps/syndie/java/src/net/i2p/syndie/ArchiveIndexer.java @@ -7,6 +7,7 @@ import net.i2p.I2PAppContext; import net.i2p.data.*; import net.i2p.syndie.data.*; import net.i2p.syndie.sml.*; +import net.i2p.util.Log; /** * Dig through the archive to build an index @@ -16,6 +17,7 @@ class ArchiveIndexer { private static final int RECENT_ENTRY_COUNT = 10; public static ArchiveIndex index(I2PAppContext ctx, Archive source) { + Log log = ctx.logManager().getLog(ArchiveIndexer.class); LocalArchiveIndex rv = new LocalArchiveIndex(ctx); rv.setGeneratedOn(ctx.clock().now()); @@ -32,7 +34,7 @@ class ArchiveIndexer { rv.setHeader(tok.nextToken(), tok.nextToken()); } } catch (IOException ioe) { - ioe.printStackTrace(); + log.error("Error reading header file", ioe); } } @@ -66,7 +68,8 @@ class ArchiveIndexer { long metadate = metaFile.lastModified(); List entries = source.listEntries(key, -1, null, null); - System.out.println("Entries under " + key + ": " + entries); + if (log.shouldLog(Log.DEBUG)) + log.debug("Entries under " + key + ": " + entries); /** tag name --> ordered map of entryId to EntryContainer */ Map tags = new TreeMap(); @@ -83,7 +86,8 @@ class ArchiveIndexer { } Map entriesByTag = (Map)tags.get(entryTags[t]); entriesByTag.put(new Long(0-entry.getURI().getEntryId()), entry); - System.out.println("Entries under tag " + entryTags[t] + ":" + entriesByTag.values()); + if (log.shouldLog(Log.DEBUG)) + log.debug("Entries under tag " + entryTags[t] + ":" + entriesByTag.values()); } if (entry.getURI().getEntryId() >= newSince) { @@ -97,8 +101,8 @@ class ArchiveIndexer { BlogURI parent = new BlogURI(reply.trim()); if ( (parent.getKeyHash() != null) && (parent.getEntryId() >= 0) ) rv.addReply(parent, entry.getURI()); - else - System.err.println("Parent of " + entry.getURI() + " is not valid: [" + reply.trim() + "]"); + else if (log.shouldLog(Log.WARN)) + log.warn("Parent of " + entry.getURI() + " is not valid: [" + reply.trim() + "]"); } } diff --git a/apps/syndie/java/src/net/i2p/syndie/BlogManager.java b/apps/syndie/java/src/net/i2p/syndie/BlogManager.java index e9cba3d9e46ece37b00c7fa349307cacc4b8db00..7e4e18e28a03de5b1e920bb053c6a0d1b5e1ad59 100644 --- a/apps/syndie/java/src/net/i2p/syndie/BlogManager.java +++ b/apps/syndie/java/src/net/i2p/syndie/BlogManager.java @@ -10,12 +10,14 @@ import net.i2p.client.naming.PetNameDB; import net.i2p.data.*; import net.i2p.syndie.data.*; import net.i2p.syndie.sml.*; +import net.i2p.util.Log; /** * */ public class BlogManager { private I2PAppContext _context; + private Log _log; private static BlogManager _instance; private File _blogKeyDir; private File _privKeyDir; @@ -28,21 +30,30 @@ public class BlogManager { static { TimeZone.setDefault(TimeZone.getTimeZone("GMT")); - String rootDir = I2PAppContext.getGlobalContext().getProperty("syndie.rootDir"); - if (false) { - if (rootDir == null) - rootDir = System.getProperty("user.home"); - rootDir = rootDir + File.separatorChar + ".syndie"; - } else { - if (rootDir == null) - rootDir = "./syndie"; + } + + public static BlogManager instance() { + synchronized (BlogManager.class) { + if (_instance == null) { + String rootDir = I2PAppContext.getGlobalContext().getProperty("syndie.rootDir"); + if (false) { + if (rootDir == null) + rootDir = System.getProperty("user.home"); + rootDir = rootDir + File.separatorChar + ".syndie"; + } else { + if (rootDir == null) + rootDir = "./syndie"; + } + _instance = new BlogManager(I2PAppContext.getGlobalContext(), rootDir); + } + return _instance; } - _instance = new BlogManager(I2PAppContext.getGlobalContext(), rootDir); } - public static BlogManager instance() { return _instance; } - public BlogManager(I2PAppContext ctx, String rootDir) { + public BlogManager(I2PAppContext ctx, String rootDir) { this(ctx, rootDir, true); } + public BlogManager(I2PAppContext ctx, String rootDir, boolean regenIndex) { _context = ctx; + _log = ctx.logManager().getLog(BlogManager.class); _rootDir = new File(rootDir); _rootDir.mkdirs(); readConfig(); @@ -63,7 +74,8 @@ public class BlogManager { _userDir.mkdirs(); _tempDir.mkdirs(); _archive = new Archive(ctx, _archiveDir.getAbsolutePath(), _cacheDir.getAbsolutePath()); - _archive.regenerateIndex(); + if (regenIndex) + _archive.regenerateIndex(); } private File getConfigFile() { return new File(_rootDir, "syndie.config"); } @@ -76,13 +88,16 @@ public class BlogManager { for (Iterator iter = p.keySet().iterator(); iter.hasNext(); ) { String key = (String)iter.next(); System.setProperty(key, p.getProperty(key)); - System.out.println("Read config prop [" + key + "] = [" + p.getProperty(key) + "]"); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Read config prop [" + key + "] = [" + p.getProperty(key) + "]"); } } catch (IOException ioe) { - ioe.printStackTrace(); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Err reading", ioe); } } else { - System.out.println("Config doesn't exist: " + config.getPath()); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Config doesn't exist: " + config.getPath()); } } @@ -97,7 +112,7 @@ public class BlogManager { out.write(DataHelper.getUTF8(name + '=' + _context.getProperty(name) + '\n')); } } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error writing the config", ioe); } finally { if (out != null) try { out.close(); } catch (IOException ioe) {} } @@ -116,10 +131,10 @@ public class BlogManager { pub.writeBytes(out); priv.writeBytes(out); } catch (DataFormatException dfe) { - dfe.printStackTrace(); + _log.error("Error creating the blog", dfe); return null; } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error creating the blog", ioe); return null; } @@ -181,9 +196,9 @@ public class BlogManager { if (info != null) rv.add(info); } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error listing the blog", ioe); } catch (DataFormatException dfe) { - dfe.printStackTrace(); + _log.error("Error listing the blog", dfe); } } } @@ -201,10 +216,66 @@ public class BlogManager { priv.readBytes(in); return priv; } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error reading the blog key", ioe); return null; } catch (DataFormatException dfe) { - dfe.printStackTrace(); + _log.error("Error reading the blog key", dfe); + return null; + } + } + + public User getUser(Hash blog) { + File files[] = _userDir.listFiles(); + for (int i = 0; i < files.length; i++) { + if (files[i].isFile() && !files[i].isHidden()) { + Properties userProps = loadUserProps(files[i]); + if (userProps == null) + continue; + User user = new User(); + user.load(userProps); + if (blog.equals(user.getBlog())) + return user; + } + } + return null; + } + + /** + * List of User instances + */ + public List listUsers() { + File files[] = _userDir.listFiles(); + List rv = new ArrayList(); + for (int i = 0; i < files.length; i++) { + if (files[i].isFile() && !files[i].isHidden()) { + Properties userProps = loadUserProps(files[i]); + if (userProps == null) + continue; + User user = new User(); + user.load(userProps); + rv.add(user); + } + } + return rv; + } + + private Properties loadUserProps(File userFile) { + try { + Properties props = new Properties(); + FileInputStream fin = new FileInputStream(userFile); + BufferedReader in = new BufferedReader(new InputStreamReader(fin, "UTF-8")); + String line = null; + while ( (line = in.readLine()) != null) { + int split = line.indexOf('='); + if (split <= 0) continue; + String key = line.substring(0, split); + String val = line.substring(split+1); + props.setProperty(key.trim(), val.trim()); + } + String userHash = userFile.getName(); + props.setProperty(User.PROP_USERHASH, userHash); + return props; + } catch (IOException ioe) { return null; } } @@ -214,25 +285,17 @@ public class BlogManager { Hash userHash = _context.sha().calculateHash(DataHelper.getUTF8(login)); Hash passHash = _context.sha().calculateHash(DataHelper.getUTF8(pass)); File userFile = new File(_userDir, Base64.encode(userHash.getData())); - System.out.println("Attempting to login to " + login + " w/ pass = " + pass + if (_log.shouldLog(Log.INFO)) + _log.info("Attempting to login to " + login + " w/ pass = " + pass + ": file = " + userFile.getAbsolutePath() + " passHash = " + Base64.encode(passHash.getData())); if (userFile.exists()) { try { - Properties props = new Properties(); - FileInputStream fin = new FileInputStream(userFile); - BufferedReader in = new BufferedReader(new InputStreamReader(fin, "UTF-8")); - String line = null; - while ( (line = in.readLine()) != null) { - int split = line.indexOf('='); - if (split <= 0) continue; - String key = line.substring(0, split); - String val = line.substring(split+1); - props.setProperty(key.trim(), val.trim()); - } + Properties props = loadUserProps(userFile); + if (props == null) throw new IOException("Error reading " + userFile); return user.login(login, pass, props); } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error logging in", ioe); return "<span class=\"b_loginMsgErr\">Error logging in - corrupt userfile</span>"; } } else { @@ -251,7 +314,6 @@ public class BlogManager { public String getRemotePasswordHash() { String pass = _context.getProperty("syndie.remotePassword"); - System.out.println("Remote password? [" + pass + "]"); if ( (pass == null) || (pass.trim().length() <= 0) ) return null; return pass; } @@ -330,7 +392,7 @@ public class BlogManager { } _archive.setDefaultSelector(defaultSelector); } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error writing out the config", ioe); } finally { if (out != null) try { out.close(); } catch (IOException ioe) {} readConfig(); @@ -353,21 +415,30 @@ public class BlogManager { } } - public void saveUser(User user) { - if (!user.getAuthenticated()) return; - String userHash = Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(user.getUsername())).getData()); + /** + * Store user info, regardless of whether they're logged in. This lets you update a + * different user's info! + */ + void storeUser(User user) { + String userHash = user.getUserHash(); File userFile = new File(_userDir, userHash); + if (!userFile.exists()) return; FileOutputStream out = null; try { out = new FileOutputStream(userFile); out.write(DataHelper.getUTF8(user.export())); user.getPetNameDB().store(user.getAddressbookLocation()); } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error writing out the user", ioe); } finally { if (out != null) try { out.close(); } catch (IOException ioe){} } } + + public void saveUser(User user) { + if (!user.getAuthenticated()) return; + storeUser(user); + } public String register(User user, String login, String password, String registrationPassword, String blogName, String blogDescription, String contactURL) { System.err.println("Register [" + login + "] pass [" + password + "] name [" + blogName + "] descr [" + blogDescription + "] contact [" + contactURL + "] regPass [" + registrationPassword + "]"); String hashedRegistrationPassword = getRegistrationPasswordHash(); @@ -399,7 +470,7 @@ public class BlogManager { bw.write("showexpanded=false\n"); bw.flush(); } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error registering the user", ioe); return "<span class=\"b_regMsgErr\">Internal error registering - " + ioe.getMessage() + "</span>"; } finally { if (out != null) try { out.close(); } catch (IOException ioe) {} @@ -425,7 +496,7 @@ public class BlogManager { try { routerDb.store(); } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error exporting the hosts", ioe); return "<span class=\"b_addrMsgErr\">Error exporting the hosts: " + ioe.getMessage() + "</span>"; } } @@ -433,6 +504,21 @@ public class BlogManager { return "<span class=\"b_addrMsgOk\">Hosts exported</span>"; } + /** + * Guess what the next entry ID should be for the given user. Rounds down to + * midnight of the current day + 1 for each post in that day. + */ + public long getNextBlogEntry(User user) { + long entryId = -1; + long now = _context.clock().now(); + long dayBegin = getDayBegin(now); + if (user.getMostRecentEntry() >= dayBegin) + entryId = user.getMostRecentEntry() + 1; + else + entryId = dayBegin; + return entryId; + } + public BlogURI createBlogEntry(User user, String subject, String tags, String entryHeaders, String sml) { return createBlogEntry(user, subject, tags, entryHeaders, sml, null, null, null); } @@ -443,13 +529,7 @@ public class BlogManager { SigningPrivateKey privkey = getMyPrivateKey(info); if (privkey == null) return null; - long entryId = -1; - long now = _context.clock().now(); - long dayBegin = getDayBegin(now); - if (user.getMostRecentEntry() >= dayBegin) - entryId = user.getMostRecentEntry() + 1; - else - entryId = dayBegin; + long entryId = getNextBlogEntry(user); StringTokenizer tok = new StringTokenizer(tags, " ,\n\t"); String tagList[] = new String[tok.countTokens()]; @@ -466,12 +546,14 @@ public class BlogManager { raw.append(tagList[i]).append('\t'); raw.append('\n'); if ( (entryHeaders != null) && (entryHeaders.trim().length() > 0) ) { - System.out.println("Entry headers: " + entryHeaders); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Creating entry with headers: " + entryHeaders); BufferedReader userHeaders = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(DataHelper.getUTF8(entryHeaders)), "UTF-8")); String line = null; while ( (line = userHeaders.readLine()) != null) { line = line.trim(); - System.out.println("Line: " + line); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("header line: " + line); if (line.length() <= 0) continue; int split = line.indexOf('='); int split2 = line.indexOf(':'); @@ -520,7 +602,7 @@ public class BlogManager { return null; } } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error creating post", ioe); return null; } } @@ -536,7 +618,7 @@ public class BlogManager { info.load(metadataStream); return _archive.storeBlogInfo(info); } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error importing meta", ioe); return false; } } @@ -552,7 +634,7 @@ public class BlogManager { c.load(entryStream); return _archive.storeEntry(c); } catch (IOException ioe) { - ioe.printStackTrace(); + _log.error("Error importing entry", ioe); return false; } } @@ -616,7 +698,7 @@ public class BlogManager { Destination d = new Destination(location); return (d.getPublicKey() != null); } catch (DataFormatException dfe) { - dfe.printStackTrace(); + _log.error("Error validating address location", dfe); return false; } } else { diff --git a/apps/syndie/java/src/net/i2p/syndie/CLI.java b/apps/syndie/java/src/net/i2p/syndie/CLI.java index 83f9e9a23a52ca916301b7c35de1cf4a58522e0f..b51a94593c6365f5a6bc6ea25a8a2ac74b7c8f61 100644 --- a/apps/syndie/java/src/net/i2p/syndie/CLI.java +++ b/apps/syndie/java/src/net/i2p/syndie/CLI.java @@ -13,7 +13,7 @@ public class CLI { public static final String USAGE = "Usage: \n" + "rootDir regenerateIndex\n" + "rootDir createBlog name description contactURL[ archiveURL]*\n" + - "rootDir createEntry blogPublicKeyHash tag[,tag]* (NOW|entryId) (NONE|entryKeyBase64) smlFile[ attachmentFile]*\n" + + "rootDir createEntry blogPublicKeyHash tag[,tag]* (NEXT|NOW|entryId) (NONE|entryKeyBase64) smlFile[ attachmentFile attachmentName attachmentDescription mimeType]*\n" + "rootDir listMyBlogs\n" + "rootDir listTags blogPublicKeyHash\n" + "rootDir listEntries blogPublicKeyHash blogTag\n" + @@ -130,50 +130,117 @@ public class CLI { } private static void createEntry(String args[]) { - // "rootDir createEntry blogPublicKey tag[,tag]* (NOW|entryId) (NONE|entryKeyBase64) smlFile[ attachmentFile]*\n" + - + // "rootDir createEntry blogPublicKeyHash tag[,tag]* (NEXT|NOW|entryId) (NONE|entryKeyBase64) " + // smlFile[ attachmentFile attachmentName attachmentDescription mimeType]*\n" + String rootDir = args[0]; + String hashStr = args[2]; + List tags = new ArrayList(); + StringTokenizer tok = new StringTokenizer(args[3], ","); + while (tok.hasMoreTokens()) + tags.add(tok.nextToken().trim()); + String entryIdDef = args[4]; + String entryKeyDef = args[5]; + String smlFile = args[6]; + List attachmentFilenames = new ArrayList(); + List attachmentNames = new ArrayList(); + List attachmentDescriptions = new ArrayList(); + List attachmentMimeTypes = new ArrayList(); + for (int i = 7; i + 3 < args.length; i += 4) { + attachmentFilenames.add(args[i].trim()); + attachmentNames.add(args[i+1].trim()); + attachmentDescriptions.add(args[i+2].trim()); + attachmentMimeTypes.add(args[i+3].trim()); + } I2PAppContext ctx = I2PAppContext.getGlobalContext(); - BlogManager mgr = new BlogManager(ctx, args[0]); + BlogManager mgr = new BlogManager(ctx, rootDir); + EntryContainer entry = createEntry(ctx, mgr, hashStr, tags, entryIdDef, entryKeyDef, smlFile, true, + attachmentFilenames, attachmentNames, attachmentDescriptions, + attachmentMimeTypes); + if (entry != null) + mgr.getArchive().regenerateIndex(); + } + + /** + * Create a new entry, storing it into the blogManager's archive and incrementing the + * blog's "most recent id" setting. This does not however regenerate the manager's index. + * + * @param blogHashStr base64(SHA256(blog public key)) + * @param tags list of tags/categories to post under (String elements + * @param entryIdDef NEXT (for next entry id for the blog, or midnight of the current day), + * NOW (current time), or an explicit entry id + * @param entryKeyDef session key under which the entry should be encrypted + * @param smlFilename file in which the sml entry is to be found + * @param storeLocal if true, should this entry be stored in the mgr.getArchive() + * @param attachmentFilenames list of filenames for attachments to load + * @param attachmentNames list of names to use for the given attachments + * @param attachmentDescriptions list of descriptions for the given attachments + * @param attachmentMimeTypes list of mime types to use for the given attachments + * @return blog URI posted, or null + */ + public static EntryContainer createEntry(I2PAppContext ctx, BlogManager mgr, String blogHashStr, List tags, + String entryIdDef, String entryKeyDef, String smlFilename, boolean storeLocal, + List attachmentFilenames, List attachmentNames, + List attachmentDescriptions, List attachmentMimeTypes) { + Hash blogHash = new Hash(Base64.decode(blogHashStr)); + User user = mgr.getUser(blogHash); long entryId = -1; - if ("NOW".equals(args[4])) { + if ("NOW".equalsIgnoreCase(entryIdDef)) { entryId = ctx.clock().now(); + } else if ("NEXT".equalsIgnoreCase(entryIdDef) || (entryIdDef == null)) { + entryId = mgr.getNextBlogEntry(user); } else { try { - entryId = Long.parseLong(args[4]); + entryId = Long.parseLong(entryIdDef); } catch (NumberFormatException nfe) { nfe.printStackTrace(); - return; + return null; } } - StringTokenizer tok = new StringTokenizer(args[3], ","); - String tags[] = new String[tok.countTokens()]; - for (int i = 0; i < tags.length; i++) - tags[i] = tok.nextToken(); - BlogURI uri = new BlogURI(new Hash(Base64.decode(args[2])), entryId); + String tagVals[] = new String[(tags != null ? tags.size() : 0)]; + if (tags != null) + for (int i = 0; i < tags.size(); i++) + tagVals[i] = ((String)tags.get(i)).trim(); + BlogURI uri = new BlogURI(blogHash, entryId); BlogInfo blog = mgr.getArchive().getBlogInfo(uri); if (blog == null) { System.err.println("Blog does not exist: " + uri); - return; + return null; } SigningPrivateKey key = mgr.getMyPrivateKey(blog); try { - byte smlData[] = read(args[6]); - EntryContainer c = new EntryContainer(uri, tags, smlData); - for (int i = 7; i < args.length; i++) { - c.addAttachment(read(args[i]), new File(args[i]).getName(), - "Attached file", "application/octet-stream"); + byte smlData[] = read(smlFilename); + EntryContainer c = new EntryContainer(uri, tagVals, smlData); + if ( (attachmentFilenames != null) && + (attachmentFilenames.size() == attachmentNames.size()) && + (attachmentFilenames.size() == attachmentDescriptions.size()) && + (attachmentFilenames.size() == attachmentMimeTypes.size()) ) { + for (int i = 0; i < attachmentFilenames.size(); i++) { + File attachmentFile = new File((String)attachmentFilenames.get(i)); + String name = (String)attachmentNames.get(i); + String descr = (String)attachmentDescriptions.get(i); + String mimetype = (String)attachmentMimeTypes.get(i); + c.addAttachment(read(attachmentFile.getAbsolutePath()), name, descr, mimetype); + } } SessionKey entryKey = null; - if (!"NONE".equals(args[5])) - entryKey = new SessionKey(Base64.decode(args[5])); + if ( (entryKeyDef != null) && (entryKeyDef.trim().length() > 0) && (!"NONE".equalsIgnoreCase(entryKeyDef)) ) + entryKey = new SessionKey(Base64.decode(entryKeyDef)); c.seal(ctx, key, entryKey); - boolean ok = mgr.getArchive().storeEntry(c); - System.out.println("Blog entry created: " + c+ "? " + ok); - if (ok) - mgr.getArchive().regenerateIndex(); + if (storeLocal) { + boolean ok = mgr.getArchive().storeEntry(c); + //System.out.println("Blog entry created: " + c+ "? " + ok); + if (!ok) { + System.err.println("Error: store failed"); + return null; + } + } + user.setMostRecentEntry(uri.getEntryId()); + mgr.storeUser(user); // saves even if !user.getAuthenticated() + return c; } catch (IOException ioe) { ioe.printStackTrace(); + return null; } } diff --git a/apps/syndie/java/src/net/i2p/syndie/CLIPost.java b/apps/syndie/java/src/net/i2p/syndie/CLIPost.java new file mode 100644 index 0000000000000000000000000000000000000000..a5f21ccec138c56816fda5bfab3e6812179014f5 --- /dev/null +++ b/apps/syndie/java/src/net/i2p/syndie/CLIPost.java @@ -0,0 +1,206 @@ +package net.i2p.syndie; + +import java.io.*; +import java.util.*; +import net.i2p.*; +import net.i2p.data.*; +import net.i2p.syndie.data.*; +import net.i2p.util.EepPost; + +/** + * Simple CLI to post an entry. + * + */ +public class CLIPost { + public static final String USAGE = "Usage: \"" + CLIPost.class.getName() + " [args]\", where args are:" + + "\n --syndieDir $syndieRootDir // syndie root dir, under which syndie.config exists" + + "\n --blog $blogHash // base64 of the blog's key" + + "\n --sml $smlFile // file with the SML entry" + + "\n [--importurl ($url|none)] // defaults to http://localhost:7657/syndie/import.jsp" + + "\n [--proxyhost $hostname] // HTTP proxy host for sending the data to the import URL" + + "\n [--proxyport $portnum] // HTTP proxy port for sending the data to the import URL" + + "\n [--storelocal (true|false)] // should it be stored directly with the file system" + + "\n // (false by default, since its stored locally via importurl)" + + "\n [--entryId ($num|next|now)] // entryId to use: explicit, the blog's next (default), or timestamp" + + "\n [--attachment$N $file $name $desc $type]" + + "\n // Nth file / suggested name / description / mime type"; + + public static void main(String args[]) { + String rootDir = getArg(args, "syndieDir"); + String hashStr = getArg(args, "blog"); + String smlFile = getArg(args, "sml"); + if ( (rootDir == null) || (hashStr == null) || (smlFile == null) ) { + System.err.println(USAGE); + return; + } + + String url = getArg(args, "importurl"); + String entryIdDef = getArg(args, "entryId"); + + List attachmentFilenames = new ArrayList(); + List attachmentNames = new ArrayList(); + List attachmentDescriptions = new ArrayList(); + List attachmentMimeTypes = new ArrayList(); + while (true) { + // --attachment$N $file $name $desc $type] + String file = getAttachmentParam(args, attachmentFilenames.size(), 0); + String name = getAttachmentParam(args, attachmentFilenames.size(), 1); + String desc = getAttachmentParam(args, attachmentFilenames.size(), 2); + String type = getAttachmentParam(args, attachmentFilenames.size(), 3); + if ( (file != null) && (name != null) && (desc != null) && (type != null) ) { + attachmentFilenames.add(file); + attachmentNames.add(name); + attachmentDescriptions.add(desc); + attachmentMimeTypes.add(type); + } else { + break; + } + } + + List tags = readTags(smlFile); + + // don't support the entry key stuff yet... + String entryKeyDef = null; //args[5]; + + String loc = getArg(args, "storelocal"); + boolean storeLocal = false; + if (loc != null) + storeLocal = Boolean.valueOf(loc).booleanValue(); + + if (!storeLocal && "none".equalsIgnoreCase(url)) { + System.err.println("You need to post it somewhere, so either specify \"--storelocal true\""); + System.err.println("or don't specify \"--importurl none\""); + return; + } + + I2PAppContext ctx = I2PAppContext.getGlobalContext(); + BlogManager mgr = new BlogManager(ctx, rootDir, false); + EntryContainer entry = CLI.createEntry(ctx, mgr, hashStr, tags, entryIdDef, entryKeyDef, smlFile, storeLocal, + attachmentFilenames, attachmentNames, attachmentDescriptions, + attachmentMimeTypes); + if (entry != null) { + if (storeLocal) + mgr.getArchive().regenerateIndex(); + if (!("none".equalsIgnoreCase(url))) { + if ( (url == null) || (url.trim().length() <= 0) ) + url = "http://localhost:7657/syndie/import.jsp"; + + // now send it to the import URL + BlogInfo info = mgr.getArchive().getBlogInfo(entry.getURI().getKeyHash()); + File fMeta = null; + File fData = null; + + try { + fMeta = File.createTempFile("cli", ".snm", mgr.getTempDir()); + fData = File.createTempFile("cli", ".snd", mgr.getTempDir()); + FileOutputStream out = new FileOutputStream(fMeta); + info.write(out); + out.close(); + out = new FileOutputStream(fData); + entry.write(out, true); + out.close(); + } catch (IOException ioe) { + System.err.println("Error writing temp files: " + ioe.getMessage()); + return; + } + + Map uploads = new HashMap(2); + uploads.put("blogmeta0", fMeta); + uploads.put("blogpost0", fData); + + String proxyHost = getArg(args, "proxyhost"); + String proxyPortStr = getArg(args, "proxyport"); + int proxyPort = -1; + if (proxyPortStr != null) + try { proxyPort = Integer.parseInt(proxyPortStr); } catch (NumberFormatException nfe) { } + + OnCompletion job = new OnCompletion(); + EepPost post = new EepPost(); + post.postFiles(url, (proxyPort > 0 ? proxyHost : null), proxyPort, uploads, job); + boolean posted = job.waitForCompletion(30*1000); + if (posted) + System.out.println("Posted successfully: " + entry.getURI().toString()); + else + System.out.println("Posting failed"); + } else if (storeLocal) { + System.out.println("Store local successfully: " + entry.getURI().toString()); + } else { + // foo + } + } else { + System.err.println("Error creating the blog entry"); + } + } + + private static class OnCompletion implements Runnable { + private boolean _complete; + public OnCompletion() { _complete = false; } + public void run() { + _complete = true; + synchronized (OnCompletion.this) { + OnCompletion.this.notifyAll(); + } + } + public boolean waitForCompletion(long max) { + long end = max + System.currentTimeMillis(); + while (!_complete) { + long now = System.currentTimeMillis(); + if (now >= end) + return false; + try { + synchronized (OnCompletion.this) { + OnCompletion.this.wait(end-now); + } + } catch (InterruptedException ie) {} + } + return true; + } + } + + private static String getArg(String args[], String param) { + if (args != null) + for (int i = 0; i + 1< args.length; i++) + if (args[i].equalsIgnoreCase("--"+param)) + return args[i+1]; + return null; + } + private static String getAttachmentParam(String args[], int attachmentNum, int paramNum) { + if (args != null) + for (int i = 0; i + 4 < args.length; i++) + if (args[i].equalsIgnoreCase("--attachment"+attachmentNum)) + return args[i+1+paramNum]; + return null; + } + + private static List readTags(String smlFile) { + BufferedReader in = null; + try { + in = new BufferedReader(new InputStreamReader(new FileInputStream(smlFile), "UTF-8")); + String line = null; + while ( (line = in.readLine()) != null) { + if (line.length() <= 0) + return new ArrayList(); + else if (line.startsWith("Tags:")) + return parseTags(line.substring("Tags:".length())); + } + return null; + } catch (IOException ioe) { + return new ArrayList(); + } finally { + if (in != null) try { in.close(); } catch (IOException ioe) {} + } + } + + private static List parseTags(String tags) { + if (tags == null) + return new ArrayList(); + StringTokenizer tok = new StringTokenizer(tags, " ,\t\n"); + List rv = new ArrayList(); + while (tok.hasMoreTokens()) { + String cur = tok.nextToken().trim(); + if (cur.length() > 0) + rv.add(cur); + } + return rv; + } +} diff --git a/apps/syndie/java/src/net/i2p/syndie/User.java b/apps/syndie/java/src/net/i2p/syndie/User.java index d11856c62cdaccfbe13d132f655c960c7c5d1e49..3d25413e89151737ece0019770e24303f061d911 100644 --- a/apps/syndie/java/src/net/i2p/syndie/User.java +++ b/apps/syndie/java/src/net/i2p/syndie/User.java @@ -16,6 +16,7 @@ public class User { private String _username; private String _hashedPassword; private Hash _blog; + private String _userHash; private long _mostRecentEntry; /** Group name to List of blog selectors, where the selectors are of the form * blog://$key, entry://$key/$entryId, blogtag://$key/$tag, tag://$tag @@ -39,6 +40,8 @@ public class User { private String _torProxyHost; private int _torProxyPort; private PetNameDB _petnames; + + static final String PROP_USERHASH = "__userHash"; public User() { _context = I2PAppContext.getGlobalContext(); @@ -47,6 +50,7 @@ public class User { private void init() { _authenticated = false; _username = null; + _userHash = null; _hashedPassword = null; _blog = null; _mostRecentEntry = -1; @@ -70,6 +74,7 @@ public class User { public boolean getAuthenticated() { return _authenticated; } public String getUsername() { return _username; } + public String getUserHash() { return _userHash; } public Hash getBlog() { return _blog; } public String getBlogStr() { return Base64.encode(_blog.getData()); } public long getMostRecentEntry() { return _mostRecentEntry; } @@ -105,15 +110,22 @@ public class User { } public String login(String login, String pass, Properties props) { - String expectedPass = props.getProperty("password"); + _username = login; + load(props); String hpass = Base64.encode(_context.sha().calculateHash(DataHelper.getUTF8(pass)).getData()); - if (!hpass.equals(expectedPass)) { - _authenticated = false; + if (!hpass.equals(_hashedPassword)) { return "<span class=\"b_loginMsgErr\">Incorrect password</span>"; } - - _username = login; - _hashedPassword = expectedPass; + _lastLogin = _context.clock().now(); + _authenticated = true; + return LOGIN_OK; + } + + + public void load(Properties props) { + _authenticated = false; + _hashedPassword = props.getProperty("password"); + _userHash = props.getProperty(PROP_USERHASH); // blog=luS9d3uaf....HwAE= String b = props.getProperty("blog"); @@ -185,9 +197,6 @@ public class User { _eepProxyHost = props.getProperty("eepproxyhost"); _webProxyHost = props.getProperty("webproxyhost"); _torProxyHost = props.getProperty("torproxyhost"); - _lastLogin = _context.clock().now(); - _authenticated = true; - return LOGIN_OK; } private int getInt(String val) { diff --git a/history.txt b/history.txt index 32f3995ae35f40ade89ca0be458f1b0fc36b2cdb..c0147bff6abda59a4f2f346825f4e8f330dd6355 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,10 @@ -$Id: history.txt,v 1.286 2005/10/08 17:05:49 jrandom Exp $ +$Id: history.txt,v 1.287 2005/10/09 00:46:57 jrandom Exp $ + +2005-10-09 jrandom + * Syndie CLI cleanup for simpler CLI posting. Usage shown with + java -jar lib/syndie.jar + * Beginnings of the Syndie logging cleanup + * Delete corrupt Syndie posts 2005-10-09 jrandom * Now that the streaming lib works reasonably, set the default inactivity diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index a5408f020cc9cc7ed7485d556d44ec5cbc3e7c1b..4dc63df947567b3323ee0ff249039d2ebb400f36 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.261 $ $Date: 2005/10/08 17:05:48 $"; + public final static String ID = "$Revision: 1.262 $ $Date: 2005/10/09 00:46:57 $"; public final static String VERSION = "0.6.1.2"; - public final static long BUILD = 2; + public final static long BUILD = 3; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID);