Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"

Post a journal entry to

by rjray (Chaplain)
on Apr 06, 2002 at 08:14 UTC ( #157135=sourcecode: print w/replies, xml ) Need Help??
Category: Web stuff
Author/Contact Info rjray

This script is derived from one of the examples I developed for the chapter of my book that introduces the SOAP::Lite module.

It posts a journal entry to the journal system at, without using the browser interface, and without faking a POST to the CGI interface. It uses instead the still-alpha SOAP interface that use.perl currently offers.

All elements of the SOAP request may be specified on the command-line, including entry subject, whether to enable comments, uid and passwd, and the option of reading the entry from a file (the default is to read from STDIN, filter-like). It also will attempt to set the authentication credentials from your Netscape cookie file. But as I said, those can be set by the command-line (and the cmd-line switch overrides the Netscape cookie).

In a first-response to this code posting, I will post a XEmacs defun (which should also work under GNU/Emacs) that I use to post from within XEmacs by selecting the text I want to upload into the region. More on that in the follow-up node.


#!/usr/bin/perl -w

use strict;
use subs 'make_cookie';

use Getopt::Std;

use Digest::MD5 'md5_hex';
use HTTP::Cookies;
use SOAP::Lite;
use XML::RSS;

my (%opts, $title, $discuss, $readfh, $body, $host, $uri, $proxy,
    $cookie_file, $cookie_jar, $journal, $result);

getopts('c:m:f:C:', \%opts) or die <<"USAGE";
Usage: $0 [ -m title ] [ -f file ] [ -c yes|no ] [ -C user:pass ]

-m title        Provide title for the journal entry
                (default is command name-based)
-f file         Read the journal entry from FILE instead of STDIN
-c yes|no       Allow or disallow comments
                (default is to let your default stand)
-C user:pass    Provide authentication credentials in place of (or in
                absence of) Netscape cookie authentication. User in
                this case is UID, not nickname.


$title       = $opts{'m'} || "Generated by $0";
$discuss     = (exists $opts{c} && $opts{c} =~ /no/i) ? 0 : 1;
if ($opts{f}) {
    open(FILE, "< $opts{f}") or die "$0: Error opening $opts{f}: $!\n"
    $readfh = \*FILE;
} else {
    $readfh = \*STDIN;
$body = join('', "<!-- posted by $0 -->\n", <$readfh>);

$host        = '';
$uri         = "http://$host/Slash/Journal/SOAP";
$proxy       = "http://$host/";
$cookie_file = "$ENV{HOME}/.netscape/cookies";

if ($opts{C}) {
    $cookie_jar = HTTP::Cookies->new;
                            user => make_cookie(split /:/, $opts{C}, 2
                            '/', $host);
} elsif (-f $cookie_file) {
    $cookie_jar = HTTP::Cookies::Netscape->new(File => $cookie_file);
} else {
    die "$0: No authentication data found, cannot continue";

$journal = SOAP::Lite
               ->proxy($proxy, cookie_jar => $cookie_jar);
die "$0: Error creating SOAP::Lite client, cannot continue"
    unless $journal;
$result = $journal->add_entry(subject => $title,
                              body    => $body,
                              discuss => $discuss);

if ($result->fault) {
    die "$0: Operation failed: " . $result->faultstring . "\n";
} else {
    printf "New entry added as %s\n", $result->result;


# Taken from the Slash codebase
sub make_cookie {
    my ($uid, $passwd) = @_;
    my $cookie = $uid . '::' . md5_hex($passwd);
    $cookie =~ s/(.)/sprintf("%%%02x", ord($1))/ge;
    $cookie =~ s/%/%25/g;

Replies are listed 'Best First'.
(X)Emacs client
by rjray (Chaplain) on Apr 06, 2002 at 08:36 UTC

    This bit of elisp is something I use to post the contents of a buffer after editing it to my satisfaction. I'm posting it separately so that it doesn't interfere with the "Download Code" link for the Perl utility itself. It is not really complete, and certainly not perfect. Right now, you have to have the desired data in the region, I'd like for it to default to the whole buffer if the region isn't active (but there is no shell-command-on-buffer function in elisp, on the the region-oriented one).

    When run, it will prompt you for your use.perl UID and password if those are not already available. It can be called non-interactively with those values, plus a yes/no setting for enabling comments, and the entry subject. The UID and password (as well as the location of the script that gets used) can be configured with the following global values:

    Set this to your user ID. The SOAP interface works on UID's, not text names.
    Set this to your password (if you so desire to). If this is not set, you will be prompted, and the elisp API routine does an annoying video-inversion trick when reading a password. The defun tries to set a variable to disable this, as per the elisp docs, but it has no effect. I have this set on my home desktop, but not on my laptop or other machines that are more easily accessed by others.
    Set this to the path to the commands itself (from the parent post), if (X)Emacs is not likely to find it otherwise. For safety's sake, I have this set, to the value:
    (concat (getenv "HOME") "/bin/")

    The code:

    (defun perl-journal-post-entry (&optional uid &optional passwd &optional comment &optional subject) "Post the contents of the the current region as a journ +al entry." (interactive) (make-local-variable 'perl-journal-uid) (make-local-variable 'perl-journal-passwd) (make-local-variable 'perl-journal-command) (make-local-variable 'passwd-invert-frame-when-keyboard-grabbed) (let* ((p-command (cond (perl-journal-command) (t ""))) (p-uid (cond (uid) (perl-journal-uid) (t (read-string " UID: ")))) (p-passwd (cond (passwd) (perl-journal-passwd) (t (read-passwd " Password: "))) +) (p-comment (cond ((= comment "no") "no") (t "yes"))) (p-subject (cond (subject) (t (read-string "Entry subject: ")))) (passwd-invert-frame-when-keyboard-grabbed nil) (command (format "%s -m %S -c %s -C %S" p-command p-subject p-comment (format "%s:%s" p-uid p-passwd)))) (shell-command-on-region (region-beginning) (region-end) command)) +)


      Right now, you have to have the desired data in the region, I'd like for it to default to the whole buffer if the region isn't active (but there is no shell-command-on-buffer function in elisp, on the the region-oriented one).

      Perhaps . . .

      (if (not (region-exists-p)) (mark-whole-buffer))

      Update: You might want to do a save-excursion before that so you don't leave it marked afterwards. Of course it's been so long since I even tried diddling with elisp I can't remember if that's recommended or not.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://157135]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (2)
As of 2022-12-05 01:45 GMT
Find Nodes?
    Voting Booth?

    No recent polls found