[dw-free] Remove TxtLJ backend
[commit: http://hg.dwscoalition.org/dw-free/rev/fd9f9a2a1ed4]
http://bugs.dwscoalition.org/show_bug.cgi?id=199
Remove modules, tests, references to
Patch by
denise.
Files modified:
http://bugs.dwscoalition.org/show_bug.cgi?id=199
Remove modules, tests, references to
Patch by
![[staff profile]](https://www.dreamwidth.org/img/silk/identity/user_staff.png)
Files modified:
- bin/dev/inject_sms.pl
- bin/moveucluster.pl
- bin/upgrading/en.dat
- bin/upgrading/proplists.dat
- bin/worker/process-sms
- cgi-bin/LJ/Entry.pm
- cgi-bin/LJ/Event.pm
- cgi-bin/LJ/Event/CommunityInvite.pm
- cgi-bin/LJ/Event/CommunityJoinRequest.pm
- cgi-bin/LJ/Event/InvitedFriendJoins.pm
- cgi-bin/LJ/Event/JournalNewComment.pm
- cgi-bin/LJ/Event/JournalNewEntry.pm
- cgi-bin/LJ/Event/NewUserpic.pm
- cgi-bin/LJ/Event/OfficialPost.pm
- cgi-bin/LJ/Event/UserMessageRecvd.pm
- cgi-bin/LJ/Event/UserNewEntry.pm
- cgi-bin/LJ/NotificationItem.pm
- cgi-bin/LJ/NotificationMethod.pm
- cgi-bin/LJ/NotificationMethod/SMS.pm
- cgi-bin/LJ/SMS.pm
- cgi-bin/LJ/SMS/Message.pm
- cgi-bin/LJ/SMS/MessageAck.pm
- cgi-bin/LJ/SMS/MessageHandler.pm
- cgi-bin/LJ/SMS/MessageHandler/Add.pm
- cgi-bin/LJ/SMS/MessageHandler/Echo.pm
- cgi-bin/LJ/SMS/MessageHandler/Friends.pm
- cgi-bin/LJ/SMS/MessageHandler/Help.pm
- cgi-bin/LJ/SMS/MessageHandler/ILike.pm
- cgi-bin/LJ/SMS/MessageHandler/Menu.pm
- cgi-bin/LJ/SMS/MessageHandler/Post.pm
- cgi-bin/LJ/SMS/MessageHandler/PostComm.pm
- cgi-bin/LJ/SMS/MessageHandler/Read.pm
- cgi-bin/LJ/SMS/MessageHandler/Stop.pm
- cgi-bin/LJ/Setting/Display/SMSHistory.pm
- cgi-bin/LJ/Test.pm
- cgi-bin/LJ/User.pm
- cgi-bin/ljdb.pl
- cgi-bin/ljdefaults.pl
- cgi-bin/ljlib.pl
- doc/raw/build/ljconfig/ljconfig2db.pl
- doc/raw/lj.book/install/ljconfig.disabled.xml
- doc/raw/lj.book/install/ljconfig.helpurls.xml
- doc/raw/lj.book/install/workers_setup.xml
- t/esn-findsubscription.t
- t/esn-journalnewentry.t
- t/notificationmethod-sms.t
- t/sms-handler-postcomm.t
- t/sms-handler-read.t
-------------------------------------------------------------------------------- diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 bin/dev/inject_sms.pl --- a/bin/dev/inject_sms.pl Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -#!/usr/bin/perl - -use strict; -use lib "$ENV{LJHOME}/cgi-bin"; - -use LJ::SMS::Message; - -require "ljlib.pl"; - -my ($user, $msg) = @ARGV[0,1]; - -my $u = LJ::load_user($user); - -my $ljmsg = LJ::SMS::Message->new - ( owner => $u, - from => $u, - type => 'incoming', - body_text => $msg, - ); - -warn LJ::D($ljmsg); - -warn "Enqueue\n"; -LJ::SMS->enqueue_as_incoming($ljmsg); - - - diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 bin/moveucluster.pl --- a/bin/moveucluster.pl Mon Aug 03 15:16:25 2009 +0000 +++ b/bin/moveucluster.pl Mon Aug 03 15:24:55 2009 +0000 @@ -517,7 +517,6 @@ sub moveUser { $dbh->do("DELETE FROM syndicated WHERE userid = ?", undef, $u->id); $dbh->do("DELETE FROM supportnotify WHERE userid = ?", undef, $u->id); $dbh->do("DELETE FROM reluser WHERE userid = ?", undef, $u->id); - $dbh->do("DELETE FROM smsusermap WHERE userid = ?", undef, $u->id); $dbh->do("DELETE FROM friends WHERE userid = ?", undef, $u->id); $dbh->do("DELETE FROM phonepostlogin WHERE userid = ?", undef, $u->id); diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 bin/upgrading/en.dat --- a/bin/upgrading/en.dat Mon Aug 03 15:16:25 2009 +0000 +++ b/bin/upgrading/en.dat Mon Aug 03 15:24:55 2009 +0000 @@ -1700,8 +1700,6 @@ esn.officialpost.html=There is <a href=" esn.officialpost.html=There is <a href="[[url]]">a new announcement</a> in [[username]] esn.officialpost.nosubject=[[sitenameshort]] Announcement: New [[username]] announcement - -esn.officialpost.sms=There is a new [[sitename]] announcement in [[username]] Reply with READ [[username]] to read it. Standard rates apply. esn.officialpost.string=There is a new announcement in [[username]] at [[url]] @@ -1809,8 +1807,6 @@ esn.supofficialpost.html=There is <a hre esn.supofficialpost.nosubject=[[sitenameshort]] Announcement: New [[username]] announcement -esn.supofficialpost.sms=There is a new [[sitename]] announcement in [[username]] Reply with READ [[username]] to read it. Standard rates apply. - esn.supofficialpost.string=There is a new announcement in [[username]] at [[url]] esn.supofficialpost.subject=[[sitenameshort]] Announcement: [[subject]] @@ -2224,8 +2220,6 @@ notification_method.im.title=IM notification_method.im.title=IM notification_method.inbox.title=Inbox - -notification_method.sms.title=TxtLJ number.million=[[number]] million @@ -2637,10 +2631,6 @@ setting.display.secretquestion.actionlin setting.display.secretquestion.label=Secret Question -setting.display.smshistory.label=Text Messages - -setting.display.smshistory.option=View [[sms_title]] history - setting.display.username.actionlink=Rename setting.display.username.label=Username @@ -2826,28 +2816,6 @@ setting.sitescheme.error.invalid=Invalid setting.sitescheme.error.invalid=Invalid site scheme. setting.sitescheme.label=Site Scheme - -setting.sms.error.carrier.invalid=Invalid carrier selection. - -setting.sms.error.carrier.none=You must select a carrier in order to register. - -setting.sms.error.phone.failed=The number [[number]] could not be registered. - -setting.sms.error.phone.inuse=That number is currently in use by another user. - -setting.sms.error.phone.invalid=You must enter a valid U.S. 10-digit phone number. - -setting.sms.error.phone.ratelimit=You have tried to register a number too many times in one day. Please wait and try again. - -setting.sms.option=Receive updates and interact with LiveJournal by text message. - -setting.sms.option.advanced=advanced setup options - -setting.sms.option.carrier=Mobile Carrier: - -setting.sms.option.carrier.selectone=(Select Carrier) - -setting.sms.option.phone=Mobile Number: setting.stylealwaysmine.label=Other Journals diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 bin/upgrading/proplists.dat --- a/bin/upgrading/proplists.dat Mon Aug 03 15:16:25 2009 +0000 +++ b/bin/upgrading/proplists.dat Mon Aug 03 15:24:55 2009 +0000 @@ -974,62 +974,6 @@ userproplist.skype: multihomed: 1 prettyname: Skype ID -userproplist.sms_carrier: - cldversion: 4 - datatype: char - des: SMS carrier - indexed: 0 - multihomed: 0 - prettyname: SMS carrier - -userproplist.sms_enabled: - cldversion: 4 - datatype: char - des: If the user has activated and confirmed their SMS settings - indexed: 0 - multihomed: 0 - prettyname: SMS enabled status - -userproplist.sms_friend_group: - cldversion: 4 - datatype: char - des: Default SMS friends page display - indexed: 0 - multihomed: 0 - prettyname: SMS friends page group - -userproplist.sms_perday_notif_limit: - cldversion: 4 - datatype: num - des: Notification limit per day by SMS - indexed: 0 - multihomed: 0 - prettyname: SMS notification limit per day - -userproplist.sms_perpost_notif_limit: - cldversion: 4 - datatype: num - des: Notification limit per post per day by SMS - indexed: 0 - multihomed: 0 - prettyname: SMS notification limit per post per day - -userproplist.sms_post_notify: - cldversion: 4 - datatype: char - des: Does the user want notification of replies to posts made via SMS - indexed: 0 - multihomed: 0 - prettyname: Auto-subscribe to comments posted via SMS - -userproplist.sms_yes_means: - cldversion: 4 - datatype: char - des: What a "yes" SMS message from the user means - indexed: 0 - multihomed: 0 - prettyname: What "yes" SMS message means - userproplist.state: cldversion: 4 datatype: char @@ -1310,13 +1254,6 @@ logproplist.revtime: sortorder: 99 ownership: system -logproplist.sms_msgid: - datatype: num - des: SMS Message ID of the message which led to this journal entry - prettyname: SMS Message ID - sortorder: 99 - ownership: user - logproplist.statusvis: datatype: char des: 'V' or undef for visible, 'S' for suspended diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 bin/worker/process-sms --- a/bin/worker/process-sms Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -#!/usr/bin/perl -use strict; -use lib "$ENV{LJHOME}/cgi-bin"; -require 'ljlib.pl'; -require 'ljprotocol.pl'; -require 'ljlang.pl'; -use LJ::Worker::TheSchwartz; -use LJ::SMS; - -foreach my $classname (LJ::SMS->schwartz_capabilities) { - schwartz_decl($classname); -} - -schwartz_work(); - diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Entry.pm --- a/cgi-bin/LJ/Entry.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Entry.pm Mon Aug 03 15:24:55 2009 +0000 @@ -589,123 +589,6 @@ sub as_atom $xml =~ s!^<\?xml.+?>\s*!!s; return $xml; } - -sub as_sms { - my $self = shift; - my %opts = @_; - my $for_u = delete $opts{for_u}; - croak "invalid for_u arg to as_sms" - unless LJ::isu($for_u); - my $maxlen = delete $opts{maxlen} || 160; - croak "invalid parameters: " . join(",", keys %opts) - if %opts; - - my $ret = ""; - - # is this a community or journal post? - if ($self->journalid != $self->posterid) { - $ret .= "(" . $self->journal->display_name . ") "; - } - - # add in poster's username - $ret .= $self->poster->display_name . ":\n"; - - # now for the first $maxlen characters of the subject, - # falling back to the first $maxlen characters of the post - foreach my $meth (qw(subject_text event_text)) { - my $text = LJ::strip_html($self->$meth) or next; - $ret .= $for_u->max_sms_substr - ($text, maxlen => $maxlen, suffix => "..."); - last; - } - - return $ret; -} - -sub as_paged_sms { - my $self = shift; - my %opts = @_; - my $for_u = delete $opts{for_u}; - my $page = delete $opts{page} || 1; - $page = 1 if $page > 99; - croak "invalid parameters: " . join(",", keys %opts) - if %opts; - - my $full_text; - { - my $subj_text = $self->subject_text; - my $body_text = $self->event_text; - - if ($subj_text) { - $full_text = "[$subj_text] " . $body_text; - } else { - $full_text = "$body_text"; - } - - # full text should be devoid of html tags, with the - # exception of lj (user|comm) which just become a - # username - $full_text = LJ::strip_html($full_text); - } - - my $header = ""; - - # is this a community or journal post? - if ($self->journalid != $self->posterid) { - $header .= "(" . $self->journal->display_name . ") "; - } - - # add in poster's username - $header .= $self->poster->display_name; - - my %pageret = (); - my $maxpage = 1; - - { # lexical scope for 'use bytes' ... - use bytes; - - PAGE: - foreach my $currpage (1..99) { - - # Note: This is acknowledged to be ghetto. We set '99' for the max page - # number while we still build the list so that at the end once there - # is a real max number we can replace it. So the character capacity - # of a single '9' is lost when the total number of pages is single-digit - my $page_head = "${header} ($currpage of 99)\n"; - my $page_suffix = "..."; - - # if the length of this bit of text is greater than our page window, - # then append whatever fits and move onto the next page - # - note that max_sms_substr works on utf-8 character boundaries, so - # doing a subsequent length($to_append) is utf-8-safe - my $new_page = $for_u->max_sms_substr($page_head . $full_text, suffix => $page_suffix); - my $offset = length($new_page) - (length($page_head) + length($page_suffix)); - $full_text = substr($full_text, $offset); - - # remember this created page - $pageret{$currpage} = $new_page; - - # stop creating new pages once $full_text is drained - unless (length $full_text) { - - # strip "..." off of this page since it's the last - $pageret{$currpage} =~ s/$page_suffix$//; - - $maxpage = $currpage; - last PAGE; - } - } - } - - # did the user request an out-of-bounds page? - $page = 1 unless exists $pageret{$page}; - - # we reserved '99' for length checking above, now replace that with the real max number of pages - $pageret{$page} =~ s/\($page of 99\)/\($page of $maxpage\)/; - - return $pageret{$page}; -} - # raw utf8 text, with no HTML cleaning sub subject_raw { diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Event.pm --- a/cgi-bin/LJ/Event.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Event.pm Mon Aug 03 15:24:55 2009 +0000 @@ -189,13 +189,6 @@ sub subscription_as_html { return $class . " arg1: $arg1 arg2: $arg2 user: $user"; } -sub as_sms { - my $self = shift; - my $str = $self->as_string; - return $str if length $str <= 160; - return substr($str, 0, 157) . "..."; -} - # override in subclasses sub subscription_applicable { my ($class, $subscr) = @_; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Event/CommunityInvite.pm --- a/cgi-bin/LJ/Event/CommunityInvite.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Event/CommunityInvite.pm Mon Aug 03 15:24:55 2009 +0000 @@ -125,14 +125,6 @@ sub as_string { $self->comm->display_username); } -sub as_sms { - my $self = shift; - - return sprintf("%s sent you an invitation to join the community %s. Visit the invitation page to accept", - $self->inviter->display_username, - $self->comm->display_username); -} - sub subscription_as_html { my ($class, $subscr) = @_; return BML::ml('event.comm_invite'); # "I receive an invitation to join a community"; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Event/CommunityJoinRequest.pm --- a/cgi-bin/LJ/Event/CommunityJoinRequest.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Event/CommunityJoinRequest.pm Mon Aug 03 15:24:55 2009 +0000 @@ -133,14 +133,6 @@ sub as_email_html { return _as_email($self, $u, 1); } -sub as_sms { - my $self = shift; - - return sprintf("%s requests membership in %s. Visit community settings to approve.", - $self->requestor->display_username, - $self->comm->display_username); -} - sub subscription_as_html { my ($class, $subscr) = @_; return BML::ml('event.community_join_requst'); # Someone requests membership in a community I maintain'; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Event/InvitedFriendJoins.pm --- a/cgi-bin/LJ/Event/InvitedFriendJoins.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Event/InvitedFriendJoins.pm Mon Aug 03 15:24:55 2009 +0000 @@ -109,11 +109,6 @@ sub as_string { return sprintf "A friend you invited has created the journal %s.", $self->friend->user; } -sub as_sms { - my $self = shift; - return $self->as_string; -} - sub friend { my $self = shift; return LJ::load_userid($self->arg1); diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Event/JournalNewComment.pm --- a/cgi-bin/LJ/Event/JournalNewComment.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Event/JournalNewComment.pm Mon Aug 03 15:24:55 2009 +0000 @@ -158,31 +158,6 @@ sub as_string { } else { return "$poster has posted a new comment in $journal at " . $comment->url; } -} - -sub as_sms { - my ($self, $u) = @_; - - my $user = $self->comment->poster ? $self->comment->poster->display_username : '(Anonymous user)'; - my $edited = $self->comment->is_edited; - - my $msg; - - if ($self->comment->parent) { - if ($edited) { - $msg = LJ::u_equals($self->comment->parent->poster, $u) ? "$user edited a reply to your comment: " : "$user edited a reply to a comment: "; - } else { - $msg = LJ::u_equals($self->comment->parent->poster, $u) ? "$user replied to your comment: " : "$user replied to a comment: "; - } - } else { - if ($edited) { - $msg = LJ::u_equals($self->comment->entry->poster, $u) ? "$user edited a reply to your post: " : "$user edited a reply to a post: "; - } else { - $msg = LJ::u_equals($self->comment->entry->poster, $u) ? "$user replied to your post: " : "$user replied to a post: "; - } - } - - return $msg . $self->comment->body_text; } sub _can_view_content { diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Event/JournalNewEntry.pm --- a/cgi-bin/LJ/Event/JournalNewEntry.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Event/JournalNewEntry.pm Mon Aug 03 15:24:55 2009 +0000 @@ -96,14 +96,6 @@ sub as_string { if $entry->journal->is_person; return "$poster has posted a new entry$about in $journal at " . $entry->url; -} - -sub as_sms { - my $self = shift; - - my $incomm = $self->entry->journal->is_comm ? " in " . $self->entry->journal->user : ''; - sprintf("%s has posted with a new entry$incomm. To view, send READ %s to read it. Standard rates apply.", - $self->entry->poster->user, $self->entry->journal->user); } sub as_html { diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Event/NewUserpic.pm --- a/cgi-bin/LJ/Event/NewUserpic.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Event/NewUserpic.pm Mon Aug 03 15:24:55 2009 +0000 @@ -23,13 +23,6 @@ sub as_html { return "(Deleted userpic)" unless $up && $up->valid; return $self->event_journal->ljuser_display . " has uploaded a new <a href='" . $up->url . "'>userpic</a>."; -} - -sub as_sms { - my $self = shift; - - return $self->event_journal->display_username . " has uploaded a new userpic. You can view it at: " . - $self->userpic->url; } sub as_email_string { diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Event/OfficialPost.pm --- a/cgi-bin/LJ/Event/OfficialPost.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Event/OfficialPost.pm Mon Aug 03 15:24:55 2009 +0000 @@ -130,14 +130,6 @@ sub as_string { }); } -sub as_sms { - my $self = shift; - my $entry = $self->entry or return "(Invalid entry)"; - return sprintf("There is a new $LJ::SITENAMEABBREV announcement in %s. " . - "Reply with READ %s to read it. Standard rates apply.", - $entry->journal->display_username, $entry->journal->display_username); -} - sub subscription_as_html { my ($class, $subscr) = @_; return BML::ml('event.officialpost', { sitename => $LJ::SITENAME }); # $LJ::SITENAME makes a new announcement diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Event/UserMessageRecvd.pm --- a/cgi-bin/LJ/Event/UserMessageRecvd.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Event/UserMessageRecvd.pm Mon Aug 03 15:24:55 2009 +0000 @@ -130,15 +130,6 @@ sub as_string { return $ret; } -sub as_sms { - my $self = shift; - - my $subject = $self->load_message->subject; - my $other_u = $self->load_message->other_u; - return sprintf("You've received a new message \"%s\" from %s", - $subject, $other_u->user); -} - sub subscription_as_html { my ($class, $subscr) = @_; my $journal = $subscr->journal or croak "No user"; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Event/UserNewEntry.pm --- a/cgi-bin/LJ/Event/UserNewEntry.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Event/UserNewEntry.pm Mon Aug 03 15:24:55 2009 +0000 @@ -99,19 +99,6 @@ sub as_string { $self->poster->{name}); } -sub as_sms { - my $self = shift; - - my $entry = $self->entry; - my $where = "in their journal"; - unless ($entry->posterid == $entry->journalid) { - $where = "in '" . $entry->journal->{user} . "'"; - } - - return sprintf("User '%s' posted $where", $self->poster->{user}); - -} - sub as_html { my $self = shift; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/NotificationItem.pm --- a/cgi-bin/LJ/NotificationItem.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/NotificationItem.pm Mon Aug 03 15:24:55 2009 +0000 @@ -72,8 +72,6 @@ sub title { return eval { $self->event->as_html($self->u) } || $@; } elsif ($mode eq "im") { return eval { $self->event->as_im($self->u) } || $@; - } elsif ($mode eq "sms") { - return eval { $self->event->as_sms($self->u) } || $@; } } diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/NotificationMethod.pm --- a/cgi-bin/LJ/NotificationMethod.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/NotificationMethod.pm Mon Aug 03 15:24:55 2009 +0000 @@ -4,13 +4,12 @@ use Carp qw/ croak /; use Class::Autouse qw (LJ::Typemap LJ::NotificationMethod::Email - LJ::NotificationMethod::SMS LJ::NotificationMethod::Inbox LJ::NotificationMethod::IM LJ::NotificationMethod::DebugLog ); -# this mofo is basically just an interface +# this is basically just an interface # Mischa's contribution: "straight up" sub new { croak "can't instantiate base LJ::NotificationMethod" } sub notify { croak "can't call notification on LJ::NotificationMethod base class" } diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/NotificationMethod/SMS.pm --- a/cgi-bin/LJ/NotificationMethod/SMS.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -package LJ::NotificationMethod::SMS; - -use strict; -use Carp qw/ croak /; -use base 'LJ::NotificationMethod'; -use Class::Autouse qw( - LJ::SMS - LJ::SMS::Message - ); - -sub can_digest { 0 }; - -sub new { - my $class = shift; - my $u = shift; - croak "invalid user object passed" - unless LJ::isu($u); - - my $self = { u => $u }; - - return bless $self, $class; -} - -sub title { BML::ml('notification_method.sms.title') } - -sub help_url { "sms_about" } - -sub new_from_subscription { - my $class = shift; - my $subs = shift; - - return $class->new($subs->owner); -} - -sub u { - my $self = shift; - croak "'u' is an object method" - unless ref $self eq __PACKAGE__; - - if (my $u = shift) { - croak "invalid 'u' passed to setter" - unless LJ::isu($u); - - $self->{u} = $u; - } - croak "superfluous extra parameters" - if @_; - - return $self->{u}; -} - -# notify a single event -sub notify { - my $self = shift; - croak "'notify' is an object method" - unless ref $self eq __PACKAGE__; - - my $u = $self->u; - - croak "'notify' requires an event" - unless @_; - - my @events = @_; - - foreach my $ev (@events) { - croak "invalid event passed" unless ref $ev; - my $msg_txt = $ev->as_sms($u); - - last if $u->prop('sms_perday_notif_limit') && - $u->sms_sent_message_count(max_age => 86400, class_key_like => 'Notif%') >= $u->prop('sms_perday_notif_limit'); - - my $event_name = $ev->class; - $event_name =~ s/LJ::Event:://; - - my $msg = LJ::SMS::Message->new( - owner => $u, - to => $u, - body_text => $msg_txt, - class_key => 'Notif-' . $event_name, - ); - - $u->send_sms($msg); - } - - return 1; -} - -sub configured { - my $class = shift; - - # FIXME: should probably have more checks - return LJ::SMS->configured ? 1 : 0; -} - -sub configured_for_user { - my $class = shift; - my $u = shift; - - return LJ::SMS->configured_for_user($u) ? 1 : 0; -} - -sub disabled_url { "$LJ::SITEROOT/manage/sms/" } - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS.pm --- a/cgi-bin/LJ/SMS.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,469 +0,0 @@ -package LJ::SMS; - -# LJ::SMS object -# -# wrangles LJ::SMS::Messages and the app logic associated -# with them... -# -# also contains LJ::Worker class for incoming SMS -# - -use strict; -use Carp qw(croak); - -sub schwartz_capabilities { - return qw(LJ::Worker::IncomingSMS); -} - -sub load_mapping { - my $class = shift; - my %opts = @_; - my $uid = delete $opts{uid}; - my $num = delete $opts{num}; - my $force_master = delete $opts{force_master}; - croak "invalid options passed to load_mapping: " . join(",", keys %opts) - if %opts; - croak "can't pass both uid and num to load_mapping" - if defined $uid && defined $num; - croak "invalid userid: $uid" - if defined $uid && $uid !~ /^\d+$/; - croak "invalid number: $num" - if defined $num && $num !~ /^\+?\d+$/; - croak "no userid or number passed to load_mapping: uid=$uid, num=$num" - unless $uid || $num; - - my $force = $LJ::_PRAGMA_FORCE_MASTER || $force_master; - - my $db = $force ? LJ::get_db_writer() : LJ::get_db_reader() - or die "unable to contact db reader"; - - # load by userid if that's what was specified - if ($uid) { - my $row = $LJ::SMS::REQ_CACHE_MAP_UID{$uid}; - undef $row if $force; - - unless (ref $row) { - $row = $db->selectrow_hashref - ("SELECT number, userid, verified, instime " . - "FROM smsusermap WHERE userid=?", undef, $uid) || {}; - die $db->errstr if $db->err; - - # set whichever cache bits we can - $LJ::SMS::REQ_CACHE_MAP_UID{$uid} = $row; - $LJ::SMS::REQ_CACHE_MAP_NUM{$row->{number}} = $row if $row->{number}; - } - - # return row hashref - return $row; - } - - # load by msisdn 'num' - if ($num) { - my $row = $LJ::SMS::REQ_CACHE_MAP_NUM{$num}; - undef $row if $force; - - unless (ref $row) { - $row = $db->selectrow_hashref - ("SELECT number, userid, verified, instime " . - "FROM smsusermap WHERE number=?", undef, $num) || {}; - die $db->errstr if $db->err; - - # set whichever cache bits we can - $LJ::SMS::REQ_CACHE_MAP_NUM{$num} = $row; - $LJ::SMS::REQ_CACHE_MAP_UID{$row->{userid}} = $row if $row->{userid}; - } - - return $row; - } - - return undef; -} - -sub replace_mapping { - my ($class, $uid, $num, $verified) = @_; - $uid = LJ::want_userid($uid); - $verified = uc($verified); - croak "invalid userid" unless int($uid) > 0; - if ($num) { - croak "invalid number" unless $num =~ /^\+\d+$/; - croak "invalid verified flag" unless $verified =~ /^[YN]$/; - } - - my $dbh = LJ::get_db_writer(); - - # need to get currently mapped number so we can invalidate the reverse number lookup cache - my $num_row = $LJ::SMS::REQ_CACHE_MAP_UID{$uid}; - my $old_num = $num_row ? $num_row->{number} : undef; - delete $LJ::SMS::REQ_CACHE_MAP_NUM{$old_num} if $old_num; - - # invalidate user -> num cache - delete $LJ::SMS::REQ_CACHE_MAP_UID{$uid}; - - if ($num) { - $dbh->do("REPLACE INTO smsusermap SET number=?, userid=?, verified=?, instime=UNIX_TIMESTAMP()", - undef, $num, $uid, $verified); - - die $dbh->errstr if $dbh->err; - - # now update request cache with definitive data from global master - LJ::SMS->load_mapping(uid => $uid, force_master => 1); - - } else { - return $dbh->do("DELETE FROM smsusermap WHERE userid=?", undef, $uid); - } -} - -# get the userid of a given number from smsusermap -sub num_to_uid { - my $class = shift; - my $num = shift; - my %opts = @_; - my $verified_only = delete $opts{verified_only}; - $verified_only = defined $verified_only ? $verified_only : 1; - - my $row = LJ::SMS->load_mapping( num => $num, %opts ); - - if ($verified_only) { - return $row->{verified} eq 'Y' ? $row->{userid} : undef; - } - - return $row->{userid}; -} - -sub uid_to_num { - my $class = shift; - my $uid = LJ::want_userid(shift); - my %opts = @_; - my $verified_only = delete $opts{verified_only}; - $verified_only = defined $verified_only ? $verified_only : 1; - - my $row = LJ::SMS->load_mapping( uid => $uid, %opts ); - - if ($verified_only) { - return $row->{verified} eq 'Y' ? $row->{number} : undef; - } - - return $row->{number}; -} - -sub sent_message_count { - my $class = shift; - my $u = shift; - croak "invalid user object for message count" - unless LJ::isu($u); - - my %opts = @_; - - return $class->message_count($u, status => 'success', type => 'outgoing', %opts); -} - -sub message_count { - my $class = shift; - my $u = shift; - croak "invalid user object for message count" - unless LJ::isu($u); - - my %opts = @_; - - my $status = delete $opts{status}; - croak "invalid status: $status" - if $status && $status !~ /^(success|error|unknown)$/; - - my $type = delete $opts{type}; - croak "invalid message type: $type" - if $type && $type !~ /^(incoming|outgoing|unknown)$/; - - my $class_key = delete $opts{class_key}; - my $class_key_like = delete $opts{class_key_like}; - my $max_age = delete $opts{max_age}; - - croak "must pass class_key OR class_key_like" if ($class_key || $class_key_like) && - ! ($class_key xor $class_key_like); - - croak "invalid parameters: " . join(",", keys %opts) - if %opts; - - my @where_sql = (); - my @where_vals = (); - if ($status) { - push @where_sql, "status=?"; - push @where_vals, $status; - } - if ($type) { - push @where_sql, "type=?"; - push @where_vals, $type; - } - if ($class_key) { - push @where_sql, "class_key=?"; - push @where_vals, $class_key; - } - if ($class_key_like) { - $class_key_like = $u->quote($class_key_like); - push @where_sql, "class_key LIKE $class_key_like"; - } - if ($max_age) { - my $q_max_age = int($max_age); - my $timestamp = $LJ::_T_SMS_NOTIF_LIMIT_TIME_OVERRIDE ? time() : 'UNIX_TIMESTAMP()'; - push @where_sql, "timecreate>($timestamp-$q_max_age)"; - # don't push @where_vals - } - my $where_sql = @where_sql ? " AND " . join(" AND ", @where_sql) : ""; - - my ($ct) = $u->selectrow_array - ("SELECT COUNT(*) FROM sms_msg WHERE userid=?$where_sql", - undef, $u->id, @where_vals); - die $u->errstr if $u->err; - - return $ct+0; -} - -# given a number of $u object, returns whether there is a verified mapping -sub num_is_verified { - my $class = shift; - my $num = shift; - - # load smsusermap row via API, then see if the number was verified - my $row = LJ::SMS->load_mapping(num => $num); - - return 1 if $row && $row->{verified} eq 'Y'; - return 0; -} - -sub num_is_pending { - my $class = shift; - my $num = shift; - return LJ::SMS->num_is_verified($num) ? 0 : 1; -} - -# get the time a number was inserted -sub num_instime { - my $class = shift; - my $num = shift; - - # load smsusermap row via API, then see if the number was verified - my $row = LJ::SMS->load_mapping(num => $num); - - # select the most recently inserted time - return $row->{instime}; -} - -# return how much time a user has left to register their number -# returns false if no time left -sub num_register_time_remaining { - my $class = shift; - my $u = shift; - - return 1 unless $LJ::SMS_REGISTER_TIME_LIMIT; - - my $instime = $u->sms_num_instime; - my $register_time = $LJ::SMS_REGISTER_TIME_LIMIT; - if ($instime && $instime + $register_time > time()) { - return ($instime + $register_time) - time(); - } - - return 0; -} - -sub set_number_verified { - my ($class, $uid, $verified) = @_; - - $uid = LJ::want_userid($uid); - $verified = uc($verified); - croak "invalid userid" unless int($uid) > 0; - croak "invalid verified flag" unless $verified =~ /^[YN]$/; - - # need to find their currently mapped number to replace - # mapping given only $uid - my $num = LJ::SMS->uid_to_num($uid, verified_only => 0, force_master => 1); - die "no currently mapped number" unless $num; - - # replace mapping using API which will do proper caching/invalidation/etc - return $class->replace_mapping($uid, $num, $verified); -} - -# enqueue an incoming SMS for processing -sub enqueue_as_incoming { - my $class = shift; - croak "enqueue_as_incoming is a class method" - unless $class eq __PACKAGE__; - - my $msg = shift; - die "invalid msg argument" - unless $msg && $msg->isa("LJ::SMS::Message"); - - return unless $msg->should_enqueue; - - my $sclient = LJ::theschwartz(); - die "Unable to contact TheSchwartz!" - unless $sclient; - - my $shandle = $sclient->insert("LJ::Worker::IncomingSMS", $msg); - return $shandle ? 1 : 0; -} - -# can this user use SMS? -# -- $u can be undef, passed opaquely to coderef if sms_ui is coderef -sub can_use_sms { - my ($class, $u) = @_; - return 0 unless LJ::is_enabled('sms'); - return LJ::is_enabled('sms_ui', $u); -} - -# is sms sending configured? -sub configured { - my $class = shift; - - return %LJ::SMS_GATEWAY_CONFIG && LJ::sms_gateway() ? 1 : 0; -} - -sub configured_for_user { - my $class = shift; - my $u = shift; - - # active if the user has a verified sms number - return $u->sms_active_number ? 1 : 0; -} - -sub pending_for_user { - my $class = shift; - my $u = shift; - - # pending if the user has a number but it is unverified - return $u->sms_pending_number ? 1 : 0; -} - -sub sms_quota_remaining { - my ($class, $u, $type) = @_; - - return LJ::run_hook("sms_quota_remaining", $u, $type) || 0; -} - -sub add_sms_quota { - my ($class, $u, $qty, $type) = @_; - - return LJ::run_hook("modify_sms_quota", $u, delta => $qty, type => $type); -} - -sub max_sms_bytes { - my ($class, $u) = @_; - - # for now the max length for all users is 160, but - # in the future we'll need to modify this to look - # at their carrier cap and return a max from there - return '160'; -} - -sub max_sms_substr { - my $class = shift; - my ($u, $text, %opts) = @_; - - my $suffix = delete $opts{suffix} || ""; - my $maxlen = delete $opts{maxlen} || undef; - croak "invalid parameters to max_sms_substr: " . join(",", keys %opts) - if %opts; - - $maxlen ||= $u->max_sms_bytes; - - my $gw = LJ::sms_gateway() - or die "unable to load SMS gateway object"; - - # use bytes in here for length/etc - use bytes; - - # greedily find the largest bit of text that doesn't - # violate the final byte length of $maxlen, stopping - # when $maxlen == 2 and --$maxlen == 1 is tried as - # a length - my $currlen = $maxlen; - while ($currlen > 1 && $gw->final_byte_length($text . $suffix) > $maxlen) { - $text = LJ::text_trim($text, --$currlen); - } - - return $text . $suffix; -} - -sub can_append { - my $class = shift; - my ($u, $curr, $append) = @_; - croak "invalid user object" unless LJ::isu($u); - - my $maxlen = $u->max_sms_bytes; - - my $gw = LJ::sms_gateway() - or die "unable to load SMS gateway object"; - - return $gw->final_byte_length($curr . $append) <= $maxlen; -} - -sub subtract_sms_quota { - my ($class, $u, $qty, $type) = @_; - - return LJ::run_hook("modify_sms_quota", $u, delta => -$qty, type => $type); -} - -sub set_sms_quota { - my ($class, $u, $qty, $type) = @_; - - return LJ::run_hook("modify_sms_quota", $u, amount => $qty, type => $type); -} - -# Handle a request from a phone number that is not mapped ot a user -# Only respond to HELP requests, send an SMS with instructions -sub handle_unmapped { - my ($class, $dsms_msg) = @_; - - # shared test gateway requires prefix of "lj " before - # any message to ensure it is delivered to us - my $body_text = $dsms_msg->body_text || ''; - $body_text =~ s/^lj\s+//i if $LJ::IS_DEV_SERVER; - - # if it is a HELP request - if ($body_text =~ /^\s*help/i) { - my $help_text = "To use $LJ::SMS_TITLE go to $LJ::SITEROOT/sms/. For help contact support\@livejournal.com or 415-294-5054. Std msg chrgs apply. To cancel reply STOP."; - my $gw = LJ::sms_gateway() - or die "unable to instantiate SMS gateway object"; - - my $dmsg = DSMS::Message->new - ( - to => LJ::SMS::Message->normalize_num($dsms_msg->from), - from => LJ::SMS::Message->normalize_num($dsms_msg->to), - type => "outgoing", - body_text => $help_text, - ) or die "unable to construct DSMS::Message to send"; - $gw->send_msg($dmsg); - return 1; - } - - return 0; -} - -# Schwartz worker for responding to incoming SMS messages -package LJ::Worker::IncomingSMS; -use base 'TheSchwartz::Worker'; - -use Class::Autouse qw(LJ::SMS::MessageHandler); - -sub work { - my ($class, $job) = @_; - - my $msg = $job->arg; - - unless ($msg) { - $job->failed; - return; - } - - LJ::SMS::MessageHandler->handle($msg); - - return $job->completed; -} - -sub keep_exit_status_for { 0 } -sub grab_for { 300 } -sub max_retries { 5 } -sub retry_delay { - my ($class, $fails) = @_; - return (10, 30, 60, 300, 600)[$fails]; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/Message.pm --- a/cgi-bin/LJ/SMS/Message.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,940 +0,0 @@ -package LJ::SMS::Message; - -use strict; -use Carp qw(croak); - -use Class::Autouse qw( - IO::Socket::INET - LJ::Typemap - DSMS::Message - DateTime - LJ::SMS::MessageAck - ); - -# LJ::SMS::Message object -# -# internal fields: -# -# FIXME: optional msgid arg if in db? -# -# owner_uid: userid of the 'owner' of this SMS -# -- the user object who is sending -# or receiving this message -# from_uid: userid of the sender -# from_num: phone number of sender -# to_uid: userid of the recipient -# to_num: phone number of recipient -# msgid: optional message id if saved to DB -# timecreate: timestamp when message was created -# class_key: key identifier for the type of this message -# type: 'incoming' or 'outgoing' from LJ's perspective -# status: 'success', 'error', or 'unknown' depending on msg status -# error: error string associated with this message, if any -# body_text: decoded text body of message -# body_raw: raw text body of message -# meta: hashref of metadata key/value pairs -# acks: array of SMS::MessageAck objects loaded from DB -# -- note that these are read-only -# -# synopsis: -# -# my $sms = LJ::SMS->new(owner => $owneru, -# class_key => 'msg-type-123', -# type => 'outgoing', -# status => 'unknown', -# from => $num_or_u, -# to => $num_or_u, -# body_text => $utf8_text, -# meta => { k => $v }, -# ); -# -# my $sms = LJ::SMS->new_from_dsms($dsms_msg); -# -# accessors: -# -# $msg->owner_u; -# $msg->to_num; -# $msg->from_num; -# $msg->to_u; -# $msg->from_u; -# $msg->class_key; -# $msg->type; -# $msg->status; -# $msg->error; -# $msg->msgid; -# $msg->body_text; -# $msg->raw_text; -# $msg->timecreate; -# $msg->meta; -# $msg->meta($k); -# $msg->gateway_obj; -# $msg->acks; -# -# FIXME: singletons + lazy loading for queries -# - -sub new { - my ($class, %opts) = @_; - croak "new is a class method" - unless $class eq __PACKAGE__; - - my $self = bless {}, $class; - - # from/to can each be passed as either number or $u object - # in any case $self will end up with the _num and _uid fields - # specified for each valid from/to arg - foreach my $k (qw(from to)) { - my $val = delete $opts{$k}; - next unless $val; - - # extract fields from $u object - if (LJ::isu($val)) { - my $u = $val; - $self->{"${k}_uid"} = $u->{userid}; - $self->{"${k}_num"} = $u->sms_mapped_number - or croak "'$k' user has no mapped number"; - next; - } - - # normalize the number before validating... - $val = $self->normalize_num($val); - - if ($val =~ /^\+?\d+$/) { - # right now, we're trying to verify what a user has sent to us, - # and if they haven't been verified yet then we need to send - # verified_only = 0 until we mark them as verified. - $self->{"${k}_uid"} = LJ::SMS->num_to_uid($val, verified_only => 0); - $self->{"${k}_num"} = $val; - next; - } - - croak "invalid numeric argument '$k': $val"; - } - - # type: incoming/outgoing. attempt to infer if none is specified - $self->{type} = lc(delete $opts{type}); - unless ($self->{type}) { - if ($self->{from_uid} && $self->{to_uid}) { - croak "cannot send user-to-user messages"; - } elsif ($self->{from_uid}) { - $self->{type} = 'incoming'; - } elsif ($self->{to_uid}) { - $self->{type} = 'outgoing'; - } - } - - # allow class_key to be set - $self->{class_key} = delete $opts{class_key} || 'unknown'; - - # now validate an explict or inferred type - croak "type must be one of 'incoming' or 'outgoing', from the server's perspective" - unless $self->{type} =~ /^(?:incoming|outgoing)$/; - - # from there, fill in the from/to num defaulted to $LJ::SMS_SHORTCODE - if ($self->{type} eq 'outgoing') { - croak "need valid 'to' argument to construct outgoing message" - unless $self->{"to_num"}; - $self->{from_num} ||= $LJ::SMS_SHORTCODE; - } else { - croak "need valid 'from' argument to construct incoming message" - unless $self->{"from_num"}; - $self->{to_num} ||= $LJ::SMS_SHORTCODE; - } - - { # owner argument - my $owner_arg = delete $opts{owner}; - croak "owner argument must be a valid user object" - unless LJ::isu($owner_arg); - - $self->{owner_uid} = $owner_arg->{userid}; - } - - # omg we need text eh? - $self->{body_text} = delete $opts{body_text}; - $self->{body_raw} = exists $opts{body_raw} ? delete $opts{body_raw} : $self->{body_text}; - - { # any metadata the user would like to pass through - $self->{meta} = delete $opts{meta}; - croak "invalid 'meta' argument" - if $self->{meta} && ref $self->{meta} ne 'HASH'; - - $self->{meta} ||= {}; - } - - { # any message acks received for this message - $self->{acks} = delete $opts{acks} || []; - unless (ref $self->{acks} eq 'ARRAY' && - ! grep { ! ref $_ && ! $_->isa("LJ::SMS::MessageAck") } @{$self->{acks}}) - { - croak "invalid 'acks' argument"; - } - } - - # set timecreate stamp for this object - $self->{timecreate} = delete $opts{timecreate} || time(); - croak "invalid 'timecreate' parameter: $self->{timecreate}" - unless int($self->{timecreate}) > 0; - - # by default set status to 'unknown' - $self->{status} = lc(delete $opts{status}) || 'unknown'; - croak "invalid msg status: $self->{status}" - unless $self->{status} =~ /^(?:success|ack_wait|error|unknown)$/; - - # set msgid if a non-zero one was specified - $self->{msgid} = delete $opts{msgid}; - croak "invalid msgid: $self->{msgid}" - if $self->{msgid} && int($self->{msgid}) <= 0; - - # probably no error string specified here - $self->{error} = delete $opts{error} || undef; - - # able to pass in a gateway object, but default works too - $self->{gateway} = delete $opts{gateway} || LJ::sms_gateway(); - croak "invalid gateway object: $self->{gateway}" - unless $self->{gateway} && $self->{gateway}->isa("DSMS::Gateway"); - - die "invalid arguments: " . join(", ", keys %opts) - if %opts; - - return $self; -} - -sub new_from_dsms { - my ($class, $dsms_msg) = @_; - croak "new_from_dsms is a class method" - unless $class eq __PACKAGE__; - - croak "invalid dsms_msg argument: $dsms_msg" - unless ref $dsms_msg eq 'DSMS::Message'; - - my $owneru = undef; - { - my $owner_num = $dsms_msg->is_incoming ? - $dsms_msg->from : $dsms_msg->to; - - $owner_num = $class->normalize_num($owner_num); - - my $uid = LJ::SMS->num_to_uid($owner_num, verified_only => 0); - unless ($uid) { - return 0 if (LJ::SMS->handle_unmapped($dsms_msg)); - croak "invalid owner id from number: $owner_num"; - } - - $owneru = LJ::load_userid($uid); - croak "invalid owner u from number: $owner_num" - unless LJ::isu($owneru); - } - - # LJ needs utf8 flag off for all fields, we'll do that - # here now that we're officially in LJ land. - $dsms_msg->encode_utf8; - - # construct a new LJ::SMS::Message object - my $msg = $class->new - ( owner => $owneru, - from => $class->normalize_num($dsms_msg->from), - to => $class->normalize_num($dsms_msg->to), - type => $dsms_msg->type, - body_text => $dsms_msg->body_text, - body_raw => $dsms_msg->body_raw, - meta => $dsms_msg->meta, - ); - - # class_key is still unknown here, to be set later - - return $msg; -} - -sub load { - my $class = shift; - croak "load is a class method" - unless $class eq __PACKAGE__; - - my $owner_u = shift; - croak "invalid owner_u: $owner_u" - unless LJ::isu($owner_u); - - my $uid = $owner_u->{userid}; - my @msgids = (); - my $msg_rows = {}; - my $bind = ""; - - # remaining args can be key/value pairs of options, or a list of msgids - if ($_[0] =~ /\D/) { - my %opts = @_; - - # loading msgids by month and year - if (exists $opts{month} || exists $opts{year}) { - my $month = delete $opts{month}; - croak "invalid month: $month" - unless $month =~ /^\d\d?$/ && $month > 0 && $month <= 12; - - my $year = delete $opts{year}; - croak "invalid year: $year" - unless $year =~ /^\d{4}$/; - - croak "invalid options for year/month load: " . join(",", keys %opts) if %opts; - - my $dt = DateTime->new(year => $year, month => $month); - my $start_time = $dt->epoch; - my $end_time = $dt->add(months => 1)->epoch; - - $msg_rows = $owner_u->selectall_hashref - ("SELECT msgid, class_key, type, status, to_number, from_number, timecreate " . - "FROM sms_msg WHERE userid=? AND timecreate>=? AND timecreate<?", - 'msgid', undef, $uid, $start_time, $end_time) || {}; - die $owner_u->errstr if $owner_u->err; - - # not sure what args they're giving - } else { - croak "invalid parameters: " . join(",", keys %opts) - if %opts; - } - - # which messageids matched the above constraint? - @msgids = sort {$a <=> $b} keys %$msg_rows; - - } else { - @msgids = @_; - croak "invalid msgid: $_" - if grep { ! $_ || int($_) <= 0 } @msgids; - - $bind = join(",", map { "?" } @msgids); - $msg_rows = $owner_u->selectall_hashref - ("SELECT msgid, class_key, type, status, to_number, from_number, timecreate " . - "FROM sms_msg WHERE userid=? AND msgid IN ($bind)", - 'msgid', undef, $uid, @msgids) || {}; - die $owner_u->errstr if $owner_u->err; - - @msgids = grep { exists $msg_rows->{$_} } @msgids; - } - - return wantarray ? () : undef unless scalar @msgids; - - # now update $bind to be consistent with the @msgids value found above - $bind = join(",", map { "?" } @msgids); - - my $text_rows = $owner_u->selectall_hashref - ("SELECT msgid, msg_raw, msg_decoded FROM sms_msgtext WHERE userid=? AND msgid IN ($bind)", - 'msgid', undef, $uid, @msgids) || {}; - die $owner_u->errstr if $owner_u->err; - - my $error_rows = $owner_u->selectall_hashref - ("SELECT msgid, error FROM sms_msgerror WHERE userid=? AND msgid IN ($bind)", - 'msgid', undef, $uid, @msgids) || {}; - die $owner_u->errstr if $owner_u->err; - - my $tm = $class->typemap; - - my $prop_rows = {}; - my $sth = $owner_u->prepare - ("SELECT msgid, propid, propval FROM sms_msgprop WHERE userid=? AND msgid IN ($bind)"); - $sth->execute($uid, @msgids); - while (my ($msgid, $propid, $propval) = $sth->fetchrow_array) { - my $propname = $tm->typeid_to_class($propid) - or die "no propname for propid: $propid"; - - $prop_rows->{$msgid}->{$propname} = $propval; - } - - # load message acks for all messages - my @acks = LJ::SMS::MessageAck->load($owner_u, @msgids); - my %acks_by_msgid = (); - foreach my $ack (@acks) { - push @{$acks_by_msgid{$ack->msgid}}, $ack; - } - - my @ret_msgs = (); - foreach my $msgid (@msgids) { - my $msg_row = $msg_rows->{$msgid}; - my $text_row = $text_rows->{$msgid}; - my $error_row = $error_rows->{$msgid}; - my $props = $prop_rows->{$msgid}; - - push @ret_msgs, $class->new - ( owner => $owner_u, - msgid => $msgid, - error => $error_row->{error}, - meta => $props, - acks => $acks_by_msgid{$msgid}, - from => $msg_row->{from_number}, - to => $msg_row->{to_number}, - class_key => $msg_row->{class_key}, - type => $msg_row->{type}, - status => $msg_row->{status}, - timecreate => $msg_row->{timecreate}, - body_text => $text_row->{msg_decoded}, - body_raw => $text_row->{msg_raw}, - ); - } - - return wantarray() ? @ret_msgs : $ret_msgs[0]; -} - -sub load_by_uniq { - my $class = shift; - croak "load is a class method" - unless $class eq __PACKAGE__; - - my $msg_uniq = shift; - croak "invalid msg_uniq: must not be empty" - unless length $msg_uniq; - - my $dbh = LJ::get_db_writer() - or die "unable to contact global db master"; - - my ($userid, $msgid) = $dbh->selectrow_array - ("SELECT userid, msgid FROM smsuniqmap WHERE msg_uniq=?", - undef, $msg_uniq); - die $dbh->errstr if $dbh->err; - - my $owner_u = LJ::load_userid($userid) - or die "invalid owner for uniq: $msg_uniq"; - - return $class->load($owner_u, $msgid); -} - -sub register_uniq { - my $self = shift; - my $msg_uniq = shift; - - my $dbh = LJ::get_db_writer() - or die "unable to contact global db master"; - - my $owner_u = $self->owner_u; - - my $rv = $dbh->do("REPLACE INTO smsuniqmap SET msg_uniq=?, userid=?, msgid=?", - undef, $msg_uniq, $owner_u->id, $self->msgid); - die $dbh->errstr if $dbh->err; - - return $rv; -} - -sub recv_ack { - my $self = shift; - my $ack = shift; - my $meta = shift; - croak "invalid ack for recv_ack: $ack" - unless $ack && $ack->isa("LJ::SMS::MessageAck"); - croak "invalid meta arg: $meta" - if $meta && ref $meta ne 'HASH'; - - # warn if we receive an ack for a message which is no longer awaiting acks - unless ($self->is_awaiting_ack) { - my $userid = $self->owner_u->id; - my $msgid = $self->msgid; - warn "message not awaiting ack: uid=$userid, msgid=$msgid"; - } - - # save this ack to the db if it hasn't been done already - $ack->save_to_db; - - # take metadata from DSMS ack and append it to the message's 'meta' fieldset - if ($meta) { - my %to_append = (); - while (my ($k, $v) = each %{$meta||{}}) { - next unless $v; - $to_append{uc(join("_", "ACK", $ack->type, $k))} = $v; - } - - $self->meta(%to_append); - } - - # gateway ack's don't indicate final success, - # return early unless the ack is from the smsc - return 1 unless $ack->type eq 'smsc'; - - # our status flag is now that of the ack which was - # received: success, error, unknown - if ($ack->status_flag eq 'error') { - $self->status('error' => $ack->status_text); - } else { - $self->status($ack->status_flag); - } - - return LJ::run_hook("sms_recv_ack", $self, $ack); - - return 1; -} - -sub gateway { - my $self = shift; - - if (@_) { - my $gw = shift; - croak "invalid gateway param" - unless $gw; - - # setting a gateway object - if (ref $gw) { - croak "invalid gateway object: $gw" - unless $gw->isa("DSMS::Gateway"); - - return $self->{gateway} = $gw; - - # setting a new object via gw key - } else { - return $self->{gateway} = LJ::sms_gateway($gw); - } - } - - return $self->{gateway}; -} - -sub typemap { - my $class = shift; - - return LJ::Typemap->new - ( table => 'sms_msgproplist', - classfield => 'name', - idfield => 'propid', - ); -} - -sub normalize_num { - my $class = shift; - my $arg = shift; - $arg = ref $arg ? $arg->[0] : $arg; - - # add +1 if it's a US number - $arg = "+1$arg" if $arg =~ /^\d{10}$/; - - return $arg; -} - -sub meta { - my $self = shift; - my $key = shift; - my $val = shift; - - my $meta = $self->{meta} || {}; - - # if a value was specified for a set, handle that here - if ($key && $val) { - - my %to_set = ($key => $val, @_); - - # if saved to the db, go ahead and write out now - if ($self->msgid) { - - my $tm = $self->typemap; - my $u = $self->owner_u; - my $uid = $u->id; - my $msgid = $self->id; - - my @vals = (); - while (my ($k, $v) = each %to_set) { - next if $v eq $meta->{$k}; - - my $propid = $tm->class_to_typeid($k); - push @vals, ($uid, $msgid, $propid, $v); - } - - if (@vals) { - my $bind = join(",", map { "(?,?,?,?)" } (1..@vals/4)); - - $u->do("REPLACE INTO sms_msgprop (userid, msgid, propid, propval) VALUES $bind", - undef, @vals); - die $u->errstr if $u->err; - } - } - - # update elements in memory - while (my ($k, $v) = each %to_set) { - $meta->{$k} = $v; - } - - # return new set value of the first element passed - return $meta->{$key}; - } - - # if a specific key was specified, return that element - # ... otherwise return a hashref of all k/v pairs - return $key ? $meta->{$key} : $meta; -} - -sub owner_u { - my $self = shift; - - # load user obj if valid uid and return - my $uid = $self->{owner_uid}; - return $uid ? LJ::load_userid($uid) : undef; -} - -sub to_num { - my $self = shift; - return $self->{to_num}; -} - -sub to_u { - my $self = shift; - - # load userid from db unless the cache key exists - $self->{to_uid} = LJ::SMS->num_to_uid($self->{to_num}, verified_only => 0) - unless exists $self->{to_uid}; - - # load user obj if valid uid and return - my $uid = $self->{to_uid}; - return $uid ? LJ::load_userid($uid) : undef; -} - -sub from_num { - my $self = shift; - return $self->{from_num}; -} - -sub from_u { - my $self = shift; - - # load userid from db unless the cache key exists - $self->{_from_uid} = LJ::SMS->num_to_uid($self->{from_num}, verified_only => 0) - unless exists $self->{_from_uid}; - - # load user obj if valid uid and return - my $uid = $self->{_from_uid}; - return $uid ? LJ::load_userid($uid) : undef; -} - -sub class_key { - my $self = shift; - - if (@_) { - my $val = shift; - croak "invalid value for 'class_key': $val" - unless length $val; - - if ($self->msgid && $val ne $self->{class_key}) { - my $owner_u = $self->owner_u; - $owner_u->do("UPDATE sms_msg SET class_key=? WHERE userid=? AND msgid=?", - undef, $val, $owner_u->{userid}, $self->msgid); - die $owner_u->errstr if $owner_u->err; - } - - return $self->{class_key} = $val; - } - - return $self->{class_key}; -} - -sub type { - my $self = shift; - - if (@_) { - my $val = shift; - croak "invalid value for 'status': $val" - unless $val =~ /^(?:incoming|outgoing)$/; - - if ($self->msgid && $val ne $self->{type}) { - my $owner_u = $self->owner_u; - $owner_u->do("UPDATE sms_msg SET type=? WHERE userid=? AND msgid=?", - undef, $val, $owner_u->{userid}, $self->msgid); - die $owner_u->errstr if $owner_u->err; - } - - return $self->{type} = $val; - } - - return $self->{type}; -} - -sub timecreate { - my $self = shift; - return $self->{timecreate}; -} - -sub msgid { - my $self = shift; - return $self->{msgid}; -} -*id = \&msgid; - -sub status { - my $self = shift; - - if (@_) { - my $val = shift; - croak "invalid value for 'status': $val" - unless $val =~ /^(?:success|ack_wait|error|unknown)$/; - - if ($self->msgid && $val ne $self->{status}) { - my $owner_u = $self->owner_u; - $owner_u->do("UPDATE sms_msg SET status=? WHERE userid=? AND msgid=?", - undef, $val, $owner_u->{userid}, $self->msgid); - die $owner_u->errstr if $owner_u->err; - } - - # third argument to call as $self->('error' => $err_str); - if (@_ && $val eq 'error') { - my $val_arg = shift; - $self->error($val_arg); - } - - return $self->{status} = $val; - } - - return $self->{status}; -} - -sub error { - my $self = shift; - - if (@_) { - my $errstr = shift; - - # changing an errstr on an object that lives in the db? - if ($self->msgid && $errstr ne $self->{error}) { - my $owner_u = $self->owner_u; - $owner_u->do("REPLACE INTO sms_msgerror SET userid=?, msgid=?, error=?", - undef, $owner_u->{userid}, $self->msgid, $errstr); - die $owner_u->errstr if $owner_u->err; - } - - return $self->{error} = $errstr; - } - - return $self->{error}; -} - -sub is_success { - my $self = shift; - return $self->status eq 'success' ? 1 : 0; -} - -sub is_error { - my $self = shift; - return $self->status eq 'error' ? 1 : 0; -} - -sub is_awaiting_ack { - my $self = shift; - return $self->status eq 'ack_wait' ? 1 : 0; -} - -sub body_text { - my $self = shift; - - return $self->{body_text} unless $LJ::IS_DEV_SERVER; - - # shared test gateway requires prefix of "lj " before - # any message to ensure it is delivered to us - my $body_text = $self->{body_text} || ''; - $body_text =~ s/^lj\s+//i; - return $body_text; -} - -sub body_raw { - my $self = shift; - return $self->{body_raw}; -} - -sub save_to_db { - my $self = shift; - - # do nothing if already saved to db - return 1 if $self->{msgid}; - - my $u = $self->owner_u - or die "no owner object found"; - my $uid = $u->{userid}; - - # allocate a user counter id for this messaGe - my $msgid = LJ::alloc_user_counter($u, "G") - or die "Unable to allocate msgid for user: " . $self->owner_u->{user}; - - # insert main sms_msg row - my $timestamp = $LJ::_T_SMS_NOTIF_LIMIT_TIME_OVERRIDE ? time() : 'UNIX_TIMESTAMP()'; - $u->do("INSERT INTO sms_msg SET userid=?, msgid=?, class_key=?, type=?, " . - "status=?, to_number=?, from_number=?, timecreate=$timestamp", - undef, $uid, $msgid, $self->class_key, $self->type, $self->status, - $self->to_num, $self->from_num); - die $u->errstr if $u->err; - - # save blob parts to their table - $u->do("INSERT INTO sms_msgtext SET userid=?, msgid=?, msg_raw=?, msg_decoded=?", - undef, $uid, $msgid, $self->body_raw, $self->body_text); - die $u->errstr if $u->err; - - # save error string if any - if ($self->error) { - $u->do("INSERT INTO sms_msgerror SET userid=?, msgid=?, error=?", - undef, $u->{userid}, $msgid, $self->error); - die $u->errstr if $u->err; - } - - # save msgid into this object - $self->{msgid} = $msgid; - - # write props out to db... - $self->save_props_to_db; - - # acks are read-only, inserted elsewhere - - return 1; -} - -sub save_props_to_db { - my $self = shift; - - my $tm = $self->typemap; - - my $u = $self->owner_u; - my $uid = $u->id; - my $msgid = $self->id; - - my @vals = (); - while (my ($propname, $propval) = each %{$self->meta}) { - my $propid = $tm->class_to_typeid($propname); - push @vals => $uid, $msgid, $propid, $propval; - } - - if (@vals) { - my $bind = join(",", map { "(?,?,?,?)" } (1..@vals/4)); - - $u->do("REPLACE INTO sms_msgprop (userid, msgid, propid, propval) VALUES $bind", - undef, @vals); - die $u->errstr if $u->err; - } - - return 1; -} - -sub respond { - my $self = shift; - my $body_text = shift; - my %opts = @_; - - my $resp = LJ::SMS::Message->new - ( owner => $self->owner_u, - from => $self->to_num, - to => $self->from_num, - body_text => $body_text ); - - # set class key if one was specified via opts or - # one can be inferred via the message we're responding to - { - my $class_key = delete $opts{class_key}; - - # explicit class_key - my $explicit = 1 if $class_key; - - # fall back to other means - $class_key ||= - $self->class_key || # class_key set on $self - $self->meta('handler_type'); # handler_type meta set by incoming MessageHandler - - if ($class_key) { - if ($explicit) { - $resp->class_key($class_key); - } else { - # inferred class_key could have been "Request", we'll strip that and tack on "Response" - $class_key =~ s/\-Request$//i; - $resp->class_key($class_key . "-Response"); - } - } - } - - # send response message - $resp->send(%opts); - - return $resp; -} - -sub send { - my $self = shift; - my %opts = @_; - - my $err = sub { - my $errmsg = shift; - $self->status('error' => $errmsg); - $self->save_to_db; - return undef; - }; - - # is SMS disabled? - return $err->("SMS is disabled") unless LJ::is_enabled('sms'); - - # verify type of this message - $self->type('outgoing'); - - # need a destination $u in order to send a message - my $to_u = $self->to_u; - return $err->("no user to for message send") - unless $to_u; - - # do not send a message to a user with no quota remaining - return $err->("no quota remaining") - unless ! LJ::is_enabled('sms_quota_check') || $opts{no_quota} || $to_u->sms_quota_remaining || $LJ::_T_NO_SMS_QUOTA; - - # do not send message to this user unless they are confirmed and active - return $err->("sms not active for user: $to_u->{user}") - unless $opts{force} || $to_u->sms_active; - - if (my $cv = $LJ::_T_SMS_SEND) { - - # whenever a message is sent, we'll give an opportunity - # for local hooks to catch the event and act accordingly - LJ::run_hook('sms_deduct_quota', $self, %opts); - - # pretend this was successful. - $self->status('success'); - $self->save_to_db; - - return $cv->($self); - } - - # find where quota is being deducted from - my $quota_type = LJ::run_hook('sms_deduct_quota', $self, %opts); - - # set gateway if quota-type was returned, otherwise () to call as getter - my $gw = $self->gateway($quota_type || ()) - or die "unable to instantiate SMS gateway object"; - - my $dsms_msg = DSMS::Message->new - ( - to => $self->to_num, - from => $self->from_num, - type => "outgoing", - body_text => $self->body_text, - meta => $self->meta, - ) or die "unable to construct DSMS::Message to send"; - - my $rv = eval { - my @verify_delivery = $opts{verify_delivery} ? ( verify_delivery => 1 ) : (); - $gw->send_msg($dsms_msg, @verify_delivery); - }; - - # mark error status if there was a problem sending - if ($@) { - $self->status('error' => $@); - - # mark 'success' if status was previously 'unknown', but - # not if it was ack_wait, in which case we'll have to - # wait for a final ack from the gateway before setting - # the final message status - } elsif ($self->status eq 'unknown') { - $self->status('success'); - } - - # absorb metadata from DSMS message which is now sent - my $dsms_meta = $dsms_msg->meta || {}; - $self->meta(%$dsms_meta); - - # this message has been sent, log it to the db - $self->save_to_db; - - # message is created, register it in the global smsuniqmap table - if ($dsms_msg->uniq_key) { - $self->register_uniq($dsms_msg->uniq_key); - } - - return 1; -} - -sub should_enqueue { 1 } - -sub as_string { - my $self = shift; - return "from=$self->{from}, text=$self->{body_text}\n"; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageAck.pm --- a/cgi-bin/LJ/SMS/MessageAck.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,195 +0,0 @@ -#!/usr/bin/perl - -package LJ::SMS::MessageAck; - -use strict; -use Carp qw(croak); - -# LJ::SMS::MessageAck object -# -# internal fields: -# -# owner_uid userid to which this ack belongs -# msgid msgid to which this ack is a response -# type ack type: gateway, smsc, handset, unknown -# timerecv unixtime when ack was received -# status_flag status flag indicating message success -# status_code optional status code given for ack -# status_text full status string as received - -sub new { - my ($class, %opts) = @_; - croak "new is a class method" - unless $class eq __PACKAGE__; - - my $self = bless {}, $class; - - { # owner argument - my $owner_arg = delete $opts{owner}; - croak "owner argument must be a valid user object" - unless LJ::isu($owner_arg); - - $self->{owner_uid} = $owner_arg->id; - } - - # set msgid if a non-zero one was specified - $self->{msgid} = delete $opts{msgid}; - croak "invalid msgid: $self->{msgid}" - if $self->{msgid} && int($self->{msgid}) <= 0; - - # what type of ack is this? gateway? handset? - $self->{type} = delete $opts{type}; - croak "type must be one of 'gateway', 'smsc', 'handset', or 'unknown'" - unless $self->{type} =~ /^(?:gateway|smsc|handset|unknown)$/; - - # when was this message received? - $self->{timerecv} = delete $opts{timerecv} || time(); - croak "invalid timerecv: $self->{timerecv}" - if $self->{timerecv} && int($self->{timerecv}) <= 0; - - # what is the status indicated by this ack? - $self->{status_flag} = delete $opts{status_flag}; - croak "status_flag must be one of 'success', 'error', or 'unknown'" - unless $self->{status_flag} =~ /^(?:success|error|unknown)$/; - - # status code is opaque and optional - $self->{status_code} = delete $opts{status_code}; - croak "invalid status code: $self->{status_code}" - if $self->{status_code} && length $self->{status_code}; - - # what status text was given for this message? - $self->{status_text} = delete $opts{status_text}; - croak "invalid status text has no length" - unless length $self->{status_text}; - - croak "invalid parameters: " . join(",", keys %opts) - if %opts; - - return $self; -} - -sub new_from_dsms { - my ($class, $ack) = @_; - croak "new_from_dsms is a class method" - unless $class eq __PACKAGE__; - croak "invalid ack arg: $ack" - unless $ack && $ack->isa("DSMS::MessageAck"); - - # get msg_uniq from DSMS::MessageAck - my $msg_uniq = $ack->msg_uniq - or die "unable to construct LJ::SMS::MessageAck from missing msg_uniq"; - - my $msg = LJ::SMS::Message->load_by_uniq($msg_uniq) - or die "unable to load message by msg_uniq: $msg_uniq"; - - return $class->new - ( owner => $msg->owner_u, - msgid => $msg->msgid, - type => $ack->type, - timerecv => $ack->timestamp, - status_flag => $ack->status_flag, - status_code => $ack->status_code, - status_text => $ack->status_text, ); -} - -sub load { - my $class = shift; - croak "load is a class method" - unless $class eq __PACKAGE__; - - my $owner_u = shift; - croak "invalid owner_u: $owner_u" - unless LJ::isu($owner_u); - - my @msgids = @_; - foreach (@msgids) { - croak "invalid msgid: $_" - unless $_ && int($_) > 0; - } - - my @ret_acks = (); - - my $bind = join(",", map { "?" } @msgids); - my $sth = $owner_u->prepare - ("SELECT msgid, type, timerecv, status_flag, status_code, status_text " . - "FROM sms_msgack WHERE userid=? AND msgid IN ($bind)"); - $sth->execute($owner_u->id, @msgids); - - while (my $row = $sth->fetchrow_hashref) { - push @ret_acks, LJ::SMS::MessageAck->new - ( owner => $owner_u, - - map { $_ => $row->{$_} } - qw(msgid type timerecv status_flag status_code status_text) - ); - } - - return @ret_acks; -} - -sub save_to_db { - my $self = shift; - - # do nothing if already saved to db - return 1 if $self->{_saved_to_db}++; - - my $owner_u = $self->owner_u; - - my $rv = $owner_u->do - ("INSERT INTO sms_msgack SET userid=?, msgid=?, type=?, " . - "timerecv=?, status_flag=?, status_code=?, status_text=?", - undef, $owner_u->id, $self->msgid, $self->type, - $self->timerecv, $self->status_flag, $self->status_code, $self->status_text); - die $owner_u->errstr if $owner_u->err; - - return $rv; -} - -sub apply_to_msg { - my $self = shift; - my $msg = shift; - - # load message automatically unless a specific one - # is passed in by the caller - $msg ||= $self->msg; - die "no msg found for ack application" - unless $msg && $msg->isa("LJ::SMS::Message"); - - # update message status to reflect this ack's receipt - return $msg->recv_ack($self); -} - -sub owner_u { - my $self = shift; - - # load user obj if valid uid and return - my $uid = $self->{owner_uid}; - return $uid ? LJ::load_userid($uid) : undef; -} - -sub msg { - my $self = shift; - - return LJ::SMS::Message->load($self->owner_u, $self->msgid); -} - -sub _get { - my $self = shift; - my $field = shift; - croak "unknown field: $field" - unless exists $self->{$field}; - - return $self->{$field}; -} - -# FIXME: this needs to be done via the message perspective - -sub msgid { _get($_[0], 'msgid' ) } -sub type { _get($_[0], 'type' ) } -sub timerecv { _get($_[0], 'timerecv' ) } -sub status_flag { _get($_[0], 'status_flag') } -sub status_code { _get($_[0], 'status_code') } -sub status_text { _get($_[0], 'status_text') } -*id = \&msgid; - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler.pm --- a/cgi-bin/LJ/SMS/MessageHandler.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -package LJ::SMS::MessageHandler; - -# LJ::SMS::MessageHandler object -# - Base class for all LJ::SMS Message Handlers -# - -use strict; -use Carp qw(croak); - -use LJ::ModuleLoader; - -my @HANDLERS = LJ::ModuleLoader->module_subclasses("LJ::SMS::MessageHandler"); -foreach my $handler (@HANDLERS) { - eval "use $handler"; - die "Error loading MessageHandler '$handler': $@" if $@; -} - -sub handle { - my ($class, $msg) = @_; - croak "msg argument must be a valid LJ::SMS::Message object" - unless $msg && $msg->isa("LJ::SMS::Message"); - - # this is the master switch, not a code ref... if it's set we - # won't even attempt to save/process SMS messages - die "SMS globally disabled\n" unless LJ::is_enabled('sms'); - - # save msg to the db - $msg->save_to_db - or die "unable to save message to db"; - - my $handler; - foreach my $class (@HANDLERS) { - $handler = $class if $class->owns($msg); - } - - # default to posting, if no handlers own this message - $handler ||= "LJ::SMS::MessageHandler::Post"; - - # note the handler type for this message - my $htype = (split('::', $handler))[-1]; - $msg->meta(handler_type => $htype); - - # also store as the message's class_type - $msg->class_key("${htype}-Request"); - - # get the user that this message is destined for - my $u = $msg->from_u; - unless ($u) { - $msg->status('error' => "No destination user"); - return 1; - } - - # don't handle the message if the user is unverified - # UNLESS the handler accepts unverified users - if ($u->sms_pending_number) { - # user is awaiting verification. - unless ($handler->unverified_user_ok($u)) { - $msg->status('error' => "Message from unverified user"); - return 1; - } - } - - # handle the message - if ($u->is_visible) { - eval { $handler->handle($msg) }; - if ($@) { - $msg->status('error' => $@); - warn "Error handling message with handler $handler: $@" if $LJ::IS_DEV_SERVER; - } - } else { - # suspended account - $msg->status('error' => "Incoming SMS from inactive user"); - } - - # message handler should update the status to one - # of 'success' or 'error' ... - croak "after handling, msg status: " . $msg->status . ", should be set?" - if ! $msg->status || $msg->status eq 'unknown'; - - return 1; -} - -sub owns { - my ($class, $msg) = @_; - - warn "STUB: LJ::SMS::MessageHandler->owns"; - return 0; -} - -# does this handler accept messages from unverified users? -sub unverified_user_ok { - my ($class, $u) = @_; - - return 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler/Add.pm --- a/cgi-bin/LJ/SMS/MessageHandler/Add.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -package LJ::SMS::MessageHandler::Add; - -use base qw(LJ::SMS::MessageHandler); - -use strict; -use Carp qw(croak); - -sub handle { - my ($class, $msg) = @_; - - my $u = $msg->from_u - or die "no from_u for Add message"; - - my ($fgroup, $text) = $msg->body_text - =~ /^\s*a(?:dd)?(?:\.(\w+))?\s+(\S+)\s*/i; - - my $fr_user = LJ::canonical_username($text) - or die "Invalid format for username: $text"; - - my $fr_u = LJ::load_user($fr_user) - or die "Invalid user: $fr_user"; - - my $groupmask = 1; - - if ($fgroup) { - my $group = LJ::get_friend_group($u->id, { name => $fgroup }) - or die "Invalid friend group: $fgroup"; - - my $grp = $group ? $group->{groupnum}+0 : 0; - $groupmask |= (1 << $grp) if $grp; - } - - my $err; - unless ($u->is_friend($fr_u) || $u->can_add_friends(\$err, {friend => $fr_u})) { - die "Unable to add friend: $err"; - } - - $u->add_friend($fr_u, { groupmask => $groupmask }) - or die "Unable to add friend for 'Add' request"; - - # mark the requesting (source) message as processed - # -- we'd die before now if there was an error - $msg->status('success'); -} - -sub owns { - my ($class, $msg) = @_; - croak "invalid message passed to MessageHandler" - unless $msg && $msg->isa("LJ::SMS::Message"); - - return $msg->body_text =~ /^\s*a(?:dd)?(\.(\w+))?\s+\S+\s*$/i ? 1 : 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler/Echo.pm --- a/cgi-bin/LJ/SMS/MessageHandler/Echo.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -package LJ::SMS::MessageHandler::Echo; - -use base qw(LJ::SMS::MessageHandler); - -use strict; -use Carp qw(croak); - -sub handle { - my ($class, $msg) = @_; - - my $echo_text = $msg->body_text; - $echo_text =~ s/^\s*echo\s+//i; - my $resp = eval { $msg->respond($echo_text) }; - - # mark the requesting (source) message as processed - $msg->status($@ ? ('error' => $@) : 'success'); -} - -sub owns { - my ($class, $msg) = @_; - croak "invalid message passed to MessageHandler" - unless $msg && $msg->isa("LJ::SMS::Message"); - - return $msg->body_text =~ /^\s*echo/i ? 1 : 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler/Friends.pm --- a/cgi-bin/LJ/SMS/MessageHandler/Friends.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -package LJ::SMS::MessageHandler::Friends; - -use base qw(LJ::SMS::MessageHandler); - -use strict; -use Carp qw(croak); - -sub handle { - my ($class, $msg) = @_; - - my $text = $msg->body_text; - my $u = $msg->from_u; - my $maxlen = $u->max_sms_bytes; - - my ($group) = $text =~ / - ^\s* - f(?:riends)? # post full or short - - (?:\. # optional friends group setting - ( - (?:\"|\').+?(?:\"|\') # single or double quoted friends group - | - \S+) # single word friends group - )? - - \s*$/ix; - - # for quoted strings, the 'group' segment will still have single or double quotes - if ($group) { - $group =~ s/^(?:\"|\')//; - $group =~ s/(?:\"|\')$//; - } - - # if no group specified, see if they have a default friend group prop set - $group ||= $u->prop('sms_friend_group'); - - # try to find the requested friends group and construct a filter mask - my $filter; - if ($group) { - my $groups = LJ::get_friend_group($u); - while (my ($bit, $grp) = each %$groups) { - next unless $grp->{groupname} =~ /^$group$/i; - - # found the security group the user is asking for - $filter = 1 << $grp->{groupnum}; - - last; - } - } else { - # we should return the default view friends group - my $grp = LJ::get_friend_group($u, { 'name'=> 'Default View' }); - my $bit = $grp ? $grp->{'groupnum'} : 0; - $filter = $bit ? (1 << $bit) : undef; - } - - my @entries = LJ::get_friend_items({ - remoteid => $u->id, - itemshow => 5, - skip => 0, - showtypes => 'PYC', - u => $u, - userid => $u->id, - filter => $filter, - }); - - my $resp = ""; - - foreach my $item (@entries) { - - # each $item is just a magical hashref. from that we'll - # need to construct actual LJ::Entry objects to process - # and eventually return via SMS - - my $entry = LJ::Entry->new_from_item_hash($item) - or die "unable to construct entry object"; - - my $seg = $entry->as_sms(for_u => $u, maxlen => 20); - - # could we append this segment without violating the - # SMS message length boundary? - last unless LJ::SMS->can_append($u, $resp, $seg); - - # still more buffer room, append another - $resp .= $seg; - - # now try to append "\n\n" if that won't throw us over the limit - # -- if successful, loop again to try to add a new message, - # the finally strip off any \n\n ... - last unless LJ::SMS->can_append($u, $resp, "\n"); - - $resp .= "\n"; - } - - # trim trailing newlines - $resp =~ s/\n+$//; - - # ... but what if there actually were no entries? - unless ($resp) { - $resp = "Sorry, you currently have no friends page entries"; - $resp .= " for group '$group'" if $group; - $resp .= ")"; - } - - my $resp_msg = eval { $msg->respond($resp) }; - - # FIXME: do we set error status on $resp? - - # mark the requesting (source) message as processed - $msg->status($@ ? ('error' => $@) : 'success'); - - return 1; -} - -sub owns { - my ($class, $msg) = @_; - croak "invalid message passed to MessageHandler" - unless $msg && $msg->isa("LJ::SMS::Message"); - - return $msg->body_text =~ /^\s*f(?:riends)?\.?\s*$/i ? 1 : 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler/Help.pm --- a/cgi-bin/LJ/SMS/MessageHandler/Help.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -package LJ::SMS::MessageHandler::Help; - -use base qw(LJ::SMS::MessageHandler); - -use strict; -use Carp qw(croak); - -# handle messages from unverified users -sub unverified_user_ok { - my ($class, $u) = @_; - - return 1; -} - -sub handle { - my ($class, $msg) = @_; - - my $body_text = - LJ::run_hook("smscmd_help_text", $msg) || - "This is the $LJ::SITENAME SMS Gateway! Baaaaaaaah."; - - my $resp = eval { $msg->respond($body_text, no_quota => 1) }; - - # mark the requesting (source) message as processed - $msg->status($@ ? ('error' => $@) : 'success'); -} - -sub owns { - my ($class, $msg) = @_; - croak "invalid message passed to MessageHandler" - unless $msg && $msg->isa("LJ::SMS::Message"); - - return $msg->body_text =~ /^\s*help(?!\S)/i ? 1 : 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler/ILike.pm --- a/cgi-bin/LJ/SMS/MessageHandler/ILike.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -package LJ::SMS::MessageHandler::ILike; - -use base qw(LJ::SMS::MessageHandler); - -use strict; -use Carp qw(croak); - -sub handle { - my ($class, $msg) = @_; - - my $u = $msg->from_u - or die "no from_u for ILike message"; - - my $text = $msg->body_text; - $text =~ s/^\s*i\s+like\s+//i; - - # now all that's left are interests - my @ints_to_add = LJ::interest_string_to_list($text); - - # in the case where the original body text is >= 160 characters, - # we assume that they've bumped up against the edge of SMS's - # length capability and most likely the last interest has been - # cut off... in this case, we'll pop from @ints_to_add - - # FIXME: don't hardcode 160 - if (length $msg->body_text >= 160 && $msg->body_text =~ /$ints_to_add[-1]$/i) { - warn "truncating message: {" . length($msg->body_text) . "} " . $msg->body_text . "\n"; - pop @ints_to_add; - } - - # load interests - my %ints_old = (map { $_->[1] => $_->[0] } - @{ LJ::get_interests($u, { forceids => 1 }) || []}); - - my @ints_new = keys %ints_old; - push @ints_new, @ints_to_add; - - LJ::set_interests($u, \%ints_old, \@ints_new) - or die "Unable to set interests: " . join(",", @ints_new); - - # mark the requesting (source) message as processed - # -- we'd die before now if there was an error - $msg->status('success'); -} - -sub owns { - my ($class, $msg) = @_; - croak "invalid message passed to MessageHandler" - unless $msg && $msg->isa("LJ::SMS::Message"); - - return $msg->body_text =~ /^\s*i\s+like\s+/i ? 1 : 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler/Menu.pm --- a/cgi-bin/LJ/SMS/MessageHandler/Menu.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -package LJ::SMS::MessageHandler::Menu; - -use base qw(LJ::SMS::MessageHandler); - -use strict; -use Carp qw(croak); - -sub handle { - my ($class, $msg) = @_; - - my $resp = eval { $msg->respond - ("Avail.cmnds: (P)OST, (F)RIENDS, (R)EAD, (A)DD, I LIKE, HELP. " . - "E.g. to read username frank send \"READ frank\". STOP2stop, " . - "HELP4help. Std msg chrgs apply."); - }; - - # FIXME: do we set error status on $resp? - - # mark the requesting (source) message as processed - $msg->status($@ ? ('error' => $@) : 'success'); -} - -sub owns { - my ($class, $msg) = @_; - croak "invalid message passed to MessageHandler" - unless $msg && $msg->isa("LJ::SMS::Message"); - - return $msg->body_text =~ /^\s*m(?:enu)?\s*$/i ? 1 : 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler/Post.pm --- a/cgi-bin/LJ/SMS/MessageHandler/Post.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -package LJ::SMS::MessageHandler::Post; - -use base qw(LJ::SMS::MessageHandler); - -use strict; -use Carp qw(croak); - -sub handle { - my ($class, $msg) = @_; - - my $text = $msg->body_text; - - my ($sec, $subject, $body) = $text =~ / - ^\s* - (?: # the "post" portion is optional - p(?:ost)? # post full or short - - (?:\. # optional security setting - ( - (?:\"|\').+?(?:\"|\') # single or double quoted security - | - \S+) # single word security - )? - - \s+ - )? - - (?: # optional subject - (?:\[|\()(.+?)(?:\]|\)) # [...] or (...) subject - )? - - \s* - - (.+) # teh paylod! - - \s*$/isx; - - # for quoted strings, the 'sec' segment will still have single or double quotes - if ($sec) { - $sec =~ s/^(?:\"|\')//; - $sec =~ s/(?:\"|\')$//; - } - - my $u = $msg->from_u; - my $secmask = 0; - - if ($sec) { - if ($sec =~ /^pu/i) { - $sec = 'public'; - } elsif ($sec =~ /^fr/i) { - $sec = 'usemask'; - $secmask = 1; - } elsif ($sec =~ /^pr/i) { - $sec = 'private'; - } else { - my $groups = LJ::get_friend_group($u); - - my $found = 0; - while (my ($bit, $grp) = each %$groups) { - next unless $grp->{groupname} =~ /^\Q$sec\E$/i; - - # found the security group the user is asking for - $sec = 'usemask'; - $secmask = 1 << $bit; - - $found++; - last; - } - - # if the given security arg was an invalid friends group, - # post the entry as private - $sec = 'private' unless $found; - } - } - - # initiate a protocol request to post this message - my $err; - my $default_subject = "Posted using <a href='$LJ::SITEROOT/manage/sms/'>$LJ::SMS_TITLE</a>"; - my $res = LJ::Protocol::do_request - ("postevent", - { - ver => 1, - username => $u->{user}, - lineendings => 'unix', - subject => $subject || $default_subject, - event => $body, - props => { - sms_msgid => $msg->id, - useragent => 'sms', - }, - security => $sec, - allowmask => $secmask, - tz => 'guess' - }, - \$err, { 'noauth' => 1 } - ); - - # set metadata on this sms message indicating the - # type of handler used and the jitemid of the resultant - # journal post - $msg->meta - ( post_jitemid => $res->{itemid}, - post_error => $err, - ); - - # if we got a jitemid and the user wants to be automatically notified - # of new comments on this post via SMS, add a subscription to it - my $post_notify = $u->prop('sms_post_notify'); - if ($res->{itemid} && $post_notify eq 'SMS') { - - # get an entry object to subscribe to - my $entry = LJ::Entry->new($u, jitemid => $res->{itemid}) - or die "Could not load entry object"; - - $u->subscribe_entry_comments_via_sms($entry); - } - - $msg->status($err ? - ('error' => "Error posting to journal: $err") : 'success'); - - return 1; -} - -sub owns { - my ($class, $msg) = @_; - croak "invalid message passed to MessageHandler" - unless $msg && $msg->isa("LJ::SMS::Message"); - - return $msg->body_text =~ /^\s*p(?:ost)?[\.\s]/i ? 1 : 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler/PostComm.pm --- a/cgi-bin/LJ/SMS/MessageHandler/PostComm.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -package LJ::SMS::MessageHandler::PostComm; - -use base qw(LJ::SMS::MessageHandler); - -use strict; -use Carp qw(croak); - -sub handle { - my ($class, $msg) = @_; - - my $text = $msg->body_text; - - my ($commname, $sec, $subject, $body) = $text =~ / - ^\s* - p(?:ost)?c(?:omm)? # post full or short - - (?:\.([^\s\.]+)) # community username - - (?:\. # optional security setting - ( - (?:\"|\').+?(?:\"|\') # single or double quoted security - | - \S+ - ) # single word security - )? - - \s+ - - (?: # optional subject - (?:\[|\()(.+?)(?:\]|\)) # [...] or (...) subject - )? - - \s* - - (.+) # teh paylod! - - \s*$/isx; - - # for quoted strings, the 'sec' segment will still have single or double quotes - if ($sec) { - $sec =~ s/^(?:\"|\')//; - $sec =~ s/(?:\"|\')$//; - } - - my $u = $msg->from_u; - my $secmask = 0; - - if ($sec) { - if ($sec =~ /^pu/i) { - $sec = 'public'; - } elsif ($sec =~ /^(fr|me)/i) { #friends or members - $sec = 'usemask'; - $secmask = 1; - } else { - # fall back to posting members-only if we can't identify it - $sec = 'usemask'; - $secmask = 1; - } - } - - # initiate a protocol request to post this message - my $err; - my $default_subject = "Posted using <a href='$LJ::SITEROOT/manage/sms/'>$LJ::SMS_TITLE</a>"; - my $res = LJ::Protocol::do_request - ("postevent", - { - ver => 1, - username => $u->{user}, - usejournal => $commname, - lineendings => 'unix', - subject => $subject || $default_subject, - event => $body, - props => { - sms_msgid => $msg->id, - useragent => 'sms', - }, - security => $sec, - allowmask => $secmask, - tz => 'guess' - }, - \$err, { 'noauth' => 1 } - ); - - # try to load the community object so that we can add the - # postcomm_journalid prop below if it was actually a valid - # community... otherwise the prop will not be set and - # we'll error with whatever the protocol returned. - my $commu = LJ::load_user($commname); - - # set metadata on this sms message indicating the - # type of handler used and the jitemid of the resultant - # journal post - $msg->meta - ( postcomm_journalid => ($commu ? $commu->id : undef), - postcomm_jitemid => $res->{itemid}, - postcomm_error => $err, - ); - - $msg->status($err ? - ('error' => "Error posting to community: $err") : 'success'); - - return 1; -} - -sub owns { - my ($class, $msg) = @_; - croak "invalid message passed to MessageHandler" - unless $msg && $msg->isa("LJ::SMS::Message"); - - return $msg->body_text =~ /^\s*p(?:ost)?c/i ? 1 : 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler/Read.pm --- a/cgi-bin/LJ/SMS/MessageHandler/Read.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -package LJ::SMS::MessageHandler::Read; - -use base qw(LJ::SMS::MessageHandler); - -use strict; -use Carp qw(croak); - -sub handle { - my ($class, $msg) = @_; - - my $text = $msg->body_text; - my $remote = $msg->from_u; - my $maxlen = $remote->max_sms_bytes; - - my ($page, $user) = $text =~ / - ^\s* - r(?:ead)? # read full or short - - (?:\. # optional page number - (\d+) # numeric page to retrieve - )? - - \s+ - - (\S{1,15}) # optional friends group setting - - \s*$/ix; - - $page ||= 1; - $page = 1 if $page > 100; - - my $u = LJ::load_user($user) - or die "nonexistant user: $user"; - - my $err; - my ($item) = $u->recent_items( - clusterid => $u->{clusterid}, - clustersource => 'slave', - remote => $remote, - itemshow => 1, - order => 'logtime', - err => \$err, - ); - - my $resp = ""; - - # no entries for this user? - unless ($item) { - $resp = "Sorry, user '$user' has posted no entries"; - # now fall through to sending phase - } - - # have an entry, try to process it - if ($item) { - my $entry = LJ::Entry->new_from_item_hash($u, $item) - or die "unable to construct entry object"; - - # $item is just a magical hashref. from that we'll need to - # construct an actual LJ::Entry object to process and - # eventually return via SMS - - $resp = $entry->as_paged_sms(for_u => $remote, page => $page); - - # trim trailing newlines - $resp =~ s/\n+$//; - } - - my $resp_msg = eval { $msg->respond($resp) }; - - # FIXME: do we set error status on $resp? - - # mark the requesting (source) message as processed - $msg->status($@ ? ('error' => $@) : 'success'); - - return 1; -} - -sub owns { - my ($class, $msg) = @_; - croak "invalid message passed to MessageHandler" - unless $msg && $msg->isa("LJ::SMS::Message"); - - return $msg->body_text =~ /^\s*r(?:ead)(?!\S)/i ? 1 : 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/SMS/MessageHandler/Stop.pm --- a/cgi-bin/LJ/SMS/MessageHandler/Stop.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -package LJ::SMS::MessageHandler::Stop; - -use base qw(LJ::SMS::MessageHandler); - -use strict; -use Carp qw(croak); - -sub handle { - my ($class, $msg) = @_; - - my $u = $msg->from_u or croak "No user in message"; - - if ($msg->body_text =~ /stop all/i || $u->prop('sms_yes_means') eq 'stop') { - LJ::SMS::stop_all($u, $msg); - } else { - - $msg->respond("$LJ::SMS_TITLE: Disable $LJ::SMS_TITLE? ". - "Send YES to confirm. Std msg chrgs apply.", no_quota => 1); - - $u->set_prop('sms_yes_means', 'stop'); - } - - # mark the requesting (source) message as processed - $msg->status($@ ? ('error' => $@) : 'success'); -} - -sub owns { - my ($class, $msg) = @_; - croak "invalid message passed to MessageHandler" - unless $msg && $msg->isa("LJ::SMS::Message"); - - my @synonyms = qw ( - stop - end - cancel - unsub - unsubscribe - quit - ); - - foreach my $syn (@synonyms) { - return 1 if $msg->body_text =~ /^\s*$syn(?!\S)/i; - } - - return 0; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Setting/Display/SMSHistory.pm --- a/cgi-bin/LJ/Setting/Display/SMSHistory.pm Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -package LJ::Setting::Display::SMSHistory; -use base 'LJ::Setting'; -use strict; -use warnings; - -sub should_render { - my ($class, $u) = @_; - - return $u && !$u->is_community ? 1 : 0; -} - -sub label { - my $class = shift; - - return $class->ml('setting.display.smshistory.label'); -} - -sub option { - my ($class, $u, $errs, $args) = @_; - - return "<a href='$LJ::SITEROOT/manage/sms/status.bml'>" . $class->ml('setting.display.smshistory.option', { sms_title => $LJ::SMS_TITLE }) . "</a>"; -} - -1; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/Test.pm --- a/cgi-bin/LJ/Test.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/Test.pm Mon Aug 03 15:24:55 2009 +0000 @@ -16,7 +16,7 @@ use Class::Autouse qw( LJ::ModuleCheck ); @ISA = qw(Exporter); -@EXPORT = qw(memcache_stress with_fake_memcache temp_user temp_comm temp_feed alloc_sms_num fake_apache); +@EXPORT = qw(memcache_stress with_fake_memcache temp_user temp_comm temp_feed fake_apache); my @temp_userids; # to be destroyed later END { @@ -181,18 +181,6 @@ sub memcache_stress (&) { LJ::MemCache::set_memcache($pre_mem); } -sub alloc_sms_num { - my $sms_num; - - for (1..100) { - $sms_num = '+1'; - $sms_num .= int(rand(10)) foreach (1..10); - return $sms_num unless LJ::SMS->num_to_uid($sms_num); - } - - die "Unable to allocate SMS number after 100 tries"; -} - package LJ::Test::FakeMemCache; # duck-typing at its finest! # this is a fake Cache::Memcached object which implements the @@ -287,28 +275,6 @@ sub forget_dead_hosts {} package LJ::User; - -# set the user up for sms -sub t_activate_sms { - my ($u) = @_; - $u->set_sms_number( - LJ::Test::alloc_sms_num(), - verified => 'Y' - ); -} - -# pretend the user sent us an SMS -sub t_receive_sms { - my ($u, $message) = @_; - - my $msg = LJ::SMS::Message->new( - owner => $u, - from => $u, - body_text => $message, - ); - - LJ::SMS::MessageHandler->handle($msg); -} # post a fake entry in a community journal sub t_post_fake_comm_entry { diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/LJ/User.pm --- a/cgi-bin/LJ/User.pm Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/LJ/User.pm Mon Aug 03 15:24:55 2009 +0000 @@ -28,8 +28,6 @@ use DW::Logic::ProfilePage; use Class::Autouse qw( LJ::Subscription - LJ::SMS - LJ::SMS::Message LJ::Identity LJ::Auth LJ::Jabber::Presence @@ -68,7 +66,6 @@ use Class::Autouse qw( ### 20. Page Notices Functions ### 21. Password Functions ### 22. Priv-Related Functions -### 23. SMS-Related Functions ### 24. Styles and S2-Related Functions ### 25. Subscription, Notifiction, and Messaging Functions ### 26. Syndication-Related Functions @@ -4371,184 +4368,6 @@ sub revoke_priv_all { ######################################################################## -### 23. SMS-Related Functions -### FIXME: Determine which of these are TxtLJ backend (bug 199). All? - - -sub add_sms_quota { - my ($u, $qty, $type) = @_; - - return LJ::SMS->add_sms_quota($u, $qty, $type); -} - - -sub can_use_sms { - my $u = shift; - return LJ::SMS->can_use_sms($u); -} - - -sub delete_sms_number { - my $u = shift; - return LJ::SMS->replace_mapping($u, undef); -} - - -sub max_sms_bytes { - return LJ::SMS->max_sms_bytes( @_ ); -} - - -sub max_sms_substr { - return LJ::SMS->max_sms_substr( @_ ); -} - - -# opts: -# no_quota = don't check user quota or deduct from their quota for sending a message -sub send_sms { - my ($u, $msg, %opts) = @_; - - return 0 unless $u; - - croak "invalid user object for object method" - unless LJ::isu($u); - croak "invalid LJ::SMS::Message object to send" - unless $msg && $msg->isa("LJ::SMS::Message"); - - my $ret = $msg->send(%opts); - - return $ret; -} - - -sub send_sms_text { - my ($u, $msgtext, %opts) = @_; - - my $msg = LJ::SMS::Message->new( - owner => $u, - to => $u, - type => 'outgoing', - body_text => $msgtext, - ); - - # if user specified a class_key for send, set it on - # the msg object - if ($opts{class_key}) { - $msg->class_key($opts{class_key}); - } - - $msg->send(%opts); -} - - -sub set_sms_number { - my ($u, $num, %opts) = @_; - my $verified = delete $opts{verified}; - - # these two are only checked if $num, because it's possible - # to just pass ($u, undef, undef) to delete the mapping - if ($num) { - croak "invalid number" unless $num =~ /^\+\d+$/; - croak "invalid verified flag" unless $verified =~ /^[YN]$/; - } - - return LJ::SMS->replace_mapping($u, $num, $verified); -} - - -sub set_sms_number_verified { - my ($u, $verified) = @_; - - return LJ::SMS->set_number_verified($u, $verified); -} - - -sub set_sms_quota { - my ($u, $qty, $type) = @_; - - return LJ::SMS->set_sms_quota($u, $qty, $type); -} - - -sub sms_active { - my $u = shift; - - # active if the user has a verified sms number - return LJ::SMS->configured_for_user($u); -} - - -sub sms_active_number { - my $u = shift; - return LJ::SMS->uid_to_num($u, verified_only => 1); -} - - -# this method returns any mapped number for the user, -# regardless of its verification status -sub sms_mapped_number { - my $u = shift; - return LJ::SMS->uid_to_num($u, verified_only => 0); -} - - -sub sms_message_count { - my $u = shift; - return LJ::SMS->message_count($u, @_); -} - - -sub sms_num_instime { - my $u = shift; - - return LJ::SMS->num_instime($u->sms_mapped_number); -} - - -sub sms_pending { - my $u = shift; - - # pending if user has an unverified number - return LJ::SMS->pending_for_user($u); -} - - -sub sms_pending_number { - my $u = shift; - my $num = LJ::SMS->uid_to_num($u, verified_only => 0); - return undef unless $num; - return $num if LJ::SMS->num_is_pending($num); - return undef; -} - - -sub sms_quota_remaining { - return LJ::SMS->sms_quota_remaining( @_ ); -} - - -sub sms_register_time_remaining { - my $u = shift; - - return LJ::SMS->num_register_time_remaining($u); -} - - -sub sms_sent_message_count { - my $u = shift; - return LJ::SMS->sent_message_count($u, @_); -} - - -sub subtract_sms_quota { - my ($u, $qty, $type) = @_; - - return LJ::SMS->subtract_sms_quota($u, $qty, $type); -} - - -######################################################################## ### 24. Styles and S2-Related Functions @@ -5310,33 +5129,6 @@ sub opt_getting_started { my $prop = $u->raw_prop('opt_getting_started') || 'Y'; return $prop; -} - - -# FIXME: We're not using TxtLJ, so this can probably go. -# Came from section 25. -sub subscribe_entry_comments_via_sms { - my ($u, $entry) = @_; - croak "Invalid LJ::Entry passed" - unless $entry && $entry->isa("LJ::Entry"); - - # don't subscribe if user is over subscription limit - return unless $u->can_add_inbox_subscription; - - my %sub_args = - ( event => "LJ::Event::JournalNewComment", - journal => $u, - arg1 => $entry->ditemid, ); - - $u->subscribe - ( method => "LJ::NotificationMethod::SMS", - %sub_args, ); - - $u->subscribe - ( method => "LJ::NotificationMethod::Inbox", - %sub_args, ); - - return 1; } @@ -6129,7 +5921,7 @@ sub unset_remote # 'R' == memory (remembrance), 'K' == keyword id, # 'P' == phone post, 'C' == pending comment # 'O' == pOrtal box id, 'V' == 'vgift', 'E' == ESN subscription id -# 'Q' == Notification Inbox, 'G' == 'SMS messaGe' +# 'Q' == Notification Inbox, # 'D' == 'moDule embed contents', 'I' == Import data block # 'Z' == import status item, 'X' == eXternal account # @@ -6250,9 +6042,6 @@ sub alloc_user_counter undef, $uid); } elsif ($dom eq "Q") { $newmax = $u->selectrow_array("SELECT MAX(qid) FROM notifyqueue WHERE userid=?", - undef, $uid); - } elsif ($dom eq "G") { - $newmax = $u->selectrow_array("SELECT MAX(msgid) FROM sms_msg WHERE userid=?", undef, $uid); } elsif ($dom eq "D") { $newmax = $u->selectrow_array("SELECT MAX(moduleid) FROM embedcontent WHERE userid=?", diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/ljdb.pl --- a/cgi-bin/ljdb.pl Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/ljdb.pl Mon Aug 03 15:24:55 2009 +0000 @@ -212,7 +212,7 @@ package LJ; use Carp qw(croak); -# when calling a supported function (currently: LJ::load_user() or LJ::load_userid*), LJ::SMS::load_mapping() +# when calling a supported function (currently: LJ::load_user() or LJ::load_userid*) # ignores in-process request cache, memcache, and selects directly # from the global master # diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/ljdefaults.pl --- a/cgi-bin/ljdefaults.pl Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/ljdefaults.pl Mon Aug 03 15:24:55 2009 +0000 @@ -350,10 +350,6 @@ } } - # sms defaults - $LJ::SMS_DOMAIN ||= $LJ::DOMAIN; - $LJ::SMS_TITLE ||= "$LJ::SITENAMESHORT SMS"; - # random user defaults to a week $RANDOM_USER_PERIOD = 7; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 cgi-bin/ljlib.pl --- a/cgi-bin/ljlib.pl Mon Aug 03 15:16:25 2009 +0000 +++ b/cgi-bin/ljlib.pl Mon Aug 03 15:24:55 2009 +0000 @@ -93,8 +93,6 @@ sub END { LJ::end_request(); } "user_schools", "portal_config", "portal_box_prop", "loginlog", "active_user", "userblobcache", "notifyqueue", "cprod", "urimap", - "sms_msg", "sms_msgprop", "sms_msgack", - "sms_msgtext", "sms_msgerror", "jabroster", "jablastseen", "random_user_set", "poll2", "pollquestion2", "pollitem2", "pollresult2", "pollsubmission2", @@ -335,26 +333,6 @@ sub theschwartz { $LJ::SchwartzClient{$role} = TheSchwartz->new(databases => \@dbs); return $LJ::SchwartzClient{$role}; -} - -sub sms_gateway { - my $conf_key = shift; - - # effective config key is 'default' if one wasn't specified or nonexistent - # config was specified, meaning fall back to default - unless ($conf_key && $LJ::SMS_GATEWAY_CONFIG{$conf_key}) { - $conf_key = 'default'; - } - - return $LJ::SMS_GATEWAY{$conf_key} ||= do { - my $class = "DSMS::Gateway" . - ($LJ::SMS_GATEWAY_TYPE ? "::$LJ::SMS_GATEWAY_TYPE" : ""); - - eval "use $class"; - die "unable to use $class: $@" if $@; - - $class->new(config => $LJ::SMS_GATEWAY_CONFIG{$conf_key}); - }; } sub gtop { @@ -1317,8 +1295,6 @@ sub start_request %LJ::REQ_CACHE_USER_ID = (); # users by id %LJ::REQ_CACHE_REL = (); # relations from LJ::check_rel() %LJ::REQ_LANGDATFILE = (); # caches language files - %LJ::SMS::REQ_CACHE_MAP_UID = (); # cached calls to LJ::SMS::num_to_uid() - %LJ::SMS::REQ_CACHE_MAP_NUM = (); # cached calls to LJ::SMS::uid_to_num() %LJ::S2::REQ_CACHE_STYLE_ID = (); # styleid -> hashref of s2 layers for style %LJ::S2::REQ_CACHE_LAYER_ID = (); # layerid -> hashref of s2 layer info (from LJ::S2::load_layer) %LJ::S2::REQ_CACHE_LAYER_INFO = (); # layerid -> hashref of s2 layer info (from LJ::S2::load_layer_info) diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 doc/raw/build/ljconfig/ljconfig2db.pl --- a/doc/raw/build/ljconfig/ljconfig2db.pl Mon Aug 03 15:16:25 2009 +0000 +++ b/doc/raw/build/ljconfig/ljconfig2db.pl Mon Aug 03 15:24:55 2009 +0000 @@ -560,22 +560,6 @@ Please see <a href='http://status.exa }, 'server_totally_down' => { 'desc' => "The site is globally marked as 'down' and users get an error message, as defined by \$SERVER_DOWN_MESSAGE and \$SERVER_DOWN_SUBJECT. But compared to \$SERVER_DOWN, this error message is done incredibly early before any dispatch to different modules. See also [ljconfig[server_down]].", - }, - }, - - 'messaging_related' => { - 'name' => "Messaging Related", - 'sms_domain' => { - 'desc' => "Base domain for SMS service. Defaults to value of [ljconfig[domain]]. You might use this in message footers you send to users.", - }, - 'sms_shortcode' => { - 'desc' => "Number of your SMS service for users to send to and receive from.", - 'example' => "55512", - }, - 'sms_title' => { - 'desc' => "The name of your <acronym>SMS</acronym> service. Used on <acronym>SMS</acronym> communications and site pages.", - 'default' => '$SITENAMESHORT SMS', - 'example' => 'TXT$SITENAMEABBREV', }, }, diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 doc/raw/lj.book/install/ljconfig.disabled.xml --- a/doc/raw/lj.book/install/ljconfig.disabled.xml Mon Aug 03 15:16:25 2009 +0000 +++ b/doc/raw/lj.book/install/ljconfig.disabled.xml Mon Aug 03 15:24:55 2009 +0000 @@ -283,22 +283,6 @@ <listitem><simpara>Allow QuickReply to be built in to S2 layers.</simpara></listitem> </varlistentry> <varlistentry> - <term>sms</term> - <listitem><simpara>Global flag to enable the <acronym>SMS</acronym> messaging feature (and its user-interface) for users.</simpara></listitem> - </varlistentry> - <varlistentry> - <term>sms_post_auto_subscribe</term> - <listitem><simpara>Show the <quote>Subscribe me to my <acronym>SMS</acronym> posts via <acronym>SMS</acronym></quote> button to users.</simpara></listitem> - </varlistentry> - <varlistentry> - <term>sms_quota_check</term> - <listitem><simpara>Enable checking for how many <acronym>SMS</acronym> messages a user has sent out of their quota.</simpara></listitem> - </varlistentry> - <varlistentry> - <term>sms_ui</term> - <listitem><simpara>Enable <acronym>SMS</acronym> user-interface for users. This enables links and management pages.</simpara></listitem> - </varlistentry> - <varlistentry> <term>syncitems</term> <listitem><simpara>Enable the <literal>syncitems</literal> client protocol mode, without restarting &apache;.</simpara></listitem> </varlistentry> diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 doc/raw/lj.book/install/ljconfig.helpurls.xml --- a/doc/raw/lj.book/install/ljconfig.helpurls.xml Mon Aug 03 15:16:25 2009 +0000 +++ b/doc/raw/lj.book/install/ljconfig.helpurls.xml Mon Aug 03 15:24:55 2009 +0000 @@ -44,10 +44,6 @@ <listitem><simpara>Explains how to choose a secure password</simpara></listitem> </varlistentry> <varlistentry> - <term>sms_about</term> - <listitem><simpara>Explains what the <acronym>SMS</acronym> feature is and how it works</simpara></listitem> - </varlistentry> - <varlistentry> <term>userpic_inactive</term> <listitem><simpara>Explains why a userpic might become inactive, and how to make the userpic active again</simpara></listitem> </varlistentry> diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 doc/raw/lj.book/install/workers_setup.xml --- a/doc/raw/lj.book/install/workers_setup.xml Mon Aug 03 15:16:25 2009 +0000 +++ b/doc/raw/lj.book/install/workers_setup.xml Mon Aug 03 15:24:55 2009 +0000 @@ -125,7 +125,6 @@ For example: For example: <informalexample> <programlisting>localhost / process-esn = 1 -localhost / process-sms = 1 localhost / send-email = 1</programlisting></informalexample></para> <para>You need to configure <systemitem class="daemon">gearmand</systemitem> servers in <filename>ljconfig.pl</filename>, diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 t/esn-findsubscription.t --- a/t/esn-findsubscription.t Mon Aug 03 15:16:25 2009 +0000 +++ b/t/esn-findsubscription.t Mon Aug 03 15:24:55 2009 +0000 @@ -69,13 +69,6 @@ test_subscription(sub { journal => $u2, ); ok(!$foundsubs, "Couldn't find bogus subscription"); - $foundsubs = $u1->has_subscription( - event => "JournalNewComment", - method => "SMS", - journal => $u2, - ); - ok(!$foundsubs, "Couldn't find bogus subscription"); - } # look for more general matches { diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 t/esn-journalnewentry.t --- a/t/esn-journalnewentry.t Mon Aug 03 15:16:25 2009 +0000 +++ b/t/esn-journalnewentry.t Mon Aug 03 15:24:55 2009 +0000 @@ -113,10 +113,6 @@ sub test_post { ok($u2e1, "made a post$suffix"); is($@, "", "no errors"); - # make sure we got notification - $email = $got_notified->($u1); - ok($email, "got the sms $state"); - # S1 failing case: # post an entry on $u1, where nobody's subscribed my $u1e1 = eval { $u1->t_post_fake_entry(%opts) }; diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 t/notificationmethod-sms.t --- a/t/notificationmethod-sms.t Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -#!/usr/bin/perl - -use strict; -use Test::More 'no_plan'; -use lib "$ENV{LJHOME}/cgi-bin"; -require 'ljlib.pl'; - -use LJ::Test qw(temp_user memcache_stress); - -use Class::Autouse qw( - LJ::Event::Befriended - LJ::NotificationMethod::SMS - ); - -local $LJ::_T_NO_SMS_QUOTA = 1; - -my $u; -my $valid_u = sub { - return $u = temp_user(); -}; - -# less duplication of this so we can revalidate -my $meth; -my $valid_meth = sub { - $meth = eval { LJ::NotificationMethod::SMS->new($u) }; - ok(ref $meth && ! $@, "valid SMS method instantiated"); - return $meth; -}; - -sub run_tests{ - { - # constructor tests - $valid_u->(); - $valid_meth->(); - - $meth = eval { LJ::NotificationMethod::SMS->new() }; - like($@, qr/invalid user/, "no args passed to constructor"); - - $meth = eval { LJ::NotificationMethod::SMS->new({user => 'ugly'}) }; - like($@, qr/invalid user/, "non-user passed to constructor"); - - # test valid case - $valid_meth->(); - } - - # accessor/setter tests - { - my $mu; - - $valid_u->(); - $valid_meth->(); - - # now we have valid from prev test - $mu = eval { $meth->{u} }; - is($mu, $u, "member u is constructed u"); - - $mu = eval { $meth->u }; - is_deeply($mu, $u, "gotten u is constructed u"); - - $mu = eval { $meth->u('foo') }; - like($@, qr/invalid 'u'/, "setting non-ref"); - - $mu = eval { $meth->u($u, 'bar') }; - like($@, qr/superfluous/, "superfluous args"); - - # clear out $u - %$u = (); - LJ::start_request(); - $mu = eval { $meth->u }; - ok(! %$u, "cleared 'u'"); - - $valid_u->(); - - $mu = eval { $meth->u($u) }; - is_deeply($mu, $u, "set new 'u' in object"); - } - - # notify - { - $valid_u->(); - $u->set_sms_number("+12345", verified => 'Y'); - $valid_meth->(); - - my $ev; - - my $fromu = $u; # yeah, you can friend yourself - $ev = LJ::Event::Befriended->new($u, $fromu); - ok(ref $ev && ! $@, "created LJ::Event::Befriended object"); - - # failures - eval { LJ::NotificationMethod::SMS::notify() }; - like($@, qr/'notify'.+?object method/, "notify class method"); - - eval { $meth->notify }; - like($@, qr/requires an event/, "notify no events"); - - eval { $meth->notify(undef) }; - like($@, qr/invalid event/, "notify undef event"); - - my $str = $ev->as_string; - - my $got_sms = 0; - local $LJ::_T_SMS_SEND = sub { - my $sms = shift; - $got_sms = $sms; - }; - - $meth->notify($ev); - ok($got_sms, "got sms"); - } -} - -memcache_stress { - run_tests; -} diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 t/sms-handler-postcomm.t --- a/t/sms-handler-postcomm.t Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -#!/usr/bin/perl - -use strict; -use Test::More 'no_plan'; -use lib "$ENV{LJHOME}/cgi-bin"; - -require "ljlib.pl"; -require "ljprotocol.pl"; -require "communitylib.pl"; - -use LJ::Entry; -use LJ::SMS; -use LJ::SMS::MessageHandler::PostComm; -use LJ::Test qw(memcache_stress temp_user temp_comm); - -run_tests(); - -sub run_tests { - - # ->owns - { - # set up test accounts - my $u = temp_user(); - my $user = $u->{user}; - - my $c = temp_comm(); - my $comm = $c->{user}; - - # set up account settings - $u->set_sms_number('+15555551212', verified => 'Y'); - LJ::join_community($u, $c, 0, 1); - LJ::update_user($u, { status => 'A' }); - - foreach my $prefix - ( "postcomm.$comm", - "PostComm.$comm", - "postc.$comm", - "pcomm.$comm", - "pc.$comm", - "PC.$comm" ) - { - foreach my $sec - ("", - ".public", - ".pu", - ".PuBliC", - ".pU", - ".friends", - ".fr", - ".fRieNDS", - ".FR", - # can't use custom/private security on comms - ) - { - foreach my $subj - (map { $_ ? "$_ " : "" } - "", - "[TestSubject]", - "(TestSubject)") - { - my $text = "$prefix$sec ${subj}foo"; - - my $msg = LJ::SMS::Message->new - ( - owner => $u, - type => 'incoming', - from => $u, - body_text => $text - ); - - my $rv = LJ::SMS::MessageHandler::PostComm->owns($msg); - ok($rv, "owns: $text"); - - $rv = eval { LJ::SMS::MessageHandler->handle($msg) }; - my $ok = $rv && ! $@ && $msg && $msg->is_success && ! $msg->error; - die $msg->error if $msg->error; - ok($ok, "handle: $text"); - warn "rv: $rv, \$@: $@, msg: " . LJ::D($msg) unless $ok; - - - my $jitemid = $msg->meta("postcomm_jitemid"); - ok($jitemid, "postcomm_jitemid set"); - ok($msg->meta("handler_type") eq "PostComm", "handler_type prop set"); - - my $entry = eval { LJ::Entry->new($c, jitemid => $jitemid) }; - ok($entry && ! $@, "entry in db"); - ok($entry && $entry->event_text eq "foo", "event text matches"); - ok($entry && $entry->prop("sms_msgid") eq $msg->id, "event sms_msgid prop matches"); - } - } - } - } - - # protocol failure - - # protocol success - - -} diff -r cdcc2fdcdaf2 -r fd9f9a2a1ed4 t/sms-handler-read.t --- a/t/sms-handler-read.t Mon Aug 03 15:16:25 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -#!/usr/bin/perl - -use strict; -use Test::More 'no_plan'; -use lib "$ENV{LJHOME}/cgi-bin"; - -require "ljlib.pl"; -require "ljprotocol.pl"; -require "communitylib.pl"; - -use LJ::Entry; -use LJ::SMS; -use LJ::SMS::MessageHandler::Read; -use LJ::Test qw(memcache_stress temp_user); - -# save the sent message in a global so we can check it -my $SENT_MSG = undef; -$LJ::_T_SMS_SEND = sub { $SENT_MSG = shift }; - -sub run_tests { - - # ->owns - { - # set up test accounts - my $u = temp_user(); - my $user = $u->{user}; - - # set up account settings - $u->set_sms_number('+15555551212', verified => 'Y'); - - $LJ::DISABLED{sms_quota_check} = 1; - LJ::update_user($u, { status => 'A' }); - - # post an entry to this user account - my $entry = $u->t_post_fake_entry - ( - subject => "This is a test subject", - body => LJ::rand_chars(160*8) - ); - - # special case, $page0 should be equal to $page1 exactly - my $page0_ret; - my @pages_ret; - - foreach my $cmd (qw(read ReAd r R)) { - - # common header for each message page - # -- declared here and modified throughout test - my $header; - - PAGE: - foreach my $page (0..25) { - my $psuf = $page ? ".$page" : ""; - my $text = "$cmd$psuf $user"; - - # replace {\d} with page number for matching - $header =~ s/\(\d+([^\)]*)\)/\($page$1\)/; - - my $msg = LJ::SMS::Message->new - ( - owner => $u, - type => 'incoming', - from => $u, - to => '12345', - body_text => $text - ); - - my $rv = LJ::SMS::MessageHandler::Read->owns($msg); - ok($rv, "owns: $text"); - $rv = eval { LJ::SMS::MessageHandler->handle($msg) }; - my $ok = $rv && ! $@ && $msg && $msg->is_success && ! $msg->error; - ok($ok && ref $SENT_MSG, "handle: $text"); - - { - my $sent = $SENT_MSG; - my $sent_text = $sent->body_text; - - # special case, page 0 (no page specified) should equal page 1 - if ($page == 0) { - $page0_ret = $sent_text; - - # now find the header out of here - my $idx = index($page0_ret, "[" . $entry->subject_orig); - $header = substr($page0_ret, 0, $idx); - } - if ($page == 1) { - ok($page0_ret = $sent_text, "page 0 matches page 1: $text") - } - if ($page > 0) { - last PAGE if $page > 1 && $sent_text eq $page0_ret; - - my $idx = do { use bytes; length($header) }; - $sent_text = substr($sent_text, $idx); - $sent_text =~ s/\.\.\.$//; - push @pages_ret, $sent_text; - } - } - - ok($msg->meta("handler_type") eq "Read", "handler_type prop set: $text"); - } - - { - my $subj = $entry->subject_orig; - my $body = $entry->event_orig; - ok(join("", @pages_ret) =~ /^.+?$subj.+?$body\.*$/, "paging adds up: $cmd"); - } - } - } - - # protocol failure - - # protocol success - - -} - -run_tests(); - --------------------------------------------------------------------------------
no subject
no subject
for i in `bin/cvsreport.pl -n -1`; do rm $i; done
(I think I picked it up from one of the wiki pages. somewhere... IT is possible someone has written a script for this too?)