Sponsoring The Perl Toolchain Summit 2025: Help make this important event another success Learn more

package Net::Msmgr;
use 5.006;
use strict;
require Exporter;
use vars qw / $TRID $dalogin /;
our @ISA = qw(Exporter);
our %EXPORT_TAGS = ( 'debug' => [ qw ( DEBUG_PACKET_SEND
DEBUG_PACKET_RECV
DEBUG_COMMAND_SEND
DEBUG_COMMAND_RECV
DEBUG_OPEN
DEBUG_CLOSE
DEBUG_CONFUSED
DEBUG_HANDLER
DEBUG_NOTIFICATION) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'debug'} }, qw { GetVersion8Response } );
our @EXPORT = qw();
our $VERSION = substr(q$Revision: 0.16 $,10);
use constant DEBUG_PACKET_SEND => 1;
use constant DEBUG_PACKET_RECV => 2;
use constant DEBUG_COMMAND_SEND => 4;
use constant DEBUG_COMMAND_RECV => 8;
use constant DEBUG_OPEN => 16;
use constant DEBUG_CLOSE => 32;
use constant DEBUG_CONFUSED => 64;
use constant DEBUG_HANDLER => 128;
use constant DEBUG_NOTIFICATION => 256;
$TRID = 0 ;
$dalogin = undef; # cache this for speedier connections
sub TRID
{
$TRID++;
return $TRID;
}
sub GetVersion8Response
{
my $user = shift;
my ($trid, $scheme, $state, $string ) = @_;
my %challenge_part = map { split '=' } split(',', $string) ;
unless ($dalogin)
{
my $ua = new LWP::UserAgent;
my $response = $ua->get('https://nexus.passport.com/rdr/pprdr.asp');
my %passport_urls =
map { split '=' } split(',',($response->headers->header('PassportURLs')));
$dalogin = $passport_urls{'DALogin'};
}
warn "No dalogin" unless $dalogin;
return unless $dalogin;
my $username = uri_escape($user->user);
my $password = uri_escape($user->password);
my $auth_string = 'Passport1.4 ' . join(',',
qq {OrgVerb=GET},
qq {OrgURL=$challenge_part{ru}} ,
qq {sign-in=$username},
qq {pwd=$password},
qq {lc=$challenge_part{lc}},
qq {id=$challenge_part{id}},
qq {tw=$challenge_part{tw}},
qq {fs=$challenge_part{fs}},
## qq {ru=$challenge_part{ru}},
qq {ct=$challenge_part{ct}},
qq {kpp=$challenge_part{kpp}},
qq {kv=$challenge_part{kv}},
qq {ver=$challenge_part{ver}},
qq {tpf=$challenge_part{tpf}} );
my $ua = new LWP::UserAgent;
my $request = new HTTP::Request ( GET => 'https://' . $dalogin );
$request->headers->header('Authorization' => $auth_string);
my $response = $ua->request($request);
if ($response->is_success)
{
if (my $auth_info = $response->header('authentication-info'))
{
$auth_info =~ m/(t=.*\$\$\&p=.*\$\$)/;
if (my $magic_string = $1)
{
return $magic_string;
}
}
}
return undef;
}
1;
=pod
=head1 NAME
Net::Msmgr - Microsoft Network Chat Client Toolkit
This is the documentation for $Revision: 0.16 $
=head1 SYNOPSIS
use Net::Msmgr;
use Net::Msmgr::Sesssion;
use Net::Msmgr::User;
our $session = new Net::Msmgr::Session;
our $user = new Net::Msmgr::User ( user => 'username@msn.com',
password => 'my_password' ) ;
$session->user($user);
$session->login_handler( sub { shift->Logout } ) ;
$session->connect_handler ( ... ) ;
$session->Login;
=head1 OVERVIEW
This is a set of perl modules for encapsulating interactions with the
Microsoft Network "Messenger" chat system. You might use it to
develop clients, or robots. The components are, this module, Net::Msmgr,
which contains some non-object helper routines (mostly the
authentication chain for using MSNP8 (Protocol version 8) and a
handful of manifest constants for debugging.
Other modules include:
=over
=item Net::Msmgr::Session
Encapsulates the entirety of a session.
=item Net::Msmgr::User
Holds user authentication credentials.
=item Net::Msmgr::Command
Used to hold command objects sent to or received from the servers.
=item Net::Msmgr::Connection
Used to encapsulate server connections.
=item Net::Msmgr::Switchboard
Derived from Net::Msmgr::Connection
=item Net::Msmgr::Conversation
A higher level view of conversation - contains (but is not) a Switchboard
=item Net::Msmgr::Object
Pure base class from which all of the others are derived. Direct from
the perltoot manpage.
=head1 SERVER PROTOCOL
The entire protocol consists of a series of discrete messages that are
passed between the client and the various servers that make up the
system. Messages come in a variety of broad classes (Normal,
Asyncronous, and Payload), and those are subdivided into more specific
types (Transfer Requests, Chat Messages, State Change Notifications.)
There are three servers you will deal with during a basic session, the
Dispatch Server, which is a meta server to distribute inbound
sessions, the Notification Server, which will hold a single connection
for the life of the session, and Switchboard Servers, which you will hold
as many connections as you have chat groups active.
Technically, there is no difference between the Dispatch Server and
the Notification Server, except that the Dispatch Server will
(historically) always refer you to a Notification Server. There is
nothing in the protocol to prohibit a Notification Server from ALSO
refering you to a third Notification Server, although this author has
never seen that happen.
Because of this, we tend to think of the DS and the NS as dissimilar
entities, but there is no need for them to be so, and in the interest
of flexibility they are treated the same. There is no limit, besides
end-user patience to how many XFR messages you can receive.
=head2 DISPATCH SERVER
This is the first-base server. Your minimum action here is to request
a session, and act on the instructions from the server.
=head2 NOTIFICATION SERVER
This is the center of your session, and when you have connected here,
most (other) clients, and this library will consider you "connected"
to MSN Chat.
=head2 SWITCHBOARD SERVER
To send or receive messages from other clients, there must be a
connection to one or more Switchboard Servers. Each one of these
connections is a 'party line', and all users currently connected to
the same session (referenced by what the library calls a $ssid
Switchboard Session ID) will see all messages sent by any user. The
number of users that can be attached to a SSID appears to be
reaosonably unlimited (on the order of dozens).
=head1 COMMAND SUMMARY
Here is a quick summary of all of the messages used in this library
between the client and the servers.
=over
=item VER -- Version
Optionally sent from client to DS / NS for protocol version negotiation.
=item INF -- Information
Optionally sent from client to DS / NS, asking what Encryption
Technique to use. In MSNP7 and lower, it is always MD5. MSNP8 uses a
different technique, but does not use this command to negotiate it.
Go figure.
=item USR -- User Information
Used in two variants from client to server as part of
the login procedure, in a slightly different variant from server to client as
part of that same procedure, and again later during the authentication
with Switchboard Servers.
=item XFR -- Transfer
Used in one variant from server to client as part of
the login procedure, referring you from DS to NS. Used again later
from client to server to request a connection to a switchboard server.
=item CHG -- Change
Sent from client to server to alter your 'presence' (online, out to lunch, etc.)
=item ILN -- Inital online
Sent from server to client in response to your first change to online
status, with a list of visible users already on the system.
=item SYN -- Synchonize
Optionally sent from client to server to request a download of all of your user lists.
=item GTC -- no known mnemonic
Part of the bundle of information sent from server to client, it
advises the client of a user-set preference for dealing with new
users. It is stored on the server, but not acted on in any way. Can
be sent as a command to the server to alter this setting.
=item BLP -- Blocking Preference
Part of the bundle of information sent from server to client as part
of a SYN. Used by the server to determine behavior if an unkonwn user
attempts to invite you to a switchboard session.
=item PRP -- Personal Phone Number
Sent from server to client during SYN, and sent from client to server
to change the settings. Designed to hold telephone numbers on the
server in URI-encoded strings, and a few variants to hold some mobile
device preferences.
=item LST -- List
Sent from server to client during SYN, and in resposne to a LST
command. One variant for each of the four lists (Allow, Block, Forward
and Reverse) the server maintains for each client.
=item ADD -- Add
Sent from client to server to add a user to a list. Echoed from
server to client with new list serial-number. The server maintains
this serial-number, such that the client may cache the list locally.
=item REM -- Remove
Sent from client to server to remove a user from a list.
=item REA -- Rename
Sent from client to server to change the Friendly Name associated with
a user in your lists. Also used to change your own friendly name.
=item MSG -- Message
Sent from DS/NS server to client at login, and sometimes for
administrative (shutdown) messages. Also, the core of what this
protocol is about - sending messages to other users and receiving
messages from other users via Switchboard Servers.
=item ANS -- Answer
Sent from client to switchboard server in resposne to a switchboard
invitation.
=item IRO -- Initial Roster
Sent from switchboard to client upon connection to a switchboard
server informing client of other users attached to that switchboard
session.
=item CAL -- Call
Sent from client to switchboard to invite another user to join the
switchboard session.
=item OUT -- Out
Async command sent from client to NS/DS/SB server to terminate their session.
=item NLN -- Online
Async command sent from NS to client to advise of another user coming online.
=item FLN -- Offline
Async command sent from NS to client to advise of another user going offline.
=item PNG -- Ping
Async command sent from client to NS to make sure it is still there.
=item QNG -- Pong
Async command sent from NS to client to acknowledge its presence.
=item RNG -- Ring
Async command sent from NS to client to advise of another user inviting you to a Switchboard Session.
=item JOI -- Join
Async command sent from SB to client to advise of another user joining a Switchboard Session.
=item BYE -- Bye
Async command sent from SB to client to advise of another user leaving a Switchboard Session.
=back
=head1 COMMAND FORMATS
Commands sent in the protocols come in three (and a theoretically
possible fourth) variants. This library refers to them as Normal,
Async, and Payload.
=head2 NORMAL COMMANDS
The vast bulk of commands are Normal, and each
one is tagged with a numeric identifier by the client. This
identifier will be used by the server to correlate its responses to
your requests. This library does not currently verify any of these
transaction identifiers (TRIDs), but does send each command with a
unique monotonically-increasing number. Library users can feel free
to use the TRID in Normal messages as a unique identifier, within the
rules of the protocol. (That is: Sometimes a single Normal command
from client to server will result in many related responses, all of
which will contain the TRID of that single request).
=head2 ASYNC COMMANDS
Another block of commands are those sent from server to client in
resposne to asyncronous events, such as users in your Forward List
changing their status, invitations by other users to Switchboard
Sessions, and users joining and leaving Switchboard Sessions.
=head2 PAYLOAD COMMANDS
The final type of command is that which contains message data. This
library only (currently) supports one, the MSG command, which is used
to encapsulate messages from server to client, and peer to peer.
=head1 ASYNCRONOUS INPUT
The library user is responsible for dealing with non-blocking IO, and
there are several ways you might do this. If you are writing a
Perl/Tk you would probably use fileevent, or you might want to use
Joshua Pritikin's Event package (which I use), or you can roll your
own with select and poll. You could even use alarm and signals to
periodically sweep all of the inbound sessions.
To help you with this, there are a pair of handlers in the
Net::Msmgr::Session object, $session->connect_handler, and
$session->disconnect_handler - which are called just after the TCP
connect() call and just before the TCP close() call respectively.
Each of these will be called with a single pointer to the Net::Msmgr::Connection object.
It is the users' responsibility to call $connection->_recv_message
whenever input is available on $connection->socket.
With Tk this would be something like
sub Connect_handler
{
my $connection = shift;
$mainwindow->fileevent($connection->socket,
'readable',
sub { $connection->_recv_message });
}
$session->connect_hanlder(\&Connect_handler);
$session->Login;
MainLoop;
Under Joshua Pritikin's Event package, you might use
our %watcher;
sub ConnectHandler
{
my ($connection) = @_;
my $socket = $connection->socket;
$watcher{$connection} = Event->io(fd => $socket,
cb => [ $connection , '_recv_message' ],
poll => 're',
desc => 'recv_watcher',
repeat => 1);
}
sub DisconnectHandler
{
my $connection = shift;
$watcher{$connection}->cancel;
}
$session->connect_handler(\&ConnectHandler);
$session->disconnect_handler(\&DisconnectHandler);
A third handler Net::Msmgr::Session::switchboard_handler() will be called
with a Net::Msmgr::Connection object and an ssid for each switchboard session
you are invited to, or instantiate through
Net::Msmgr::Session::ui_new_switchboard().
=cut
#
# $Log: Msmgr.pm,v $
# Revision 0.16 2003/08/07 00:01:59 lawrence
# Initial Release
#
#