#!/usr/bin/perl #BEGIN { # push @INC, "/opt/www/kokochi.com/mt/extlib"; #} use POSIX; use MIME::Explode; use XMLRPC::Lite; use Image::Size; # You need to have the perl MIME::Explode and XMLRPC::Lite modules installed. # You can get them at CPAN http://cpan.org/ # the following is to decode japanese encoding into HTML entities # see http://www.TokyoTidbits.com/ # Comment out the following line if you don't need japanese decoding use Dav::decode_iso_2002_jp; # meant to be used in conjunction with procmail # example, in your .procmailrc a block like: # :0 c: # * ^FROM.*yourcellphoneaddres@comapny,com # |/usr/local/bin/blogpost.pl # which pipes email from yourcellphoneaddres@comapny,com into this code # # requires existance of a .blogpostrc config file in your $HOME directory # or else the -c parameter (see below) # # example: # blogurl = http://www.danger-island.com/blog/ # blogxmlrpc = http://www.danger-island.com/mt/mt-xmlrpc.cgi # blogimgurl = http://www.danger-island.com/blog/images # subdir = default # output_dir = /apache/htdocs/blog/images # bloguser = mie # blogpass = mypassword # blogid = 1 # defaulttitle = new post from cell phone # defaultbody = # defaultcategory = 16 # # Note: default category is the category ID in moveable type # which you can find by doing a view source on a page that lets you # set the category. You can leave that out and it'll post with no # category. # # Disclaimer: I am not really a perl programmer. # you can specify which .blogpostrc file to use with -c # ...note that there is no space between -c and the file path # example procmailrc line: # |blogpost.pl -c/home/dav/.blogpostrc.hiptop_posts # REQUIRED HELPER APPS # pnmscale from the netpbm package # djpeg and cjpeg # mplayer # OPTIONAL HELPER APPS # GPS system # curl (needed for GPS) # this is used for new unique files my $datestring = strftime('%Y-%m-%d_%H%M%S', localtime); # set to 1 to enable GPS system my $gps_check = 1; my $gps_dir = '/home/users/dav/www/kokochi.com/gps'; my $gps_file = "$gps_dir/gpstag.dat"; my $gps_map = "map-$datestring.gif"; my $map_dir_url = 'http://kokochi.com/gps'; # ---------------------- # set utility variable # ---------------------- my $dir = "default"; my $ignore_gifs = false; # tmobile inserts a bunch of stupid gifs. ignore them. # ---------------------- # handle command line args # ---------------------- if ($#ARGV>-1) { if ($ARGV[0] =~ /-c(\S+)/) { $rcfile = $1; } } # ---------------------- # get ref to rc file # ---------------------- if (! defined $rcfile) { $home = $ENV{'HOME'}; if (!defined($home)) { die "cannot run blogpost.pl if \$HOME is not set\n"; } $rcfile = "$home/.blogpostrc"; } if (! -e $rcfile) { die "$rcfile not found\n"; } # ---------------------- # load rc file # ---------------------- &readSetup; $blogimgdirurl = "$blogimgurl/$dir"; $outputdatadir = "$output_dir/$dir"; #print "imgdirurl= $blogimgdirurl\n"; # ---------------------- # set up datestring for unique filenames # ---------------------- $pid = $$; $logfile = "$folder/$datestring.mail"; #$tmpfile = tmpnam(); #open( TMPOUT, ">$tmpfile" ); # ---------------------- # use MIME::Explode to parse mail content # ---------------------- my $explode = MIME::Explode->new( output_dir => $outputdatadir, mkdir => 0755, decode_subject => 1, chcek_content_type => 1, exclude_types => [], ); #my $headers = $explode->parse(\*STDIN, \*TMPOUT); my $headers = $explode->parse(\*STDIN); #&dumpAll; # parse out the headers &parseAll; # ---------------------- # rename images making them unique # ---------------------- for ($count = 0; $count<=$#attachments; $count++) { #print "RENAMING: $attachments[$count]\n"; $oldpath = "$outputdatadir/$attachments[$count]"; if ($oldpath =~ /\.([A-Za-z0-9]{2,4})$/) { my $ext_ = $1; if ($oldpath =~ /Jot.+\.([gG][iI][fF])$/) { # this is a gif file from the nokia digital pen $newname = "Jot_${datestring}_${pid}_${count}.gif"; } else { # this is something else, jpeg, or movie $newname = "${datestring}_${pid}_${count}.${ext_}"; } } else { # panic default # just name it something so it can be processed and recovered $newname = "${datestring}_${pid}_${count}.jpg"; } $newpath = "$outputdatadir/$newname"; rename( $oldpath, $newpath ) && ($attachments[$count]=$newname); } # ------------------------ # make thumbnails of jpegs and movies # ------------------------ # really, this should check the jpeg size first for ($count = 0; $count<=$#attachments; $count++) { my $orig_image = $attachments[$count]; my $stem; my $ext; ($stem, $ext) = split(/\./, $orig_image); if ($ext =~ /jpg$/i) { my $tmp_image = "/tmp/$stem.pnm"; my $tmp_thumb = "/tmp/th_$stem.pnm"; my $orig_thumb = "th_$orig_image"; system("djpeg -pnm \"$outputdatadir/$orig_image\" > \"$tmp_image\""); system("pnmscale -xysize 200 200 \"$tmp_image\" > \"$tmp_thumb\""); system("cjpeg \"$tmp_thumb\" > \"$outputdatadir/$orig_thumb\""); system("/bin/rm \"$tmp_thumb\""); system("chmod a+r \"$outputdatadir/$orig_thumb\""); # Mie's Nokia 7610 makes jpegs that are 1152x864 pixels. # That's really just too big for a blog/web thing, resize # to 800x600 my $tmp_orig = "/tmp/large_$stem.pnm"; system("pnmscale -xysize 800 800 \"$tmp_image\" > \"$tmp_orig\""); # overwrite the actual original image now system("cjpeg \"$tmp_orig\" > \"$outputdatadir/$orig_image\""); #system("/bin/rm \"$tmp_image\""); system("/bin/rm \"$tmp_orig\""); system("chmod a+r \"$outputdatadir/$orig_image\""); } elsif ($ext =~ /3gp$/i) { &make_video_thumbnail("$outputdatadir/$orig_image"); #./mplayer -vo jpeg -frames 1 -jpeg outdir=/tmp:quality=100:optimize=100 /tmp/2004-06-25_221301_23546_1.3gp } } # ---------------------- # just a hack, add an extra cmd line param to see output, for quick debugging # ---------------------- if ($#ARGV>0) { print "# Summary\n"; print "# date: $dateline\n"; print "# subject: $subject\n"; print "# body: $body\n"; foreach $attachment (@attachments) { print "# file A: $outputdatadir/$attachment\n"; } } # ---------------------- # set blog title and body to defaults if necessary # ---------------------- if ($subject eq '') { $subject = $default_title; } print "*********\nbody is:\n$body\n**********\n"; if ($body eq '') { if ($from =~ /4154255010.*tmo/) { foreach $attachment (@attachments) { print "* found tmobile ($from), looking for text: $attachment\n"; $ignore_gifs = true; if ($attachment =~ /\.txt$/i) { my $txt = ''; my $txtfile = "$outputdatadir/$attachment"; print "* found text: $txtfile\n"; if (open( TXTFILE, $txtfile)) { while () { $txt = "$txt$_" } close TXTFILE; $body = $txt; last; } else { print "* failed to open for reading: $txtfile\m"; } } } } else { $body = $default_body; } } print "*********\nbody is now:\n$body\n**********"; # ------------------------ # now prepare for posting # ------------------------ $postbody = ''; my $postbody_pen_gif_html; $image_count = 0; if ($#attachments>-1) { $postbody = "$postbody"; } my $in_tr = 0; foreach $attachment (@attachments) { print "* adding: $attachment\n"; if ($in_tr == 0) { $postbody = "$postbody"; $in_tr=1; } if ($attachment !~ /^Jot.+\.gif$/i) { # if it is one of these gifs then we need to skip this column $postbody = "$postbody"; } if ($image_count%2==0) { # this is 'cause M$ IE & moveable type weren't playing nice # on rendering the images... $postbody = "$postbody"; $in_tr = 0; } } # end foreach attachment if ($in_tr>0) { $postbody = "$postbody"; $in_tr = 0; } if ($#attachments>-1) { $postbody = $postbody."
"; } if ($attachment =~ /\.amc$/i) { # .amc files are the video clips from Mie's cellphone $postbody = "$postbody
EZ Movie file (.amc)

(Install Player)"; $image_count++; } elsif ($attachment =~ /(.+)\.3gp$/i) { # nokia movie file # used to be height 123 width 110 #$postbody = "$postbody
Quicktime 6.5 Movie (.3gp)
Download free player."; $postbody = "$postbody
Click to see video
."; $image_count++; } elsif ($attachment =~ /\.mov$/i) { # nokia movie file #$postbody = "$postbody
"; $postbody = "$postbody
Click to see video
."; $image_count++; } elsif ($attachment =~ /^Jot.+\.gif$/i) { # store this for now, so we can attach to the blog post after the jpg/movie table $postbody_pen_gif_html = "$postbody_pen_gif_html"; } elsif ( $attachment =~ /\.jpg$/i ) { # --------------------------------------------------- # if it's a jpg, check for any EXIF GPS embedded info # --------------------------------------------------- my $gpsinfo = undef; my $latitude = undef; my $latitude_ref = undef; my $longitude = undef; my $longitude_ref = undef; my $altitude = undef; $gpsinfo = `java -jar /home/dav/bin/metadata-extractor-2.1.jar $outputdatadir/$attachment`; if ($gpsinfo =~ m/GPS Altitude = (\d+) /) { $altitude = $1; } if ($gpsinfo =~ m/GPS Latitude Ref = ([NS])/) { $latitude_ref = $1; } if ($gpsinfo =~ m/GPS Latitude = (\d+).(\d+).(\d+).(\d+)/) { $latitude = "$1.$2.$3.$4"; } if ($gpsinfo =~ m/GPS Longitude Ref = ([EW])/) { $longitude_ref = $1; } if ($gpsinfo =~ m/GPS Longitude = (\d+).(\d+).(\d+).(\d+)/) { $longitude = "$1.$2.$3.$4"; } #print "lat: $latitude\n"; #print "lon: $longitude\n"; if (defined $latitude) { # we have GPS info, link the image to the mapping CGIs my $sign_latitude = $latitude; my $sign_longitude = $longitude; if ($latitude_ref eq 'S') { $sign_latitude = "-$latitude"; } if ($longitude_ref eq 'W') { $sign_longitude = "-$longitude"; } my $mapfan = "http://www.mapfan.com/map.cgi?ZM=10&SbmtPB=MAP&MAP=$longitude_ref$longitude$latitude_ref$latitude&Func=INDEX&&"; my $atnavi = "http://www.at-navi.com/pcx/jsp/map/mapMilLoginCtl.jsp?lat=${sign_latitude}&lon=${sign_longitude}&unit=0&datum=0&sc=2"; my $ttgps = "http://www.tokyotidbits.com/cgi-bin/gpsjpg?lat=${sign_latitude}&lon=${sign_longitude}&alt=${altitude}&jpg=$blogimgdirurl/$attachment"; $postbody = "$postbody
[location info]"; } else { # we have thumbnails for jpegs, link to source and display thumb $postbody = "$postbody"; my $width, $height; ($width, $height) = imgsize("$outputdatadir/th_$attachment"); if (defined $width && defined $height) { $postbody = "$postbody"; } else { $postbody = "$postbody"; } $image_count++; $postbody = "$postbody"; #$postbody = "$postbody"; } } elsif ($attachment =~ /\.gif$/i ) { if ($ignore_gifs eq false) { # just display gifs $postbody = "$postbody"; $image_count++; } else { print "* skipping gifs: $attachment\n"; } } else { print "* Ignoring attachment: $attachment\n"; # ignore other attachments fo rnow } if ($attachment !~ /^Jot.+\.gif$/i) { # if it is one of these gifs then we need to skip this column $postbody = "$postbody
"; } # add the pen gifs if there are any if (defined $postbody_pen_gif_html) { $postbody = $postbody."
$postbody_pen_gif_html"; $postbody = $postbody."
"; $postbody = $postbody."
"; $postbody = $postbody."[No transcription for handwritten text. Would you like to transcribe?]"; $postbody = $postbody.""; $postbody = $postbody."
"; $postbody = $postbody.""; $postbody = $postbody."
"; } # get rid of annoying yahoo signature my $yahoo_offset = index( $body, '_____________________________' ); if ($yahoo_offset>-1) { print "* Removing yahoo offset\n"; $body = substr($body, 0, $yahoo_offset); } if ($gps_check>0) { my $gps_block = &gpsHook; $postbody = $postbody.$gps_block; } # add the message body text $postbody = $postbody."
$body"; #just get rid of any newlines before MT gets them $postbody =~ s/\n//g; # NOTICE: delete the following two lines if you don't need japanese decoding $postbody = Dav::decode_iso_2002_jp::decode($postbody); $subject = Dav::decode_iso_2002_jp::decode($subject); # for 24 hour blog posting #if ($blogid==5) { # $postbody = "$postbody

This post is part of the Project Blog 24 hour blog for charity event. My charity is the Best Friends Animal Sanctuary"; #} # -------------------------- # post to MT via XML RPC # -------------------------- print "* Posting: $postbody\n"; # Note: for the publish/draft hack to work, the mt.cfg must have # the NoPublishMeansDraft option set to 1 if ($subject =~ /^-/) { print "as DRAFT\n"; } else { print "as PUBLISH\n"; } my $xmlrpcHandle = new XMLRPC::Lite; my $result = $xmlrpcHandle ->proxy($blogxmlrpc) ->call('metaWeblog.newPost', $blogid, $bloguser, $blogpass, { 'title' => $subject, 'description' => $postbody }, (($subject =~ /^-/)?0:1) ); # -------------------------- # If category is set, or if a handwritten gif is included then we need to # edit the posted entry to add category and/or comment id info for the # transcription cgi call # -------------------------- if ($result->fault) { print "* FAILED: $result\n"; print "* blogid: [$blogid]\n"; print "* bloguser: [$bloguser]\n"; print "* blogpass: [$blogpass]\n"; exit; } else { my $postid = $result->result(); print "* New entry posted, entry_id=$postid\n"; if (defined $default_category) { $categories[0] = [{ 'categoryId' => $default_category }]; $result = $xmlrpcHandle ->proxy($blogxmlrpc) ->call('mt.setPostCategories', $postid, $bloguser, $blogpass, @categories ); } # for some reason I can't figure out, __ENTRY_ID__ was not getting # replaced consistently. I figured it should be safe to remove this # conditional #if (defined $postbody_pen_gif_html) { # insert the blog post id into the transciption cgi URL print "* setting __ENTRYID__...\n"; $postbody =~ s/__ENTRYID__/$postid/; #} if (defined $default_category || defined $postbody_pen_gif_html) { # call editPost so it will rebuild post (adding category or id info) $result = $xmlrpcHandle ->proxy($blogxmlrpc) ->call('metaWeblog.editPost', $postid, $bloguser, $blogpass, { 'title' => $subject, 'description' => $postbody }, (($subject =~ /^-/)?0:1) ); print "* editPost returned $result\n"; } } #close TMPOUT; exit; # ********************************************************************* # ********************************************************************* # ********************************************************************* sub readSetup { $default_title = 'new cell shot'; $default_body = 'no description'; open( RC, $rcfile ) || die "cannot open $rcfile\n"; while () { chop; if ($_ =~ /blogurl\s*=\s*(.+)/) { $blogurl = $1; } elsif ($_ =~ /blogxmlrpc\s*=\s*(.+)/) { $blogxmlrpc = $1; } elsif ($_ =~ /blogimgurl\s*=\s*(.+)/) { $blogimgurl = $1; } elsif ($_ =~ /output_dir\s*=\s*(.+)/) { $output_dir = $1; } elsif ($_ =~ /subdir\s*=\s*(.+)/) { $dir = $1; } elsif ($_ =~ /bloguser\s*=\s*(.+)/) { $bloguser = $1; } elsif ($_ =~ /blogpass\s*=\s*(.+)/) { $blogpass = $1; } elsif ($_ =~ /blogid\s*=\s*(.+)/) { $blogid = $1; } elsif ($_ =~ /defaulttitle\s*=\s*(.+)/) { $default_title = $1; } elsif ($_ =~ /defaultbody\s*=\s*(.+)/) { $default_body = $1; } elsif ($_ =~ /defaultcategory\s*=\s*(.+)/) { $default_category = $1; } elsif ($_ =~ /transrcribe_cgi_url\s*=\s*(.+)/) { $transrcribe_cgi_url = $1; } elsif ($_ =~ /draft\s*=\s*(.+)/) { $draft_post = $1; } } close RC; #print "blogurl=$blogurl\n"; #print "blogurl=$blogimgurl\n"; #print "output=$output_dir\n"; #print "bloguser=[$bloguser]\n"; #print "blogpass=[$blogpass]\n"; } # ********************************************************************* sub parseAll { $jpgs=0; for my $part (sort{ $a cmp $b } keys(%{$headers})) { $filename = $headers->{$part}->{'content-disposition'}->{filename}; $filepath = $headers->{$part}->{'content-disposition'}->{filepath}; if ($filename eq 'file.txt') { $body = `cat $outputdatadir/$filename`; chop $body; } elsif ($filename ne '') { $attachments[$jpgs++]=$filename; $attachments_full[$jpgs]=$filepath; chmod 0644, $filepath; #print "filename: $filename\n"; #print "filepath: $filepath\n"; } } $from = $headers->{'0.0'}->{from}; $dateline = $headers->{'0.0'}->{date}; $subject = join("", @{$headers->{'0.0'}->{subject}->{value}}); } # ********************************************************************* sub dumpAll { for my $part (sort{ $a cmp $b } keys(%{$headers})) { for my $k (keys(%{$headers->{$part}})) { if(ref($headers->{$part}->{$k}) eq "ARRAY") { for my $i (0 .. $#{$headers->{$part}->{$k}}) { print "$part => $k => $i => ", $headers->{$part}->{$k}->[$i], "\n"; } } elsif(ref($headers->{$part}->{$k}) eq "HASH") { for my $ks (keys(%{$headers->{$part}->{$k}})) { if(ref($headers->{$part}->{$k}->{$ks}) eq "ARRAY") { print "$part => $k => $ks => ", join(($ks eq "charset") ? " " : "", @{$headers->{$part}->{$k}->{$ks}}), "\n"; } else { print "$part => $k => $ks => ", $headers->{$part}->{$k}->{$ks}, "\n"; } print "$part => $k => $ks => ", $headers->{$part}->{$k}->{$ks}, "\n"; } } else { print "$part => $k => ", $headers->{$part}->{$k}, "\n"; } } } } # end dumpAll ##### make video thumbnails sub make_video_thumbnail { my $dir, $stem; $video_file = shift; if ($video_file !~ /(.*)\/([^\/]+)\.3gp$/i && $video_file !~ /(.*)\/([^\/]+)\.mov$/i) { return; } else { $dir=$1; $stem=$2; } my $orig_video = $video_file; # grab first frame of video my $exe = "/home/dav/mplayer/bin/mplayer"; my $mplayer_opts = "-vo jpeg -frames 1"; my $jpeg_opts = "-jpeg outdir=/tmp:quality=100:optimize=100"; my $cmd = "$exe $mplayer_opts $jpeg_opts $orig_video"; system("$cmd >/dev/null 2>/tmp/make_vid_thumb.stderr"); # mplayer creates /tmp/0000000[12].jpg my $thumbnail = "$dir/vid_thumb_$stem.jpg"; system("/bin/mv \"/tmp/00000001.jpg\" \"$thumbnail\""); system("chmod a+r \"$thumbnail\""); # for some reason mplayer makes two jpegs system("/bin/rm \"/tmp/00000002.jpg\""); #print "thumbnail made for: $orig_video\n"; } # Checks in the filesystem for a gps tag file. # If it exists, it will use the coordinates to # plot a map for this posting and then delete # the file. sub gpsHook { $gps_block = ''; if (-e $gps_file) { print "* GPS tag file exists.\n"; open( GPS, $gps_file ); $latLine = ; $lonLine = ; $altLine = ; close( GPS ); if ($latLine =~ /lat=([\.\d-]+)/) { $lat = $1; } if ($lonLine =~ /lon=([\.\d-]+)/) { $lon = $1; } if ($altLine =~ /alt=([\.\d-M]+)/) { $alt = $1; } if (defined $lat && defined $lon) { # attempt to get a jpg map from tiger server and display it $tiger_map_url = &GetTigerMap( $lat, $lon); $mq_url = "http://www.mapquest.com/maps/map.adp?latlongtype=decimal&latitude=$lat&longitude=$lon&zoom=7"; $acme_url = "http://mapper.acme.com/?lat=$lat&long=$lon&scale=10&theme=ColorImage&width=4&height=3&dot=Yes"; # TODO: some security cleaning here $gps_block = "

\nLatitude: $lat
\nLongitude: $lon
\nAltitude: $alt
\n"; if (defined $tiger_map_url) { $gps_block .= "
" } $gps_block .= "[Street Map][Satellite Map]\n

\n"; } else { $gps_block = "\n" ."

[GPS tagging failed]

"; } system("/bin/mv $gps_file /tmp/"); } else { print "* GPS tag file [$gps_file] did not exist.\n"; } return $gps_block } # this attempts to download the appropriate map from the Tiger server and store # it in the local filesystem. This is needed because the tiger server takes 7-10 # seconds to generate the map. sub GetTigerMap { my $lat = shift; my $lon = shift; my $map_file = "$gps_dir/$gps_map"; my $url = "http://tiger.census.gov/cgi-bin/mapgen?lat=$lat&lon=$lon&mark=$lon,$lat,redpin&iht=200&iwd=320&wid=0.035&ht=0.035"; # get the gif from tiger my $cmd = "curl --silent --fail --output $map_file \"$url\""; #print "system: $cmd\n"; system($cmd); # make it world readable $cmd = "chmod a+r $map_file"; system($cmd); sleep 1; if (-e $map_file) { return "$map_dir_url/$gps_map"; } else { return undef; } } # http://maps.civicactions.net/cgi/mapserv.cgi?service=WMS&WMTVER=1.0.0&REQUEST=map&SRS=EPSG:4326&BBOX=-180,-90,180,90&WIDTH=800&HEIGHT=400&LAYERS=landsat7,bluemarble,lakes,rivers,cities,majorroads,minorroads,tiger_polygon,tiger_landmarks,tiger_lakes,tiger_local_roads,tiger_major_roads,lowboundaries,boundaries,coastlines&FORMAT=image/jpeg&STYLES=&TRANSPARENT=TRUE #<_dav> good gawd # i suggest leaving off landsat7 since the #($!@#$ landsat7 server has stopped working today of all days #<_dav> where's lat/lon in there? # BBOX