Permalink
Browse files

Fixed and tested offline message retrieval support as well as missed …

…messages notifications.

Fixed 'im' event parameters and added 'missed' event to test program.
  • Loading branch information...
1 parent dbfadd8 commit b936829d041b656f95e9e91f795974b122276fd0 @mscdex committed Jan 29, 2011
Showing with 48 additions and 25 deletions.
  1. +0 −4 TODO
  2. +30 −16 oscar.js
  3. +18 −5 test.js
View
4 TODO
@@ -2,10 +2,6 @@
- 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
- If requesting a new service and our main connection is SSL, add empty TLV 0x8C to the service request.
View
@@ -567,7 +567,7 @@ OscarConnection.prototype.getIcon = function(who, metaData, cb) {
};
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
)
));
@@ -1605,24 +1605,27 @@ OscarConnection.prototype._parseSNAC = function(conn, snac, cb) {
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;
- if (tlvs[0x04])
+ if (keys.indexOf(0x04) > -1)
flags |= ICBM_MSG_FLAGS.AWAY;
- if (tlvs[0x06]) {
+ if (keys.indexOf(0x06) > -1) {
flags |= ICBM_MSG_FLAGS.OFFLINE;
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]) {
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],
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)
flags |= ICBM_MSG_FLAGS.HAS_ICON;
}
- if (tlvs[0x09]) {
+ if (keys.indexOf(0x09) > -1) {
flags |= ICBM_MSG_FLAGS.REQ_ICON;
self._sendIcon(sender.name); // automatically send our icon if we have one set
}
@@ -1703,8 +1706,8 @@ OscarConnection.prototype._parseSNAC = function(conn, snac, cb) {
while (idx < len) {
channel = (snac[idx++] << 8) + snac[idx++];
sender = self._parseUserInfo(snac, idx, true);
- idx = sender[0];
- sender = sender[1];
+ idx = sender[1];
+ sender = sender[0];
numMissed = (snac[idx++] << 8) + snac[idx++];
reason = (snac[idx++] << 8) + snac[idx++];
self.emit('missed', sender, numMissed, reason, channel);
@@ -2697,16 +2700,20 @@ OscarConnection.prototype._login = function(error, conn, loginCb, reentry) {
// * min msg interval === 0 seconds
if ((!conn.neededServices || typeof conn.neededServices[SNAC_SERVICES.ICBM] !== 'undefined')
&& conn.availServices[SNAC_SERVICES.ICBM]) {
- var warnRecv = self._state.svcInfo[SNAC_SERVICES.ICBM].maxReceiverWarn,// \
- warnSend = 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
- | ICBM_FLAGS.EVENTS_ALLOWED | ICBM_FLAGS.SMS_SUPPORTED | ICBM_FLAGS.OFFLINE_MSGS_ALLOWED
+ var warnRecv = 0xE703,//self._state.svcInfo[SNAC_SERVICES.ICBM].maxReceiverWarn,// \
+ 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
+ | ICBM_FLAGS.EVENTS_ALLOWED
+ | ICBM_FLAGS.SMS_SUPPORTED
+ | ICBM_FLAGS.OFFLINE_MSGS_ALLOWED
| ICBM_FLAGS.USE_HTML_FOR_ICQ;
self._send(self._createFLAP(conn, FLAP_CHANNELS.SNAC,
self._createSNAC(SNAC_SERVICES.ICBM, 0x02, NO_FLAGS,
[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),
- 0x00, 0x00, 0x03, 0xE8]
+ 0x00, 0x00, 0x00, 0x00]
)
));
}
@@ -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),
(flags >> 8 & 0xFF), (flags & 0xFF), (reqID >> 24 & 0xFF), (reqID >> 16 & 0xFF), (reqID >> 8 & 0xFF), (reqID & 0xFF)].concat(value);
};
@@ -3543,4 +3555,6 @@ exports.USER_CLASSES = USER_CLASSES;
exports.CAPABILITIES = CAPABILITIES;
exports.SSI_RESULTS = SSI_ACK_RESULTS;
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;
View
23 test.js
@@ -18,10 +18,18 @@ aim.on('typing', function(who, type) {
type = 'closed the IM';
console.log('test.js :: typing notification: ' + who + ' ' + type);
});
-aim.on('im', function(text, sender, warnLevel, flags, when) {
- console.log('test.js :: received IM from ' + sender.name + '(' + warnLevel + '): ' + text);
+aim.on('im', function(text, sender, flags, when) {
+ 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.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) {
var status = 'other';
if (user.idleMins)
@@ -30,7 +38,8 @@ aim.on('contactonline', function(user) {
status = 'available';
else if (user.status === oscar.USER_STATUSES.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) {
var status = 'other';
@@ -40,7 +49,8 @@ aim.on('contactupdate', function(user) {
status = 'available';
else if (user.status === oscar.USER_STATUSES.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) {
console.log('test.js :: ' + user.name + ' is now offline');
@@ -51,6 +61,9 @@ aim.on('icon', function(who, icon, size) {
aim.connect(function(err) {
if (err)
console.log('test.js :: Encountered error: ' + err);
- else
+ else {
console.log('test.js :: ready!');
+ // automatically check for offline messages
+ aim.getOfflineMsgs();
+ }
});

0 comments on commit b936829

Please sign in to comment.