Skip to content

Commit

Permalink
Fixed and tested offline message retrieval support as well as missed …
Browse files Browse the repository at this point in the history
…messages notifications.

Fixed 'im' event parameters and added 'missed' event to test program.
  • Loading branch information
mscdex committed Jan 29, 2011
1 parent dbfadd8 commit b936829
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 25 deletions.
4 changes: 0 additions & 4 deletions TODO
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@


- ICQ testing and debugging (don't even bother trying it yet) - ICQ testing and debugging (don't even bother trying it yet)


- Improve error messages -- check for subcodes, etc.

- Offline message support (code is there, but isn't fully tested yet)

- Secure connection support - Secure connection support


- If requesting a new service and our main connection is SSL, add empty TLV 0x8C to the service request. - If requesting a new service and our main connection is SSL, add empty TLV 0x8C to the service request.
Expand Down
46 changes: 30 additions & 16 deletions oscar.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ OscarConnection.prototype.getIcon = function(who, metaData, cb) {
}; };


OscarConnection.prototype.getOfflineMsgs = function() { OscarConnection.prototype.getOfflineMsgs = function() {
this._send(this._createFLAP(self._state.connections.main, FLAP_CHANNELS.SNAC, this._send(this._createFLAP(this._state.connections.main, FLAP_CHANNELS.SNAC,
this._createSNAC(SNAC_SERVICES.ICBM, 0x10, NO_FLAGS this._createSNAC(SNAC_SERVICES.ICBM, 0x10, NO_FLAGS
) )
)); ));
Expand Down Expand Up @@ -1605,24 +1605,27 @@ OscarConnection.prototype._parseSNAC = function(conn, snac, cb) {
break; break;
} }
} }
if (tlvs[0x03]) // must check keys since TLV values are set to undefined
// for zero-length TLVs
var keys = Object.keys(tlvs).map(function(x){return parseInt(x)});
if (keys.indexOf(0x03) > -1)
flags |= ICBM_MSG_FLAGS.ACK; flags |= ICBM_MSG_FLAGS.ACK;
if (tlvs[0x04]) if (keys.indexOf(0x04) > -1)
flags |= ICBM_MSG_FLAGS.AWAY; flags |= ICBM_MSG_FLAGS.AWAY;
if (tlvs[0x06]) { if (keys.indexOf(0x06) > -1) {
flags |= ICBM_MSG_FLAGS.OFFLINE; flags |= ICBM_MSG_FLAGS.OFFLINE;
if (tlvs[0x16]) // _should_ always be set for offline messages if (tlvs[0x16]) // _should_ always be set for offline messages
datetime = new Date((tlvs[0x16][0] << 24) + (tlvs[0x16][1] << 16) + (tlvs[0x16][2] << 8) + tlvs[0x16][3]); datetime = new Date(((tlvs[0x16][0] << 24) + (tlvs[0x16][1] << 16) + (tlvs[0x16][2] << 8) + tlvs[0x16][3]) * 1000);
} }
if (tlvs[0x08]) { if (tlvs[0x08]) {
var len = (tlvs[0x08][0] << 24) + (tlvs[0x08][1] << 16) + (tlvs[0x08][2] << 8) + tlvs[0x08][3], var len = (tlvs[0x08][0] << 24) + (tlvs[0x08][1] << 16) + (tlvs[0x08][2] << 8) + tlvs[0x08][3],
type = (tlvs[0x08][4] << 8) + tlvs[0x08][5], type = (tlvs[0x08][4] << 8) + tlvs[0x08][5],
hash = (tlvs[0x08][6] << 8) + tlvs[0x08][7], // a constant 2 bytes for a hash??? hash = (tlvs[0x08][6] << 8) + tlvs[0x08][7], // a constant 2 bytes for a hash???
datetime = (tlvs[0x08][8] << 24) + (tlvs[0x08][9] << 16) + (tlvs[0x08][10] << 8) + tlvs[0x08][11] icndatetime = ((tlvs[0x08][8] << 24) + (tlvs[0x08][9] << 16) + (tlvs[0x08][10] << 8) + tlvs[0x08][11]) * 1000;
if (len) if (len)
flags |= ICBM_MSG_FLAGS.HAS_ICON; flags |= ICBM_MSG_FLAGS.HAS_ICON;
} }
if (tlvs[0x09]) { if (keys.indexOf(0x09) > -1) {
flags |= ICBM_MSG_FLAGS.REQ_ICON; flags |= ICBM_MSG_FLAGS.REQ_ICON;
self._sendIcon(sender.name); // automatically send our icon if we have one set self._sendIcon(sender.name); // automatically send our icon if we have one set
} }
Expand Down Expand Up @@ -1703,8 +1706,8 @@ OscarConnection.prototype._parseSNAC = function(conn, snac, cb) {
while (idx < len) { while (idx < len) {
channel = (snac[idx++] << 8) + snac[idx++]; channel = (snac[idx++] << 8) + snac[idx++];
sender = self._parseUserInfo(snac, idx, true); sender = self._parseUserInfo(snac, idx, true);
idx = sender[0]; idx = sender[1];
sender = sender[1]; sender = sender[0];
numMissed = (snac[idx++] << 8) + snac[idx++]; numMissed = (snac[idx++] << 8) + snac[idx++];
reason = (snac[idx++] << 8) + snac[idx++]; reason = (snac[idx++] << 8) + snac[idx++];
self.emit('missed', sender, numMissed, reason, channel); self.emit('missed', sender, numMissed, reason, channel);
Expand Down Expand Up @@ -2697,16 +2700,20 @@ OscarConnection.prototype._login = function(error, conn, loginCb, reentry) {
// * min msg interval === 0 seconds // * min msg interval === 0 seconds
if ((!conn.neededServices || typeof conn.neededServices[SNAC_SERVICES.ICBM] !== 'undefined') if ((!conn.neededServices || typeof conn.neededServices[SNAC_SERVICES.ICBM] !== 'undefined')
&& conn.availServices[SNAC_SERVICES.ICBM]) { && conn.availServices[SNAC_SERVICES.ICBM]) {
var warnRecv = self._state.svcInfo[SNAC_SERVICES.ICBM].maxReceiverWarn,// \ var warnRecv = 0xE703,//self._state.svcInfo[SNAC_SERVICES.ICBM].maxReceiverWarn,// \
warnSend = self._state.svcInfo[SNAC_SERVICES.ICBM].maxSenderWarn, // -- use defaults for these warnSend = 0x8403,//self._state.svcInfo[SNAC_SERVICES.ICBM].maxSenderWarn, // -- use defaults for these
flags = ICBM_FLAGS.CHANNEL_MSGS_ALLOWED | ICBM_FLAGS.MISSED_CALLS_ENABLED | ICBM_FLAGS.TYPING_NOTIFICATIONS flags = ICBM_FLAGS.CHANNEL_MSGS_ALLOWED
| ICBM_FLAGS.EVENTS_ALLOWED | ICBM_FLAGS.SMS_SUPPORTED | ICBM_FLAGS.OFFLINE_MSGS_ALLOWED | ICBM_FLAGS.MISSED_CALLS_ENABLED
| ICBM_FLAGS.TYPING_NOTIFICATIONS
| ICBM_FLAGS.EVENTS_ALLOWED
| ICBM_FLAGS.SMS_SUPPORTED
| ICBM_FLAGS.OFFLINE_MSGS_ALLOWED
| ICBM_FLAGS.USE_HTML_FOR_ICQ; | ICBM_FLAGS.USE_HTML_FOR_ICQ;
self._send(self._createFLAP(conn, FLAP_CHANNELS.SNAC, self._send(self._createFLAP(conn, FLAP_CHANNELS.SNAC,
self._createSNAC(SNAC_SERVICES.ICBM, 0x02, NO_FLAGS, self._createSNAC(SNAC_SERVICES.ICBM, 0x02, NO_FLAGS,
[0x00, 0x00, (flags >> 24 & 0xFF), (flags >> 16 & 0xFF), (flags >> 8 & 0xFF), (flags & 0xFF), 0x1F, 0x40, [0x00, 0x00, (flags >> 24 & 0xFF), (flags >> 16 & 0xFF), (flags >> 8 & 0xFF), (flags & 0xFF), 0x1F, 0x40,
(warnSend >> 8 & 0xFF), (warnSend & 0xFF), (warnRecv >> 8 & 0xFF), (warnRecv & 0xFF), (warnSend >> 8 & 0xFF), (warnSend & 0xFF), (warnRecv >> 8 & 0xFF), (warnRecv & 0xFF),
0x00, 0x00, 0x03, 0xE8] 0x00, 0x00, 0x00, 0x00]
) )
)); ));
} }
Expand Down Expand Up @@ -2850,7 +2857,12 @@ OscarConnection.prototype._createSNAC = function(serviceID, subtypeID, flags, va
} }
} }
} }
var reqID = this._state.reqID = (this._state.reqID === 0x7FFFFFFF ? 1 : this._state.reqID + 1); var reqID;
// HACK: Retrieving offline messages requires a SNAC request ID of 0 (??!)
if (serviceID === SNAC_SERVICES.ICBM && subtypeID === 0x10)
reqID = 0;
else
reqID = this._state.reqID = (this._state.reqID === 0x7FFFFFFF ? 1 : this._state.reqID + 1);
return [(serviceID >> 8 & 0xFF), (serviceID & 0xFF), (subtypeID >> 8 & 0xFF), (subtypeID & 0xFF), return [(serviceID >> 8 & 0xFF), (serviceID & 0xFF), (subtypeID >> 8 & 0xFF), (subtypeID & 0xFF),
(flags >> 8 & 0xFF), (flags & 0xFF), (reqID >> 24 & 0xFF), (reqID >> 16 & 0xFF), (reqID >> 8 & 0xFF), (reqID & 0xFF)].concat(value); (flags >> 8 & 0xFF), (flags & 0xFF), (reqID >> 24 & 0xFF), (reqID >> 16 & 0xFF), (reqID >> 8 & 0xFF), (reqID & 0xFF)].concat(value);
}; };
Expand Down Expand Up @@ -3543,4 +3555,6 @@ exports.USER_CLASSES = USER_CLASSES;
exports.CAPABILITIES = CAPABILITIES; exports.CAPABILITIES = CAPABILITIES;
exports.SSI_RESULTS = SSI_ACK_RESULTS; exports.SSI_RESULTS = SSI_ACK_RESULTS;
exports.TYPING_NOTIFY = TYPING_NOTIFY; exports.TYPING_NOTIFY = TYPING_NOTIFY;
exports.MOTD_TYPES = MOTD_TYPES; exports.MOTD_TYPES = MOTD_TYPES;
exports.IM_FLAGS = ICBM_MSG_FLAGS;
exports.IM_MISSED_REASONS = ICBM_MISSED_REASONS;
23 changes: 18 additions & 5 deletions test.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -18,10 +18,18 @@ aim.on('typing', function(who, type) {
type = 'closed the IM'; type = 'closed the IM';
console.log('test.js :: typing notification: ' + who + ' ' + type); console.log('test.js :: typing notification: ' + who + ' ' + type);
}); });
aim.on('im', function(text, sender, warnLevel, flags, when) { aim.on('im', function(text, sender, flags, when) {
console.log('test.js :: received IM from ' + sender.name + '(' + warnLevel + '): ' + text); console.log('test.js :: received ' + (when ? 'offline ' : '')
+ 'IM from ' + sender.name + (when ? ' (on ' + when + ')' : '')
+ ': ' + text);
if (when)
return;
aim.sendIM(sender.name, 'I got your IM!'); aim.sendIM(sender.name, 'I got your IM!');
}); });
aim.on('missed', function(sender, numMissed, reason, channel) {
console.log('test.js :: missed ' + numMissed + ' messages from ' + sender.name
+ '. Reason: ' + reason + '. Channel: ' + channel);
});
aim.on('contactonline', function(user) { aim.on('contactonline', function(user) {
var status = 'other'; var status = 'other';
if (user.idleMins) if (user.idleMins)
Expand All @@ -30,7 +38,8 @@ aim.on('contactonline', function(user) {
status = 'available'; status = 'available';
else if (user.status === oscar.USER_STATUSES.AWAY) else if (user.status === oscar.USER_STATUSES.AWAY)
status = 'away'; status = 'away';
console.log('test.js :: ' + user.name + ' is now online and ' + status + (user.statusMsg ? ': ' + user.statusMsg : '')); console.log('test.js :: ' + user.name + ' is now online and ' + status
+ (user.statusMsg ? ': ' + user.statusMsg : ''));
}); });
aim.on('contactupdate', function(user) { aim.on('contactupdate', function(user) {
var status = 'other'; var status = 'other';
Expand All @@ -40,7 +49,8 @@ aim.on('contactupdate', function(user) {
status = 'available'; status = 'available';
else if (user.status === oscar.USER_STATUSES.AWAY) else if (user.status === oscar.USER_STATUSES.AWAY)
status = 'away'; status = 'away';
console.log('test.js :: ' + user.name + ' is now ' + status + (user.statusMsg ? ': ' + user.statusMsg : '')); console.log('test.js :: ' + user.name + ' is now ' + status
+ (user.statusMsg ? ': ' + user.statusMsg : ''));
}); });
aim.on('contactoffline', function(user) { aim.on('contactoffline', function(user) {
console.log('test.js :: ' + user.name + ' is now offline'); console.log('test.js :: ' + user.name + ' is now offline');
Expand All @@ -51,6 +61,9 @@ aim.on('icon', function(who, icon, size) {
aim.connect(function(err) { aim.connect(function(err) {
if (err) if (err)
console.log('test.js :: Encountered error: ' + err); console.log('test.js :: Encountered error: ' + err);
else else {
console.log('test.js :: ready!'); console.log('test.js :: ready!');
// automatically check for offline messages
aim.getOfflineMsgs();
}
}); });

0 comments on commit b936829

Please sign in to comment.