6 use lib
"$ENV{LJHOME}/cgi-bin";
19 use File
::Basename
();
21 # This has bitten us one too many times.
22 # Don't let startup continue unless LWP is ok.
23 die "* Installed version of LWP is too old! *" if LWP
->VERSION < 5.803;
27 return unless $u->has_password && $chal;
28 return "crp:$chal:" . Digest
::MD5
::md5_hex
($chal . $u->password_md5);
32 my ($u, $ua, $err) = @_;
33 return unless $u && $ua;
35 my $req = HTTP
::Request
->new(GET
=> "$LJ::FB_SITEROOT/interface/simple");
36 $req->push_header("X-FB-Mode" => "GetChallenge");
37 $req->push_header("X-FB-User" => $u->{'user'});
39 my $res = $$ua->request($req);
40 if ($res->is_success()) {
42 my $xmlres = XML
::Simple
::XMLin
($res->content);
43 my $methres = $xmlres->{GetChallengeResponse
};
44 return $methres->{Challenge
};
47 $$err = $res->content();
53 # name: LJ::FBUpload::do_upload
54 # des: Uploads an image to FotoBilder from LiveJournal.
55 # args: path, rawdata?, imgsec, caption?, galname
56 # des-path: => path to image on disk, or title to use if 'rawdata' isn't on disk.
57 # des-rawdata: => optional image data scalar ref.
58 # des-imgsec: => bitmask for image security. Defaults to private on
59 # unknown strings. Lack of an imgsec opt means public.
60 # des-caption: => optional image description.
61 # des-galname: => gallery to upload image to.
63 # returns: FB protocol data structure, regardless of FB success or failure.
64 # It's the callers responsibility to check the structure
65 # for FB return values.
66 # On HTTP failure, returns numeric HTTP error code, and
67 # sets $rv reference with errorstring. Or undef on unrecoverable failure.
70 my ($u, $rv, $opts) = @_;
71 unless ($u && $opts->{'path'}) {
72 $$rv = "Invalid parameters to do_upload()";
76 my $ua = LWP
::UserAgent
->new;
77 $ua->agent("LiveJournal_FBUpload/0.2");
80 my $chal = get_challenge
($u, \
$ua, \
$err);
82 $$rv = "Error getting challenge from FB server: $err";
86 my $rawdata = $opts->{'rawdata'};
88 # no rawdata was passed, so slurp it in ourselves
89 unless (open (F
, $opts->{'path'})) {
90 $$rv = "Couldn't read image file: $!\n";
95 { local $/ = undef; $data = <F
>; }
100 # convert strings to security masks/
101 # default to private on unknown strings.
102 # lack of an imgsec opt means public.
103 $opts->{imgsec
} ||= 255;
104 unless ($opts->{imgsec
} =~ /^\d+$/) {
106 private
=> 0, regusers
=> 253,
107 friends
=> 254, public
=> 255
109 $opts->{imgsec
} = 'private' unless $groupmap{ $opts->{imgsec
} };
110 $opts->{imgsec
} = $groupmap{ $opts->{imgsec
} };
113 my $basename = File
::Basename
::basename
($opts->{'path'});
114 my $length = length $$rawdata;
116 my $req = HTTP
::Request
->new(PUT
=> "$LJ::FB_SITEROOT/interface/simple");
118 'X-FB-Mode' => 'UploadPic',
119 'X-FB-UploadPic.ImageLength' => $length,
120 'Content-Length' => $length,
121 'X-FB-UploadPic.Meta.Filename' => $basename,
122 'X-FB-UploadPic.MD5' => Digest
::MD5
::md5_hex
($$rawdata),
123 'X-FB-User' => $u->{'user'},
124 'X-FB-Auth' => make_auth
($u, $chal),
125 ':X-FB-UploadPic.Gallery._size'=> 1,
126 'X-FB-UploadPic.PicSec' => $opts->{'imgsec'},
127 'X-FB-UploadPic.Gallery.0.GalName' => $opts->{'galname'} || 'LJ_emailpost',
128 'X-FB-UploadPic.Gallery.0.GalSec' => 255
131 $headers{'X-FB-UploadPic.Meta.Title'} = $opts->{title
}
134 $headers{'X-FB-UploadPic.Meta.Description'} = $opts->{caption
}
137 $req->push_header($_, $headers{$_}) foreach keys %headers;
139 $req->content($$rawdata);
140 my $res = $ua->request($req);
142 my $res_code = ($res->status_line =~ /^(\d+)/) ?
$1 : '';
143 unless ($res->is_success) {
144 $$rv = "HTTP error uploading pict: " . $res->content();
149 eval { $xmlres = XML
::Simple
::XMLin
($res->content); };
151 $$rv = "Error parsing XML: $@";
154 my $methres = $xmlres->{UploadPicResponse
};
155 $methres->{Title
} = $basename;
162 # arrayref of { title, url, width, height, caption }
163 # optional opts overrides hashref.
164 # (if not supplied, userprops are used.)
165 # returns: html string suitable for entry post body
166 # TODO: Hook this like the Fotobilder "post to journal"
167 # caption posting page. More pretty. (layout keywords?)
169 my ($u, $images, $opts) = @_;
172 $icount = scalar @
$images;
173 return "" unless $icount;
175 # Merge overrides with userprops that might
176 # have been passed in.
177 $opts = {} unless $opts && ref $opts;
178 my @props = qw
/ emailpost_imgsize emailpost_imglayout emailpost_imgcut /;
180 LJ
::load_user_props
( $u, @props );
184 $prop =~ s/emailpost_//;
185 $opts->{$prop} = lc($opts->{$prop}) || $u->{$_};
190 # set journal image display size
191 my @valid_sizes = qw
/ 100x100 320x240 640x480 /;
192 $opts->{imgsize
} = '320x240' unless grep { $opts->{imgsize
} eq $_; } @valid_sizes;
193 my ($width, $height) = split 'x', $opts->{imgsize
};
195 # force lj-cut on images larger than 320 in either direction
196 $opts->{imgcut
} = 'count'
197 if ( $width > 320 || $height > 320 ) && ! $opts->{imgcut
};
199 # insert image links into post body
200 my $horiz = $opts->{imglayout
} =~ /^horiz/i;
202 "<lj-cut text='$icount "
203 . ( ( $icount == 1 ) ?
'image' : 'images' ) . "'>"
204 if $opts->{imgcut
} eq 'count';
205 $html .= "<table border='0'><tr>" if $horiz;
207 foreach my $i ( @
$images ) {
208 my $title = LJ
::ehtml
($i->{'title'});
210 my ( $image_url, $page_url, $scaled_url );
211 $image_url = $i->{'url'};
213 my $image_uri = URI
->new($image_url);
214 my $image_hostname = $image_uri ?
$image_uri->host : '';
216 if ( $image_hostname =~ /^ic?[.]pics/ ) {
217 my ($extension) = ( $image_url =~ /(\w+)$/ );
219 $scaled_url = $page_url = $image_url;
220 $scaled_url =~ s/original\.\w+$//;
222 $scaled_url = $scaled_url . $width . '.' . $extension;
225 $page_url = $image_url . '/';
227 if ( $i->{'width'} > $width || $i->{'height'} > $height ) {
228 $scaled_url = $page_url . '/s' . $opts->{'imgsize'};
231 $scaled_url = $image_url;
235 # don't set a size on images smaller than the requested width/height
236 # (we never scale larger, just smaller)
237 my $size = '/s' . $opts->{imgsize
};
238 undef $size if $i->{width
} <= $width || $i->{height
} <= $height;
240 $html .= "<td>" if $horiz;
241 $html .= "<lj-cut text=\"$title\">" if $opts->{imgcut
} eq 'titles';
242 $html .= "<a href=\"$page_url\">";
243 $html .= "<img src=\"$scaled_url\" alt=\"$title\" border=\"0\">";
244 $html .= "</a><br />";
245 $html .= "$i->{caption}<br />" if $i->{caption
};
246 $html .= $horiz ?
'</td>' : '<br />';
247 $html .= "</lj-cut> " if $opts->{imgcut
} eq 'titles';
250 $html .= "</tr></table>" if $horiz;
251 $html .= "</lj-cut>\n" if $opts->{imgcut
} eq 'count';