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
This commit is contained in:
jrandom
2005-10-09 11:35:13 +00:00
committed by zzz
parent 5dfa9ad7f6
commit 993c70f600
9 changed files with 503 additions and 123 deletions

View File

@ -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>

View File

@ -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");
}
}
}

View File

@ -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() + "]");
}
}

View File

@ -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";
}
_instance = new BlogManager(I2PAppContext.getGlobalContext(), rootDir);
}
public static BlogManager instance() { return _instance; }
public BlogManager(I2PAppContext ctx, String rootDir) {
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;
}
}
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 {

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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

View File

@ -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);