Skip navigation
Syndie - distributed forums

# Manual

note: this manual has not yet been updated to cover the graphical Syndie client. This information is still however relevent for those running the text-only client (`syndie.exe --cli`) or for use with the text-only tab in the graphical interface.

The Syndie text interface is a context-sensitive menu driven application, and is fed commands from the standard input, allowing scriptable operation.

The application itself can be launched with zero, one, or two parameters:

        syndie [@script] [data_root]

The optional `@script` parameter reads in the contents of the `script` file, running them as if they came from the standard input. The optional `data_root` parameter tells Syndie where to locate the database, archive, and related data files. If not specified, it uses `$HOME/.syndie/` (or `%HOME%\.syndie` on windows).

When the interface starts up, the `data_root/scripts/startup` script is run, and when any nym logs in, the `data_root/scripts/login` script is run, if they exist. When a new nym is created (with register), the nym is given the preferences from the `data_root/scripts/defaultprefs` file (which contains newline delimited `name=value` pairs). The new nym is also given the aliases from the `data_root/scripts/defaultaliases` file (which also contains newline delimited `name=value` pairs)

The menus are outlined below, with unimplemented commands prefixed by `//`.

- Start menu
- General commands
- Read menu
- Manage menu
- Post menu
- Syndicate menu

- Start menu (not logged in) (up)
  `login [--db $jdbcURL] [--login $loginName --pass $password]`
    logs into Syndie at the default database location using the default login and password (each Syndie login has its own set of keys - just because one login has been authorized to post to a channel doesn't mean other logins are).
  `register [--db $jdbcURL] --login $loginName --pass $password --name $name`
    registers a new login in the Syndie database
  `restore --in $file [--db $jdbcURL]`
    Restore the Syndie database (backed up with the backup command), and archive, if included).
- General commands (available across all logged in menus) (up)
  `logout`
    Disconnect from the database, but do not exit Syndie
  `menu [$menuName]`
    Switch to the given menu, or list available menus
  `exit`
    Logout and exit Syndie
  `up`
    Move up a menu
  `togglePaginate`
    Start/stop paginating the output every 10 lines
  `toggleDebug`
    Start/stop displaying verbose messages to the user
  `prefs [--debug $boolean] [--paginate $boolean] [--httpproxyhost $hostname --httpproxyport $portNum] [--archive $archiveURL] [--freenetPrivateKey $privateKey] [--freenetPublicKey $publicKey] [--fcpHost $hostname] [--fcpPort $portNum]`
    Update the current nym's preferences, specifying the debug and paginate toggle state, the default HTTP proxy used for HTTP syndication, and the default archive location. These preferences are loaded whenever the nym logs in. If `prefs` is called with no arguments, then the preferences are simply displayed and not updated.
  `import --in $filename [--reimport $boolean] [--passphrase $pass]`
    Import the specified `.syndie` file (either a metadata message or a post). Alternately, it can import key files generated by `keygen`. If `reimport` is set, it will drop the message and reimport it, if necessary. If `passphrase` is specified, that will be used for the passphrase based encryption.
  `keygen --type (read|manage|post|reply) [--scope $channelHash] (--pubOut $publicKeyFile --privOut $privateKeyFile | --sessionOut $sessionKeyFile)`
    Generate a new crypto key for reading posts (an AES256 session key), signing channel management messages (a DSA1024 public and private keypair), signing channel posts (a DSA1024 public and private keypair), or reading/writing channel reply messages (an Elgamal2048 public and private keypair). The `--scope` parameter is just an informational field included in the key files so that on import, they can be used appropriately.
  `version`
    Display the current version of Syndie
  `?`
  `help`
    List commands available within the current menu
  `sql $sqlQuery` (advanced)
    Execute the given SQL query against the database, displaying the results
  `init $jdbcURL` (advanced)
    Create a new Syndie database at the given URL
  `backup --out $file [--includeArchive $boolean]`
    Backup the Syndie database to the given (compressed) file, optionally including the full content of the archive. If the filename specified includes the string "DATE", those four characters are replaced with the current date (YYYY-MM-DD)
  `builduri --url http://foo/bar`
  `builduri --channel $chanHash [--message $messageId [--page $pageNum]]`
  `builduri --archive $url [--password $pass]`
    Helpers for building Syndie URIs
  `history`
    Display the command history
  `!!`
    Execute the previous command again
  `!$num`
    Execute the $num-th command in the history
  `!-$num`
    Execute the command $num lines ago
  `^a[^b]`
    Replace the first occurrence of `a` with `b` in the previous command, and run it. If `^b` is not specified, the first occurrence of `a` is removed.
  `alias [foo $bar]`
    Configure the Syndie interface to interpret the command "$foo" as the command line $bar. $bar can contain any number of options, and can use ";" as a command delimiter, allowing e.g. `"alias bugs menu read; threads --channel all --tags syndie,bug,-wontfix,-closed,-worksforme,-claim"`. Aliases work in all menu contexts, and are run after attempting to interpret the command as a normal instruction - meaning you cannot effectively override existing commands with aliases.
  `definecmd --name $cmdName --class $className`
    Extend the text interface by defining a new command to be run when the specified name is executed.
  `ctrlserv ([--port $portNum])`
    Start the programmable control server, listening by default on port 10111. The control server will only listen on the loopback address (127.0.0.1). There is no security implemented. Anyone who can connect to the port will have complete access to impersonate you, read any messages you are authorized to read, etc.
  `httpserv ([--port $port] [--listeners $num] [--writable $boolean] | --kill true)`
    Run an HTTP server for the archive (or stop an existing one, if kill is specified). By default, it listens on port 8080 and can handle 5 concurrent requests. It supports GET for archive content (index files, metadata, messages) and POST compatible with the latest post command, but later it will include support for filters of what can be served up (limiting by channel, date, etc), and authentication for both GET and POST.
- Read menu (up)
  `channels [--unreadOnly $boolean] [--name $name] [--hash $hashPrefix]`
    Display a list of channels the user can access that matches the given criteria. The --name and --hash options limit the scope to channels whose name or identity hash starts with the given value.
  `next [--lines $num]`
  `prev [--lines $num]`
    Paginate through the result set of channels or messages, 10 (or $num) at a time
  `meta [--channel ($index|$hash)]`
    Display the current channel's metadata. If $index is specified, it refers to the $index-th channel in the 'channels' output, or if $hash is specified, it refers to the channel whose identity hash is given.
  `messages --channel ($index|$hash) [--includeUnauthorized $boolean] [--includeUnauthenticated $boolean]`
    Display a list of messages matching the given criteria.
  `threads [--channel ($index|$hash|all)] [--tags [-]tag[,[-]tag]*] [--includeUnauthorized $boolean] [--compact $boolean]`
    Display a list of threads matching the given criteria. The tags parameter picks threads where at least one message has each of the tags, and that none of the messages have any of the tags prefaced by `-`. The display can be fairly verbose or it can be compact (limiting the output to one line per thread). If called with no arguments, then it just displays the last set of matching threads again.
  `view (--message ($index|$uri)|--thread $index) [--page $n]`
    Display the first page of the specified message, including relevent metadata and the message's position within the thread, as well as references to other resources
  `threadnext [--position $position]`
    Jump to the next message in the thread (or to the one at the position specified)
  `threadprev [--position $position]`
    Jump to the previous message in the thread (or to the one at the position specified)
  `importkey --position $position`
    Import the referenced private key to post or manage a channel, or the session key to read posts for a channel.
  `export [--message ($index|$uri)] --out $directory`
    Dumps the full set of pages, attachments, references, metadata, and a status.txt summarizing the message to the given directory.
  `save [--message ($index|$uri)] (--page $n|--attachment $n) --out $filename`
    Save just the given page or attachment to the given file
  `reply`
    Jumps to the post menu, prepopulating the channel and references fields
  `ban [--scope (author|channel|$hash)] [--delete $boolean]`
    ban the author or channel so that no more posts from that author or messages by any author in that channel will be allowed into the Syndie archive. If --delete is specified, the messages themselves will be removed from the archive as well as the database
  `decrypt [(--message $msgId|--channel $channelId)] [--passphrase pass]`
    If the message or channel metadata in question was imported into the database before, but could not be decrypted at the time, you can attempt to decrypt it again later, using either the provided passphrase or the currently logged in nym's set of reply and channel read keys.
  //`watch (author|channel) [--nickname $name] [--category $nameInTree]`
- Manage menu (up)
  `channels`
    Display a list of channels that the current nym can manage
  `next [--lines $num]`
  `prev [--lines $num]`
    Paginate through the result set of channels, 10 (or $num) at a time
  `meta [--channel ($index|$hash)]`
    Display the current channel's metadata. If $index is specified, it refers to the $index-th channel in the 'channels' output, or if $hash is specified, it refers to the channel whose identity hash is given.
  `create`
  `update (--channel $index|$hash)`
    Begin the process of creating a new channel or updating an existing channel
  `set [$option=$value]*`
    Set various options on the channel being created or updated. They can be specified individually or on a single line.
  `set --name $channelName`
    Sets the channel's suggested name
  `set --description $desc`
    Sets the channel's description
  `set --avatar $filename`
    Bundle the 32x32 pixel PNG image as the channel's avatar
  `set --edition $editionNum`
    Specify the edition number to use for this metadata (if not specified, a randomized date-based edition will be used. note that the edition must be higher than the previous edition number)
  `set --expiration $yyyyMMdd`
    Suggest a date after which the channel metadata and all associated posts should be dropped (if not updated by then)
  `set --publicPosting $boolean`
    If true, anyone is implicitly authorized to post to the channel. If false, only those listed may.
  `set --publicReplies $boolean`
    If true, anyone is implicitly authorized to post replies to authorized messages in the channel, but not to post up new discussion threads. If false, only those listed may. This value is ignored if publicPosting is set to true.
  `set --pubTag [$tag[,$tag]*]`
    Specify tags that unauthorized people will be able to see regarding the channel
  `set --privTag [$tag[,$tag]*]`
    Specify additional tags that only authorized people will be able to see regarding the channel
  `set --refs $filename`
    Bundle the references loaded from the given file with the channel. The format is simple: `[[\t]*$name\t$uri\t$refType\t$description\n]*`. The tab indentation at the beginning of the line determines the tree structure, and blank values are allowed for various fields.
  `set --pubArchive [$syndieURI[,$syndieURI]*]`
    Specify a list of Syndie archives that people can look to for updates regarding this channel. The URIs themselves may include passphrases necessary for posting, etc.
  `set --privArchive [$syndieURI[,$syndieURI]*]`
    Specify an additional list of Syndie archives that only authorized people will be able to see regarding the channel.
  `set --encryptContent $boolean`
    Specify whether the metadata should encrypt its body without publicizing the body's encryption key. If it does, a private channel read key is included in the metadata that can be used to view or encrypt posts in the channel.
  `set --bodyPassphrase $passphrase`
    Encrypt the channel metadata with a key derived from the given passphrase
  `set --bodyPassphrasePrompt $prompt`
    When encrypting the channel metadata with a passphrase based key, include the given prompt in the clear, suggesting the passphrase to authorized readers. e.g. `set --bodyPassphrasePrompt "1+1" --bodyPassphrase "2"`
  `listnyms [--name $namePrefix] [--channel $hashPrefix]`
    Display an indexed list of channel signing keys matching the given criteria, allowing simple indexed selection of authorized nyms with addnym
  `addnym (--nym $index|--key $base64(pubKey)) --action (manage|post)`
    Add the given key to the list of authorized channel managers or posters
  `removenym (--nym $index|--key $base64(pubKey)) --action (manage|post)`
    Remove the given key from the list of authorized channel managers or posters
  `preview`
    Summarize the channel configuration before committing it
  `execute`
    Create a signed channel metadata file describing the new or updated channel configuration, importing the channel into the current Syndie database, and importing the channel manage, reply decryption, and read keys into the currently logged in Syndie account. This also clears the current create or update state
  `cancel`
    Cancel the current create or update state
- Post menu (up)
  `channels [--capability (manage|post)] [--name $name] [--hash $prefix]`
    Display a list of channels matching the given criteria.
  `next [--lines $num]`
  `prev [--lines $num]`
    Paginate through the result set of channels, 10 (or $num) at a time
  `meta [--channel ($index|$hash)]`
    Display the current channel's metadata. If $index is specified, it refers to the $index-th channel in the 'channels' output, or if $hash is specified, it refers to the channel whose identity hash is given.
  `create --channel ($index|$hash)`
    Begin the process of creating a new post
  `addpage [--page $num] --in ($filename|stdin) [--type $contentType]`
    Add a new page to the post, pulling data from the given file. If "stdin" is the `--in` parameter, the content is read from the standard input until terminated with a line containing only a single ".". The newlines are stripped on each line so that it ends with "\n" for all users, regardless of whether their OS uses "\n", "\r\n", or "\r" for line terminators. The `$num` is 1-based, so the first page is page 1.
  `listpages`
    Display a list of pages already scheduled for inclusion in the post
  `delpage $index`
    Remove the $index-th page
  `addattachment [--attachment $num] --in $filename [--type $contentType] [--name $name] [--description $desc]`
    Add a new attachment to the post The `$num` is 1-based, so the first attachment is attachment 1.
  `listattachments`
    Display a list of attachments already scheduled for inclusion in the post
  `delattachment $index`
    Remove the $index-th attachment
  `listkeys [--scope $scope] [--type $type]`
    Display the hash of private keys that the current Syndie nym has access to that match the given criteria, so that they can be fed into `addref`
  `addref --in $filename`
    Import all of the references in the given file
  `addref [--name $name] --uri $uri [--reftype $type] [--description $desc]`
    Add the specified reference to the post
  `addref --readkey $keyHash --scope $scope [--name $name] [--description $desc]`
    Add a reference that includes the given channel read key (AES256)
  `addref --postkey $keyHash --scope $scope [--name $name] [--description $desc]`
    Add a reference that includes the given channel post key (DSA private)
  `addref --managekey $keyHash --scope $scope [--name $name] [--description $desc]`
    Add a reference that includes the given channel management key (DSA private)
  `addref --replykey $keyHash --scope $scope [--name $name] [--description $desc]`
    Add a reference that includes the given channel's reply key (ElGamal private)
  `listrefs`
    Display a list of references already added, prefixed by an index
  `delref $index`
    Delete the given reference from the post
  `addparent --uri $uri`
    Add the given post's URI as a parent to the new post
  `listparents`
    Display a list of URIs this new post will be marked as replying to, with the most recent parent first
  `delparent $index`
    Remove the $index-th parent
  `listauthkeys [--authorizedonly $boolean]`
    Display an indexed list of signing keys that the current Syndie login has access to. If requested, this only includes those keys which have been marked as authorized to post in (or manage) the current channel.
  `authenticate $index`
    Use the specified key to authenticate the post as coming from the given author
  `authorize $index`
    Use the specified key to authorize the post as coming from someone allowed to post in the channel
  `listreadkeys`
    Display an indexed list of known channel read keys that we can use to encrypt the message
  `set --readkey (public|$index|pbe --passphrase $pass --prompt $prompt)`
    If `public`, create a random key and publicize it in the post's publicly readable headers. if pbe, then derive a read key from the passphrase, publicizing the prompt in the public headers. Otherwise, use the indexed channel read key
  `//set --cancel $uri[,$uri]*`
    Include instructions to cancel the given posts
  `set --messageId ($id|date)`
    Specify the post's messageId, or a random ID based on the current date
  `set --subject $subject`
    Specify the post's subject
  `set --avatar $filename`
    Specify the (32x32 pixel PNG) avatar to bundle with the post
  `set --encryptToReply $boolean`
    Encrypt the post to the channel's ElGamal reply key so only the channel owner can read the reply.
  `set --overwrite $uri`
    State that the new post will be trying to overwrite the given post, though the overwriting may not necessarily be honored
  `set --expiration ($yyyyMMdd|none)`
    Suggest that the post be deleted after the given date (or never)
  `set --forceNewThread $boolean`
    State that even if the post is replying to existing messages, it should branch off into a new thread
  `set --refuseReplies $boolean`
    State that only the author (and channel owner) can reply to the post within the current thread
  `set --publicTags $tag[,$tag]*`
    Specify tags that unauthorized people will be able to see regarding the message
  `set --privateTags $tag[,$tag]*`
    Specify tags that only people authorized to read the post can see
  `preview [--page $n]`
    View the post as it will appear
  `execute`
    Actually generate the post's signed .syndie file, and import it into the local Syndie database, clearing the creation state
  `cancel`
    Cancel the current creation state
- Syndicate menu (up)
  `buildindex`
    creates or updates the index of the local archive
  `getindex --archive $url [--proxyHost $host --proxyPort $port] [--pass $pass] [--scope (all|new|meta|unauth)] [--channel $chan] [--reimport $boolean]`
    fetch the index of the referenced archive, pulling in their list of all posts, new posts, only metadata, or new unauthenticated posts. If the $url begins with "/" or "file://", it is treated as a local archive on the filesystem, and the proxies are ignored. If the $url contains "SSK@", "USK@", or "CHK@", it is treated as a Freenet 0.7 archive, and the proxies are treated as the location of the fproxy instance (defaulting to localhost port 8888). Otherwise, the $url refers to a standard URL, and the HTTP proxies are used if specified. If `reimport` is set, individual posts that were already imported will be dropped and reimported.
  `diff`
    summarize the differences between the fetched index and the local db
  `fetch [--style (diff|known|metaonly|pir|unauth)] [--includeReplies $boolean]`
    actually fetch the posts/replies/metadata
  `(nextpbe|prevpbe) [--lines $num]`
    paginate through the messages using passphrase based encryption
  `resolvepbe --index $num --passphrase $passphrase`
    import the indexed message by using the specified passphrase
  `schedule --put (outbound|outboundmeta|archive|archivemeta) [--deleteOutbound $boolean] [--knownChanOnly $boolean]`
    schedule a set of messages to be posted. if specified, after a successful post transmission, the uploaded outbound messages will be deleted (but not messages stored in the archive only)
  `post [--postURL $url] [--passphrase $pass]`
    post the scheduled messages to the current archive (optionally using a different URL). This works by sending an RFC1867 HTTP POST containing the contents of the .syndie files in the fields `meta$n` and `post$n`, where n >= 0. If the passphrase is specified, it includes `pass=$pass`. Perhaps later that will switch to base64(HMAC($YYYYMMDD,PBE($password))) so it can be slightly secure even in absence of TLS/etc?
  `bulkimport --dir $directory --delete $boolean [--reimport $boolean]`
    import all of the .syndie files in the given directory, deleting them on completion. If `reimport` is set, individual posts that were already imported will be dropped and reimported.
  `freenetpost --privateSSK ($key|new) [--fcpHost localhost] [--fcpPort 9481]`
    post the entire local archive into Freenet, storing the data either in the given SSK or in a brand new SSK, as requested. This only works with Freenet 0.7.
  `listban`
    list the channels currently banned in the local archive
  `unban [--scope $index|$chanHash]`
    remove the specified ban

An example script:

        login
        menu post
        create --channel 0000000000000000000000000000000000000000
        addpage --in /etc/motd --type text/plain
        addattachment --in ~/public_html/webcam.png --type image/png --name cam.png
        listauthkeys --authorizedOnly true
        authenticate 0
        authorize 0
        set --subject "Today's MOTD"
        set --publicTags motd
        execute