#!/usr/bin/perl # # JLJ # # Jerry's LiveJournal text-only perl script # # Tue Feb 6 14:08:39 EST 2001 # Version 1.6 # # Jerry's Homepage: http://www.cis.rit.edu/~jerry/ # Jerry's LiveJournal: http://jerronimo.livejournal.com/ # # Use this freely. There is no copyright or obligation to send me anything # for this script. Feel free to do with it as you will. # # No Warranty is either expressed or implied with this software. Use it # at your own risk! # you need to have a .livejournal.rc file in your $HOME directory. # it needs at least "user: YourUsername" and "password: YourPassword" # lines in it. There should be a sample file included with this package. # # For backups, you can also have a 'archive dir: /home/users/me' line in # the .rc file as well, to define where backups will get saved to. If you # don't, they will go to ~/.jljbackups my ($ver); $ver="1.6"; # 1.6 Cleaned up leading and trailing whitespace on mood autoselection # Picture selector doesn't ask if you only have one picture/Icon # Post to community journals # # 1.5 Tweaks for it to work under linux... I rewrote send_any_entry() # mood id selector with automatic chooser now # picture selector # integrated in Adam T. Lindsay's proxy code # # 1.4a Fixed some code so that backups now include Music and Mood properly # # 1.4 Added music & mood, re-wrote most other code. # # 1.3 Added backup, to keep a local copy of the journal. # # 1.2 Added the paragraph cleaner. (joins paragraphs together) # # 1.1 Added editor check, so you can edit with 'vi'. # It now submits the date/time of when you finish writing. # # 1.0 Basic functionality ########################### # Todo list: # # - cache the mood list # # - speeling checker # # - what to do if the server is down? # # - dump everything into the file, and store it aside in a queue. # then try to submit it (offline posting) (some things get hairy then.) # (rewrite all of the input routine code?) ######### Perl Behaviour require 5.002; use strict; use Socket; use Convert::Cyrillic; $|=1; # form details: # # webversion full # subject subject line # event text. html ok. # security 'public' 'private' 'friends' # prop_opt_preformatted preformat (auto format?) # prop_current_moodid mood id number (automatic selector in effect) # prop_current_mood mood text box # prop_current_music music text box # prop_picture_keyword select a picture to use (select via text) # use_journal select a journal to post to ###################################################################### ######### Globals my( $year, $month, $day, $hour, $min, $sec ); my( $subject, $body, $security, $mood, $music, $picture, $community ); my( $autoformat ); my( $rawmood, $rawmusic, $rawpicture, $rawcommunity ); my( %login_hash, %mood_hash ); my( %rcfile ); my $server = ""; ###################################################################### ######### Initialization functions ###################################################################### # setup the internally date variables sub init_date { my( $ddd, $mmm ); ($sec,$min,$hour,$ddd,$mmm,$year)= localtime(time); $year += 1900; $month = $mmm+1; $day = $ddd; return; printf "Date: %04d-%02d-%02d %02d:%02d\n", $year,$month,$day, $hour,$min; } ###################################################################### # read in the rc file into the %rcfile hash. sub read_rc { my ( $value, $rcfiledata, $line, $key, $node ); $rcfiledata = sprintf "%s/.livejournal.rc", $ENV{"HOME"}; if (!-e $rcfiledata) { printf "$rcfiledata: file not found!\n"; printf "create one! ie:\n\n"; printf "user: YourUserName\n"; printf "password: YourPassword\n\n"; exit(1); } open IF, "$rcfiledata"; foreach $line () { chomp $line; ($key, $node) = split ":", $line; next if ($key eq "" || $node eq ""); $key =~ s/\s//g; #$node =~ s/\s//g; $key = lc $key; $rcfile{$key} = (split " ", $node)[0]; } if (!exists $rcfile{"server"}) { $server = "www.livejournal.com"; } else { $server = $rcfile{"server"};} if (!exists $rcfile{"user"} || !exists $rcfile{"password"}) { printf "$rcfiledata: file incomplete!\n"; printf "you need both 'user' and 'password' entries!\n"; exit(1); } close IF, return; printf "Values read in:\n"; foreach $key (keys %rcfile) { if ($key eq "password") { $value = "******"; } else { $value = $rcfile{$key}; } printf " %15s %s\n", "|".$key ."|", $value; } } ###################################################################### ######### Get Info from the user ###################################################################### sub get_user_input_line { my ($text, $inline); $inline; $text = shift; printf "%s? ", $text; $inline = ; chomp $inline; return $inline; } sub get_user_input_picture { my ( $npics, $x, $inline, $pic_done ); $pic_done = 0; $npics = int $login_hash{"pickw_count"}; if ($npics <= 1) { # there's only one picture, no point in even asking. return; } while (!$pic_done) { printf "-----\n"; for ($x=1 ; $x <= $npics ; $x++) { printf "%3d %s\n", $x, $login_hash{"pickw_".$x}; } printf "-----\n"; printf "Enter a number or hit enter for default. \n"; printf "? "; $inline = ; chomp $inline; if ($inline eq "") { return ""; } if (int $inline > $npics) { printf "Value of 1 thru %d was expected, and not %d\n", int $login_hash{"pickw_count"}, int $inline; } else { return $login_hash{"pickw_". int $inline}; } } } sub get_user_input_community { my ( $ncommunities, $x, $inline, $community_done ); $community_done = 0; $ncommunities = int $login_hash{"access_count"}; if ($ncommunities == 0) { # no communities. just return return; } while (!$community_done) { printf "-----\n"; printf "%3d %s\n", 0, "(your own journal)"; for ($x=1 ; $x <= $ncommunities ; $x++) { printf "%3d %s\n", $x, $login_hash{"access_".$x}; } printf "-----\n"; printf "Enter a number or hit enter for your own journal. \n"; printf "? "; $inline = ; chomp $inline; if ($inline eq "") { return ""; } if (int $inline > $ncommunities) { printf "Value of 0 thru %d was expected, and not %d\n", $ncommunities, int $inline; } else { return $login_hash{"access_". int $inline}; } } } ###################################################################### # read in the body of the posting, or use the defined editor. sub read_body { my( $tempfilename, $done, $editor, $line ); $tempfilename = shift; $done = 0; $body = ""; if (defined $ENV{"EDITOR"}) { $editor = $ENV{"EDITOR"}; system "$editor $tempfilename"; if (!-s $tempfilename) { printf "Body is empty. Exiting.\n"; unlink $tempfilename; exit(1); } $body = ""; open IF, "$tempfilename"; foreach () { #chomp $_; $body .= "$_"; } close IF; unlink $tempfilename; } else { # old school bbs-style editor. ;) printf "Enter body of text. use a '.' on a line by itself to end.\n"; $done = 0; while ($done == 0) { $line = ; #chomp $line; if ($line eq ".\n") { $done = 1; } else { $body .= $line; } } } } ###################################################################### # save out a backup of the message if appropriate sub save_backup { my ( $yn, $backuppath, $filename, $junk ); if (!defined $rcfile{"archive"}) { $yn = get_user_input_line("Save a backup locally"); $yn =~ s/[\W0-9_]//g; } else { if ("y" ne lc substr $rcfile{"archive"}, 0, 1) { return; } } if ($yn eq "") { $yn = "y"; } if ("y" eq substr $yn, 0, 1) { if ($rcfile{"archivedir"} eq "") { $backuppath = sprintf "%s/.jljbackups", $ENV{"HOME"}; $backuppath =~ s/\/+$//g; printf "'archive dir' not defined in the .livejournal.rc file\n"; } else { $backuppath = sprintf $rcfile{"archivedir"}, $ENV{"HOME"}; } # sort it a little bit... $backuppath = $backuppath . "/" . $year . "/" . sprintf "%02d", $month ; $junk = `mkdir -p $backuppath 2>&1`; $junk = `chmod $backuppath 700 2>&1`; $filename = sprintf "%s/%02d_%02d:%02d", $backuppath, $day, int $hour,int $min; printf "Saving a backup copy in '$filename'\n"; open OF, ">$filename"; printf OF "Date: %04d-%02d-%02d %02d%s%02d\n", $year,$month,$day, $hour,':',$min; if ($rcfile{"moodprompt"} ne "no") { printf OF "Mood: %s\n", $rawmood; } if ($rcfile{"musicprompt"} ne "no") { printf OF "Music: %s\n", $rawmusic; } if ($rcfile{"pictureprompt"} ne "no") { printf OF "Picture: %s\n", $rawpicture; } if ($rcfile{"communityprompt"} ne "no") { printf OF "Journal: %s\n", $rawcommunity; } printf OF "Subject: %s\n\n", $subject; printf OF "%s", $body; close OF; } } ###################################################################### # prompt about other things if we need to. sub other_questions { my ($val, $valid, $mood_id); if (!defined $rcfile{"autoformat"}) { $val = get_user_input_line("Autoformat the text [y]/n"); $val = lc substr $val,0,1; } $autoformat = ($val eq "y" || lc (substr $rcfile{"autoformat"},0,1) eq "y") ? "&prop_opt_preformatted=1" : "&prop_opt_preformatted=0"; # if security isn't defined, assume public, if it's 'prompt' then ask. if ($rcfile{"security"} eq "prompt") { $security = ""; $valid = "public private friends"; while (-1 eq index $valid, $val) { $val = get_user_input_line("[public]/private/friends"); if ($val eq "") { $val = "public"; } } $security = "&security=$val"; } else { $security = "&security=public"; } if (!defined $rcfile{"moodprompt"} || $rcfile{"moodprompt"} eq "yes") { $rawmood = get_user_input_line("Current mood"); $rawmood =~ s/\s+/ /g; $rawmood =~ s/^\s//g; $rawmood =~ s/\s$//g; $mood_id = $mood_hash{lc $rawmood}; if($mood_id != 0) { $mood = "&prop_current_moodid=".$mood_id; } else { $mood = "&prop_current_mood=".$rawmood; } } if (!defined $rcfile{"musicprompt"} || $rcfile{"musicprompt"} eq "yes") { $rawmusic = get_user_input_line("Current music"); $rawmusic= Convert::Cyrillic::cstocs('koi8', 'win', $rawmusic); $music = "&prop_current_music=".$rawmusic; } if (!defined $rcfile{"communityprompt"} || $rcfile{"communityprompt"} eq "yes") { $rawcommunity = get_user_input_community(); if ($rawcommunity ne "") { $community = "&usejournal=".$rawcommunity; } else { $community = ""; } } if (!defined $rcfile{"pictureprompt"} || $rcfile{"pictureprompt"} eq "yes") { $rawpicture = get_user_input_picture(); if ($rawpicture ne "") { $picture = "&prop_picture_keyword=". webize($rawpicture); } else { $picture = ""; } } } ###################################################################### # Convert special characters to be web form friendly sub webize { my ($text); $text = shift; $text =~ s/(\W)/ sprintf "%%%02lX", ord $1 /eg; return $text; } ###################################################################### # send any entry sub send_any_entry { my ($in_addr, $addr, $proto, $remotehost, $remoteport, $length ); my ($fullbody, $retval, $resp, $body, $webpath); $body = shift; $retval = ""; if ($rcfile{"proxy"} eq "yes") { if (!defined ($rcfile{"proxyhost"})) { printf ".livejournal.rc file is incomplete!\n"; printf "When using a proxy, the proxy host needs to be defined!\n"; exit(1); } else { $webpath = "http://$server/interface/flat"; $remotehost = $rcfile{"proxyhost"}; if (defined($rcfile{"proxyport"})) { $remoteport = $rcfile{"proxyport"}; } else { $remoteport = 80; } } } else { $webpath = "http://$server/interface/flat"; my $tmp=gethostbyname($server); $remotehost = inet_ntoa($tmp); $remoteport = 80; } # print "server is $server, remotehost is $remotehost, webpath is $webpath, remoteport is $remoteport\n"; $length = length $body; $fullbody=< 2) { $past_header = 1; } } return %sifted; } sub figure_out_moods { my( $keyid, $keyname, $mood, $x ); $x = 1; while (1) { $keyid = sprintf "mood_%d_id", $x; $keyname = sprintf "mood_%d_name", $x; $mood = lc $login_hash{$keyname}; $mood =~ s/\s+/ /g; $mood =~ s/^\s//g; $mood =~ s/\s$//g; if ($mood ne "") { $mood_hash{$mood} = int $login_hash{$keyid}; } else { return; } $x++; } } sub login { my( $response, $user, $password, $form, $success, $loginname ); my( $clientversion ); $user = $rcfile{"user"}; $password = $rcfile{"password"}; $clientversion = sprintf "perl-JLJ/%s", $ver; # we really should cache the moods locally, to reduce the traffic... $form= sprintf "mode=login&user=$user&password=$password&clientversion=%s&getmoods=0&getpickws" , $clientversion; $response = send_any_entry ($form); %login_hash = parse_response($response); &figure_out_moods; $loginname = $login_hash{"name"}; $success = $login_hash{"success"}; if ($success ne "OK") { printf "Error encountered with server: %s is NOT 'OK'\n", $success; exit; } printf "Welcome, %s.\n", $loginname; } ###################################################################### # do EVERYTHING! ;) sub main { my ($tempfilename); &read_rc; &login; &init_date; # edit the temp file in the home directory, or in /tmp if $HOME is undefined $tempfilename = sprintf "%s/.jlj_temp_%04d%02d%02d_%02d:%02d:%02d", (defined $ENV{"HOME"})? $ENV{"HOME"} : "/tmp", $year, $month, $day, $hour, $min, $sec; # get the subject $subject = get_user_input_line("Subject"); &read_body ($tempfilename); # get the body &other_questions; # ask about mood, music, and security &init_date; # reset the date again &save_backup; # save aside the entry, if we want to &send_entry; # send it off... #printf "\nJLJ version $ver 2001-Feb-06\n"; #printf " Scott \"Jerry\" Lawrence jlj\@absynth.com\n"; #printf " http://jerronimo.livejournal.com\n"; #printf " http://www.cis.rit.edu/~jerry/Software/perl/#jlj\n\n"; } &main;