From Chris Wilson:
[obnox/wireshark/wip.git] / packet-aim.c
1 /* packet-aim.c
2  * Routines for AIM Instant Messenger (OSCAR) dissection
3  * Copyright 2000, Ralf Hoelzer <ralf@well.com>
4  *
5  * $Id: packet-aim.c,v 1.31 2003/12/21 11:40:45 jmayer Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34
35 #include <glib.h>
36
37 #include <epan/packet.h>
38 #include <epan/strutil.h>
39
40 #include "packet-tcp.h"
41 #include "prefs.h"
42
43 #define TCP_PORT_AIM 5190
44 #define MAX_BUDDYNAME_LENGTH 30
45
46 #define STRIP_TAGS 1
47
48 typedef struct _aim_tlv {
49   guint16 valueid;
50   char *desc;
51   int datatype;
52 } aim_tlv;
53
54 /* channels */
55 #define CHANNEL_NEW_CONN    0x01
56 #define CHANNEL_SNAC_DATA   0x02
57 #define CHANNEL_FLAP_ERR    0x03
58 #define CHANNEL_CLOSE_CONN  0x04
59
60 /* SNAC families */
61 #define FAMILY_GENERIC    0x0001
62 #define FAMILY_LOCATION   0x0002
63 #define FAMILY_BUDDYLIST  0x0003
64 #define FAMILY_MESSAGING  0x0004
65 #define FAMILY_ADVERTS    0x0005
66 #define FAMILY_INVITATION 0x0006
67 #define FAMILY_ADMIN      0x0007
68 #define FAMILY_POPUP      0x0008
69 #define FAMILY_BOS        0x0009
70 #define FAMILY_USERLOOKUP 0x000A
71 #define FAMILY_STATS      0x000B
72 #define FAMILY_TRANSLATE  0x000C
73 #define FAMILY_CHAT_NAV   0x000D
74 #define FAMILY_CHAT       0x000E
75 #define FAMILY_SSI        0x0013
76 #define FAMILY_ICQ        0x0015
77 #define FAMILY_SIGNON     0x0017
78 #define FAMILY_OFT        0xfffe
79
80 /* Family Signon */
81 #define FAMILY_SIGNON_LOGON          0x0002
82 #define FAMILY_SIGNON_LOGON_REPLY    0x0003
83 #define FAMILY_SIGNON_SIGNON         0x0006
84 #define FAMILY_SIGNON_SIGNON_REPLY   0x0007
85
86 /* Family Generic */
87 #define FAMILY_GENERIC_ERROR          0x0001
88 #define FAMILY_GENERIC_CLIENTREADY    0x0002
89 #define FAMILY_GENERIC_SERVERREADY    0x0003
90 #define FAMILY_GENERIC_SERVICEREQ     0x0004
91 #define FAMILY_GENERIC_REDIRECT       0x0005
92 #define FAMILY_GENERIC_RATEINFOREQ    0x0006
93 #define FAMILY_GENERIC_RATEINFO       0x0007
94 #define FAMILY_GENERIC_RATEINFOACK    0x0008
95 #define FAMILY_GENERIC_UNKNOWNx09     0x0009
96 #define FAMILY_GENERIC_RATECHANGE     0x000a
97 #define FAMILY_GENERIC_SERVERPAUSE    0x000b
98 #define FAMILY_GENERIC_SERVERRESUME   0x000d
99 #define FAMILY_GENERIC_REQSELFINFO    0x000e
100 #define FAMILY_GENERIC_SELFINFO       0x000f
101 #define FAMILY_GENERIC_EVIL           0x0010
102 #define FAMILY_GENERIC_SETIDLE        0x0011
103 #define FAMILY_GENERIC_MIGRATIONREQ   0x0012
104 #define FAMILY_GENERIC_MOTD           0x0013
105 #define FAMILY_GENERIC_SETPRIVFLAGS   0x0014
106 #define FAMILY_GENERIC_WELLKNOWNURL   0x0015
107 #define FAMILY_GENERIC_NOP            0x0016
108 #define FAMILY_GENERIC_DEFAULT        0xffff
109
110 /* Family Location Services */
111 #define FAMILY_LOCATION_ERROR         0x0001
112 #define FAMILY_LOCATION_REQRIGHTS     0x0002
113 #define FAMILY_LOCATION_RIGHTSINFO    0x0003
114 #define FAMILY_LOCATION_SETUSERINFO   0x0004
115 #define FAMILY_LOCATION_REQUSERINFO   0x0005
116 #define FAMILY_LOCATION_USERINFO      0x0006
117 #define FAMILY_LOCATION_WATCHERSUBREQ 0x0007
118 #define FAMILY_LOCATION_WATCHERNOT    0x0008
119 #define FAMILY_LOCATION_DEFAULT       0xffff
120
121 /* Family Buddy List */
122 #define FAMILY_BUDDYLIST_ERROR        0x0001
123 #define FAMILY_BUDDYLIST_REQRIGHTS    0x0002
124 #define FAMILY_BUDDYLIST_RIGHTSINFO   0x0003
125 #define FAMILY_BUDDYLIST_ADDBUDDY     0x0004
126 #define FAMILY_BUDDYLIST_REMBUDDY     0x0005
127 #define FAMILY_BUDDYLIST_REJECT       0x000a
128 #define FAMILY_BUDDYLIST_ONCOMING     0x000b
129 #define FAMILY_BUDDYLIST_OFFGOING     0x000c
130 #define FAMILY_BUDDYLIST_DEFAULT      0xffff
131
132 /* Family Messaging Service */
133 #define FAMILY_MESSAGING_ERROR          0x0001
134 #define FAMILY_MESSAGING_PARAMINFO      0x0005
135 #define FAMILY_MESSAGING_OUTGOING       0x0006
136 #define FAMILY_MESSAGING_INCOMING       0x0007
137 #define FAMILY_MESSAGING_EVIL           0x0009
138 #define FAMILY_MESSAGING_MISSEDCALL     0x000a
139 #define FAMILY_MESSAGING_CLIENTAUTORESP 0x000b
140 #define FAMILY_MESSAGING_ACK            0x000c
141 #define FAMILY_MESSAGING_DEFAULT        0xffff
142
143 /* Family Advertising */
144 #define FAMILY_ADVERTS_ERROR          0x0001
145 #define FAMILY_ADVERTS_REQUEST        0x0002
146 #define FAMILY_ADVERTS_DATA           0x0003
147 #define FAMILY_ADVERTS_DEFAULT        0xffff
148
149 /* Family Invitation */
150 #define FAMILY_INVITATION_ERROR       0x0001
151 #define FAMILY_INVITATION_DEFAULT     0xffff
152
153 /* Family Admin */
154 #define FAMILY_ADMIN_ERROR            0x0001
155 #define FAMILY_ADMIN_INFOCHANGEREPLY  0x0005
156 #define FAMILY_ADMIN_DEFAULT          0xffff
157
158 /* Family Popup */
159 #define FAMILY_POPUP_ERROR            0x0001
160 #define FAMILY_POPUP_DEFAULT          0xffff
161
162 /* Family BOS (Misc) */
163 #define FAMILY_BOS_ERROR              0x0001
164 #define FAMILY_BOS_RIGHTSQUERY        0x0002
165 #define FAMILY_BOS_RIGHTS             0x0003
166 #define FAMILY_BOS_DEFAULT            0xffff
167
168 /* Family User Lookup */
169 #define FAMILY_USERLOOKUP_ERROR        0x0001
170 #define FAMILY_USERLOOKUP_SEARCHEMAIL  0x0002
171 #define FAMILY_USERLOOKUP_SEARCHRESULT 0x0003
172 #define FAMILY_USERLOOKUP_DEFAULT      0xffff
173
174 /* Family User Stats */
175 #define FAMILY_STATS_ERROR             0x0001
176 #define FAMILY_STATS_SETREPORTINTERVAL 0x0002
177 #define FAMILY_STATS_REPORTACK         0x0004
178 #define FAMILY_STATS_DEFAULT           0xffff
179
180 /* Family Translation */
181 #define FAMILY_TRANSLATE_ERROR        0x0001
182 #define FAMILY_TRANSLATE_DEFAULT      0xffff
183
184 /* Family Chat Navigation */
185 #define FAMILY_CHATNAV_ERROR          0x0001
186 #define FAMILY_CHATNAV_CREATE         0x0008
187 #define FAMILY_CHATNAV_INFO           0x0009
188 #define FAMILY_CHATNAV_DEFAULT        0xffff
189
190 /* Family Chat */
191 #define FAMILY_CHAT_ERROR             0x0001
192 #define FAMILY_CHAT_ROOMINFOUPDATE    0x0002
193 #define FAMILY_CHAT_USERJOIN          0x0003
194 #define FAMILY_CHAT_USERLEAVE         0x0004
195 #define FAMILY_CHAT_OUTGOINGMSG       0x0005
196 #define FAMILY_CHAT_INCOMINGMSG       0x0006
197 #define FAMILY_CHAT_DEFAULT           0xffff
198
199 /* Family Server-Stored Buddy Lists */
200 #define FAMILY_SSI_ERROR              0x0001
201 #define FAMILY_SSI_REQRIGHTS          0x0002
202 #define FAMILY_SSI_RIGHTSINFO         0x0003
203 #define FAMILY_SSI_REQLIST            0x0005
204 #define FAMILY_SSI_LIST               0x0006
205 #define FAMILY_SSI_ACTIVATE           0x0007
206 #define FAMILY_SSI_ADD                0x0008
207 #define FAMILY_SSI_MOD                0x0009
208 #define FAMILY_SSI_DEL                0x000a
209 #define FAMILY_SSI_SRVACK             0x000e
210 #define FAMILY_SSI_NOLIST             0x000f
211 #define FAMILY_SSI_EDITSTART          0x0011
212 #define FAMILY_SSI_EDITSTOP           0x0012
213
214 /* Family ICQ */
215 #define FAMILY_ICQ_ERROR              0x0001
216 #define FAMILY_ICQ_LOGINREQUEST       0x0002
217 #define FAMILY_ICQ_LOGINRESPONSE      0x0003
218 #define FAMILY_ICQ_AUTHREQUEST        0x0006
219 #define FAMILY_ICQ_AUTHRESPONSE       0x0007
220
221 static const value_string aim_fnac_family_ids[] = {
222   { FAMILY_GENERIC, "Generic" }, 
223   { FAMILY_LOCATION, "Location" },
224   { FAMILY_BUDDYLIST, "Buddy List" },
225   { FAMILY_MESSAGING, "Messaging" },
226   { FAMILY_ADVERTS, "Advertisement" },
227   { FAMILY_INVITATION, "Invitation" },
228   { FAMILY_ADMIN, "Admin" },
229   { FAMILY_POPUP, "Popup" },
230   { FAMILY_BOS, "Bos" },
231   { FAMILY_USERLOOKUP, "User Lookup" },
232   { FAMILY_STATS, "Stats" },
233   { FAMILY_TRANSLATE, "Translate" },
234   { FAMILY_CHAT_NAV, "Chat Nav" },
235   { FAMILY_CHAT, "Chat" },
236   { FAMILY_SSI, "Server Stored Info" },
237   { FAMILY_ICQ, "ICQ" },
238   { FAMILY_SIGNON, "Sign-on" },
239   { FAMILY_OFT, "OFT/Rvous" },
240   { 0, NULL }
241 };
242
243 static const value_string aim_fnac_family_signon[] = {
244   { FAMILY_SIGNON_LOGON, "Logon" },
245   { FAMILY_SIGNON_LOGON_REPLY, "Logon Reply" },
246   { FAMILY_SIGNON_SIGNON, "Sign-on" },
247   { FAMILY_SIGNON_SIGNON_REPLY, "Sign-on Reply" },
248   { 0, NULL }
249 };
250
251 static const value_string aim_fnac_family_generic[] = {
252   { FAMILY_GENERIC_ERROR, "Error" },
253   { FAMILY_GENERIC_CLIENTREADY , "Client Ready" },
254   { FAMILY_GENERIC_SERVERREADY, "Server Ready" },
255   { FAMILY_GENERIC_SERVICEREQ, "Service Req" },
256   { FAMILY_GENERIC_REDIRECT, "Redirect" },
257   { FAMILY_GENERIC_RATEINFOREQ, "Rate Info Req" },
258   { FAMILY_GENERIC_RATEINFO, "Rate Info" },
259   { FAMILY_GENERIC_RATEINFOACK, "Rate Info Ack" },
260   { FAMILY_GENERIC_UNKNOWNx09, "Unknown" },
261   { FAMILY_GENERIC_RATECHANGE, "Rate Change" },
262   { FAMILY_GENERIC_SERVERPAUSE, "Server Pause" },
263   { FAMILY_GENERIC_SERVERRESUME, "Server Resume" },
264   { FAMILY_GENERIC_REQSELFINFO, "Self Info Req" },
265   { FAMILY_GENERIC_SELFINFO, "Self Info" },
266   { FAMILY_GENERIC_EVIL, "Evil" },
267   { FAMILY_GENERIC_SETIDLE, "Set Idle" },
268   { FAMILY_GENERIC_MIGRATIONREQ, "Migration Req" },
269   { FAMILY_GENERIC_MOTD, "MOTD" },
270   { FAMILY_GENERIC_SETPRIVFLAGS, "Set Privilege Flags" },
271   { FAMILY_GENERIC_WELLKNOWNURL, "Well Known URL" },
272   { FAMILY_GENERIC_NOP, "noop" },
273   { FAMILY_GENERIC_DEFAULT, "Generic Default" },
274   { 0, NULL }
275 };
276
277 static const value_string aim_fnac_family_location[] = {
278   { FAMILY_LOCATION_ERROR, "Error" },
279   { FAMILY_LOCATION_REQRIGHTS, "Request Rights" },
280   { FAMILY_LOCATION_RIGHTSINFO, "Rights Info" },
281   { FAMILY_LOCATION_SETUSERINFO, "Set User Info" },
282   { FAMILY_LOCATION_REQUSERINFO, "Request User Info" },
283   { FAMILY_LOCATION_USERINFO, "User Info" },
284   { FAMILY_LOCATION_WATCHERSUBREQ, "Watcher Subrequest" },
285   { FAMILY_LOCATION_WATCHERNOT, "Watcher Notification" },
286   { FAMILY_LOCATION_DEFAULT, "Location Default" },
287   { 0, NULL }
288 };
289
290 static const value_string aim_fnac_family_buddylist[] = {
291   { FAMILY_BUDDYLIST_ERROR, "Error" },
292   { FAMILY_BUDDYLIST_REQRIGHTS, "Request Rights" },
293   { FAMILY_BUDDYLIST_RIGHTSINFO, "Rights Info" },
294   { FAMILY_BUDDYLIST_ADDBUDDY, "Add Buddy" },
295   { FAMILY_BUDDYLIST_REMBUDDY, "Remove Buddy" },
296   { FAMILY_BUDDYLIST_REJECT, "Reject Buddy" }, 
297   { FAMILY_BUDDYLIST_ONCOMING, "Oncoming Buddy" },
298   { FAMILY_BUDDYLIST_OFFGOING, "Offgoing Buddy" },
299   { FAMILY_BUDDYLIST_DEFAULT, "Buddy Default" },
300   { 0, NULL }
301 };
302
303 static const value_string aim_fnac_family_messaging[] = {
304   { FAMILY_MESSAGING_ERROR, "Error" },
305   { FAMILY_MESSAGING_PARAMINFO, "Parameter Info" },
306   { FAMILY_MESSAGING_INCOMING, "Incoming" },
307   { FAMILY_MESSAGING_EVIL, "Evil" },
308   { FAMILY_MESSAGING_MISSEDCALL, "Missed Call" },
309   { FAMILY_MESSAGING_CLIENTAUTORESP, "Client Auto Response" },
310   { FAMILY_MESSAGING_ACK, "Acknowledge" },
311   { FAMILY_MESSAGING_DEFAULT, "Messaging Default" },
312   { 0, NULL }
313 };
314
315 static const value_string aim_fnac_family_adverts[] = {
316   { FAMILY_ADVERTS_ERROR, "Error" },
317   { FAMILY_ADVERTS_REQUEST, "Request" },
318   { FAMILY_ADVERTS_DATA, "Data (GIF)" },
319   { FAMILY_ADVERTS_DEFAULT, "Adverts Default" },
320   { 0, NULL }
321 };
322
323 static const value_string aim_fnac_family_invitation[] = {
324   { FAMILY_INVITATION_ERROR, "Error" },
325   { FAMILY_INVITATION_DEFAULT, "Invitation Default" },
326   { 0, NULL }
327 };
328
329 static const value_string aim_fnac_family_admin[] = {
330   { FAMILY_ADMIN_ERROR, "Error" },
331   { FAMILY_ADMIN_INFOCHANGEREPLY, "Infochange reply" },
332   { FAMILY_ADMIN_DEFAULT, "Adminstrative Default" },
333   { 0, NULL }
334 };
335
336 static const value_string aim_fnac_family_popup[] = {
337   { FAMILY_POPUP_ERROR, "Error" },
338   { FAMILY_POPUP_DEFAULT, "Popup Default" },
339   { 0, NULL }
340 };
341
342 static const value_string aim_fnac_family_bos[] = {
343   { FAMILY_BOS_ERROR, "Error" },
344   { FAMILY_BOS_RIGHTSQUERY, "Rights Query" },
345   { FAMILY_BOS_RIGHTS, "Rights" },
346   { FAMILY_BOS_DEFAULT, "BOS Default" },
347   { 0, NULL }
348 };
349
350 static const value_string aim_fnac_family_userlookup[] = {
351   { FAMILY_USERLOOKUP_ERROR, "Error" },
352   { FAMILY_USERLOOKUP_DEFAULT, "Userlookup Default" },
353   { 0, NULL }
354 };
355
356 static const value_string aim_fnac_family_stats[] = {
357   { FAMILY_STATS_ERROR, "Error" },
358   { FAMILY_STATS_SETREPORTINTERVAL, "Set Report Interval" },
359   { FAMILY_STATS_REPORTACK, "Report Ack" },
360   { FAMILY_STATS_DEFAULT, "Stats Default" },
361   { 0, NULL }
362 };
363
364 static const value_string aim_fnac_family_translate[] = {
365   { FAMILY_TRANSLATE_ERROR, "Error" },
366   { FAMILY_TRANSLATE_DEFAULT, "Translate Default" },
367   { 0, NULL }
368 };
369
370 static const value_string aim_fnac_family_chatnav[] = {
371   { FAMILY_CHATNAV_ERROR, "Error" },
372   { FAMILY_CHATNAV_CREATE, "Create" },
373   { FAMILY_CHATNAV_INFO, "Info" },
374   { FAMILY_CHATNAV_DEFAULT, "ChatNav Default" },
375   { 0, NULL }
376 };
377
378 static const value_string aim_fnac_family_chat[] = {
379   { FAMILY_CHAT_ERROR, "Error" },
380   { FAMILY_CHAT_USERJOIN, "User Join" },
381   { FAMILY_CHAT_USERLEAVE, "User Leave" },
382   { FAMILY_CHAT_OUTGOINGMSG, "Outgoing Message" },
383   { FAMILY_CHAT_INCOMINGMSG, "Incoming Message" },
384   { FAMILY_CHAT_DEFAULT, "Chat Default" },
385   { 0, NULL }
386 };
387
388 static const value_string aim_fnac_family_ssi[] = {
389   { FAMILY_SSI_ERROR, "Error" },
390   { FAMILY_SSI_REQRIGHTS, "Request Rights" },
391   { FAMILY_SSI_RIGHTSINFO, "Rights Info" },
392   { FAMILY_SSI_REQLIST, "Request List" },
393   { FAMILY_SSI_LIST, "List" },
394   { FAMILY_SSI_ACTIVATE, "Activate" },
395   { FAMILY_SSI_ADD, "Add Buddy" },
396   { FAMILY_SSI_MOD, "Modify Buddy" },
397   { FAMILY_SSI_DEL, "Delete Buddy" },
398   { FAMILY_SSI_SRVACK, "Server Ack" },
399   { FAMILY_SSI_NOLIST, "No List" },
400   { FAMILY_SSI_EDITSTART, "Edit Start" },
401   { FAMILY_SSI_EDITSTOP, "Edit Stop" },
402   { 0, NULL }
403 };
404
405 #define FAMILY_SSI_TYPE_BUDDY         0x0000
406 #define FAMILY_SSI_TYPE_GROUP         0x0001
407 #define FAMILY_SSI_TYPE_PERMIT        0x0002
408 #define FAMILY_SSI_TYPE_DENY          0x0003
409 #define FAMILY_SSI_TYPE_PDINFO        0x0004
410 #define FAMILY_SSI_TYPE_PRESENCEPREFS 0x0005
411 #define FAMILY_SSI_TYPE_ICONINFO      0x0014
412
413 static const value_string aim_fnac_family_ssi_types[] = {
414   { FAMILY_SSI_TYPE_BUDDY, "Buddy" },
415   { FAMILY_SSI_TYPE_GROUP, "Group" },
416   { FAMILY_SSI_TYPE_PERMIT, "Permit" },
417   { FAMILY_SSI_TYPE_DENY, "Deny" },
418   { FAMILY_SSI_TYPE_PDINFO, "PDINFO" },
419   { FAMILY_SSI_TYPE_PRESENCEPREFS, "Presence Preferences" },
420   { FAMILY_SSI_TYPE_ICONINFO, "Icon Info" },
421   { 0, NULL }
422 };
423
424 static const value_string aim_fnac_family_icq[] = {
425   { FAMILY_ICQ_ERROR, "Error" },
426   { FAMILY_ICQ_LOGINREQUEST, "Login Request" },
427   { FAMILY_ICQ_LOGINRESPONSE, "Login Response" },
428   { FAMILY_ICQ_AUTHREQUEST, "Auth Request" },
429   { FAMILY_ICQ_AUTHRESPONSE, "Auth Response" },
430   { 0, NULL }
431 };
432
433 #define SIGNON_SCREENNAME     0x0001
434 #define SIGNON_PASSWORD       0x0025
435 #define SIGNON_CLIENTSTRING   0x0003
436 #define SIGNON_CLIENTMAJOR    0x0017
437 #define SIGNON_CLIENTMINOR    0x0018
438 #define SIGNON_CLIENTPOINT    0x0019
439 #define SIGNON_CLIENTBUILD    0x001a
440 #define SIGNON_CLIENTCOUNTRY  0x000e
441 #define SIGNON_CLIENTLANGUAGE 0x000f
442 #define SIGNON_CLIENTUSESSI   0x004a
443
444 static const aim_tlv aim_signon_signon_tlv[] = {
445   { SIGNON_SCREENNAME, "Screen Name", FT_STRING },
446   { SIGNON_PASSWORD, "Signon Challenge Response", FT_BYTES },
447   { SIGNON_CLIENTSTRING, "Login Request", FT_STRING },
448   { SIGNON_CLIENTMAJOR, "Client Major Version", FT_UINT16 },
449   { SIGNON_CLIENTMINOR, "Client Minor Version", FT_UINT16 },
450   { SIGNON_CLIENTPOINT, "Client Point", FT_UINT16 },
451   { SIGNON_CLIENTBUILD, "Client Build", FT_UINT16 },
452   { SIGNON_CLIENTCOUNTRY, "Client Country", FT_STRING },
453   { SIGNON_CLIENTLANGUAGE, "Client Language", FT_STRING },
454   { SIGNON_CLIENTUSESSI, "Use SSI", FT_UINT8 },
455   { 0, "Unknown", 0 }
456 };
457
458 #define SIGNON_LOGON_REPLY_SCREENNAME          0x0001
459 #define SIGNON_LOGON_REPLY_ERRORURL            0x0004
460 #define SIGNON_LOGON_REPLY_BOSADDR             0x0005
461 #define SIGNON_LOGON_REPLY_AUTHCOOKIE          0x0006
462 #define SIGNON_LOGON_REPLY_ERRORCODE           0x0008
463 #define SIGNON_LOGON_REPLY_EMAILADDR           0x0011
464 #define SIGNON_LOGON_REPLY_REGSTATUS           0x0013
465 #define SIGNON_LOGON_REPLY_LATESTBETABUILD     0x0040
466 #define SIGNON_LOGON_REPLY_LATESTBETAURL       0x0041
467 #define SIGNON_LOGON_REPLY_LATESTBETAINFO      0x0042
468 #define SIGNON_LOGON_REPLY_LATESTBETANAME      0x0043
469 #define SIGNON_LOGON_REPLY_LATESTRELEASEBUILD  0x0044
470 #define SIGNON_LOGON_REPLY_LATESTRELEASEURL    0x0045
471 #define SIGNON_LOGON_REPLY_LATESTRELEASEINFO   0x0046
472 #define SIGNON_LOGON_REPLY_LATESTRELEASENAME   0x0047
473
474 static const aim_tlv aim_signon_logon_reply_tlv[] = {
475   { SIGNON_LOGON_REPLY_SCREENNAME, "Screen Name", FT_STRING },
476   { SIGNON_LOGON_REPLY_ERRORURL, "Error URL", FT_STRING },
477   { SIGNON_LOGON_REPLY_BOSADDR, "BOS Server Address", FT_STRING },
478   { SIGNON_LOGON_REPLY_AUTHCOOKIE, "Authorization Cookie", FT_BYTES },
479   { SIGNON_LOGON_REPLY_ERRORCODE, "Error Code", FT_UINT16 },
480   { SIGNON_LOGON_REPLY_EMAILADDR, "Account Email Address", FT_STRING },
481   { SIGNON_LOGON_REPLY_REGSTATUS, "Registration Status", FT_UINT16 },
482   { SIGNON_LOGON_REPLY_LATESTBETABUILD, "Latest Beta Build", FT_UINT32 },
483   { SIGNON_LOGON_REPLY_LATESTBETAURL, "Latest Beta URL", FT_STRING },
484   { SIGNON_LOGON_REPLY_LATESTBETAINFO, "Latest Beta Info", FT_STRING },
485   { SIGNON_LOGON_REPLY_LATESTBETANAME, "Latest Beta Name", FT_STRING },
486   { SIGNON_LOGON_REPLY_LATESTRELEASEBUILD, "Latest Release Build", FT_UINT32 },
487   { SIGNON_LOGON_REPLY_LATESTRELEASEURL, "Latest Release URL", FT_STRING },
488   { SIGNON_LOGON_REPLY_LATESTRELEASEINFO, "Latest Release Info", FT_STRING },
489   { SIGNON_LOGON_REPLY_LATESTRELEASENAME, "Latest Release Name", FT_STRING },
490   { 0, "Unknown", 0 }
491 };
492
493 #define FAMILY_BUDDYLIST_USERFLAGS      0x0001
494 #define FAMILY_BUDDYLIST_MEMBERSINCE    0x0002
495 #define FAMILY_BUDDYLIST_ONSINCE        0x0003
496 #define FAMILY_BUDDYLIST_IDLETIME       0x0004
497 #define FAMILY_BUDDYLIST_ICQSTATUS      0x0006
498 #define FAMILY_BUDDYLIST_ICQIPADDR      0x000a
499 #define FAMILY_BUDDYLIST_ICQSTUFF       0x000c
500 #define FAMILY_BUDDYLIST_CAPINFO        0x000d
501 #define FAMILY_BUDDYLIST_UNKNOWN        0x000e
502 #define FAMILY_BUDDYLIST_SESSIONLEN     0x000f
503 #define FAMILY_BUDDYLIST_ICQSESSIONLEN  0x0010
504
505 static const aim_tlv aim_fnac_family_buddylist_oncoming_tlv[] = {
506   { FAMILY_BUDDYLIST_USERFLAGS, "User flags", FT_UINT16 },
507   { FAMILY_BUDDYLIST_MEMBERSINCE, "Member since date", FT_UINT32 },
508   { FAMILY_BUDDYLIST_ONSINCE, "Online since", FT_UINT32 },
509   { FAMILY_BUDDYLIST_IDLETIME, "Idle time (sec)", FT_UINT16 },
510   { FAMILY_BUDDYLIST_ICQSTATUS, "ICQ Online status", FT_UINT16 },
511   { FAMILY_BUDDYLIST_ICQIPADDR, "ICQ User IP Address", FT_UINT16 },
512   { FAMILY_BUDDYLIST_ICQSTUFF, "ICQ Info", FT_BYTES },
513   { FAMILY_BUDDYLIST_CAPINFO, "Capability Info", FT_BYTES },
514   { FAMILY_BUDDYLIST_UNKNOWN, "Unknown", FT_UINT16 },
515   { FAMILY_BUDDYLIST_SESSIONLEN, "Session Length (sec)", FT_UINT32 },
516   { FAMILY_BUDDYLIST_SESSIONLEN, "ICQ Session Length (sec)", FT_UINT32 },
517   { 0, "Unknown", 0 }
518 };
519
520
521 #define FAMILY_LOCATION_USERINFO_INFOENCODING  0x0001
522 #define FAMILY_LOCATION_USERINFO_INFOMSG       0x0002
523 #define FAMILY_LOCATION_USERINFO_AWAYENCODING  0x0003
524 #define FAMILY_LOCATION_USERINFO_AWAYMSG       0x0004
525 #define FAMILY_LOCATION_USERINFO_CAPS          0x0005
526
527 static const aim_tlv aim_fnac_family_location_userinfo_tlv[] = {
528   { FAMILY_LOCATION_USERINFO_INFOENCODING, "Info Msg Encoding", FT_STRING },
529   { FAMILY_LOCATION_USERINFO_INFOMSG, "Info Message", FT_STRING },
530   { FAMILY_LOCATION_USERINFO_AWAYENCODING, "Away Msg Encoding", FT_STRING },
531   { FAMILY_LOCATION_USERINFO_AWAYMSG, "Away Message", FT_STRING },
532   { FAMILY_LOCATION_USERINFO_CAPS, "Capabilities", FT_BYTES },
533   { 0, "Unknown", 0 }
534 };
535
536 #define FAMILY_LOCATION_USERINFO_INFOTYPE_GENERALINFO  0x0001
537 #define FAMILY_LOCATION_USERINFO_INFOTYPE_AWAYMSG      0x0003
538 #define FAMILY_LOCATION_USERINFO_INFOTYPE_CAPS         0x0005
539
540 static const value_string aim_snac_location_request_user_info_infotypes[] = {
541   { FAMILY_LOCATION_USERINFO_INFOTYPE_GENERALINFO, "Request General Info" },
542   { FAMILY_LOCATION_USERINFO_INFOTYPE_AWAYMSG, "Request Away Message" },
543   { FAMILY_LOCATION_USERINFO_INFOTYPE_CAPS, "Request Capabilities" },
544   { 0, NULL }
545 };
546
547 static int dissect_aim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
548 static guint get_aim_pdu_len(tvbuff_t *tvb, int offset);
549 static void dissect_aim_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
550
551 static void get_message( guchar *msg, tvbuff_t *tvb, int msg_offset, int msg_length);
552 static int get_buddyname( char *name, tvbuff_t *tvb, int len_offset, int name_offset);
553 static void dissect_aim_newconn(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree);
554 static void dissect_aim_snac(tvbuff_t *tvb, packet_info *pinfo, 
555                              int offset, proto_tree *tree);
556 static void dissect_aim_snac_fnac_subtype(tvbuff_t *tvb, int offset, 
557                                           proto_tree *tree, guint16 family);
558 static void dissect_aim_snac_signon(tvbuff_t *tvb, packet_info *pinfo, 
559                                     int offset, proto_tree *tree, 
560                                     guint16 subtype);
561 static void dissect_aim_snac_signon_logon(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree);
562 static void dissect_aim_snac_signon_logon_reply(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree);
563 static void dissect_aim_snac_signon_signon(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree);
564 static void dissect_aim_snac_signon_signon_reply(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree);
565 static void dissect_aim_snac_generic(tvbuff_t *tvb, packet_info *pinfo, 
566                                      int offset, proto_tree *tree, 
567                                      guint16 subtype);
568 static void dissect_aim_snac_buddylist(tvbuff_t *tvb, packet_info *pinfo, 
569                                        int offset, proto_tree *tree, 
570                                        guint16 subtype);
571 static void dissect_aim_snac_location(tvbuff_t *tvb, packet_info *pinfo, 
572                                       int offset, proto_tree *tree, 
573                                       guint16 subtype);
574 static void dissect_aim_snac_location_request_user_information(tvbuff_t *tvb, int offset, proto_tree *tree);
575 static void dissect_aim_snac_location_user_information(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree);
576 static void dissect_aim_snac_adverts(tvbuff_t *tvb, packet_info *pinfo, 
577                                      int offset, proto_tree *tree, 
578                                      guint16 subtype);
579 static void dissect_aim_snac_userlookup(tvbuff_t *tvb, packet_info *pinfo, 
580                                         int offset, proto_tree *tree, 
581                                         guint16 subtype);
582 static void dissect_aim_snac_chat(tvbuff_t *tvb, packet_info *pinfo, 
583                                   int offset, proto_tree *tree, 
584                                   guint16 subtype);
585 static void dissect_aim_snac_messaging(tvbuff_t *tvb, packet_info *pinfo, 
586                                        int offset, proto_tree *tree, 
587                                        guint16 subtype);
588 static void dissect_aim_snac_ssi(tvbuff_t *tvb, packet_info *pinfo, 
589                                  int offset, proto_tree *tree, 
590                                  guint16 subtype);
591 static void dissect_aim_snac_ssi_list(tvbuff_t *tvb, packet_info *pinfo _U_, 
592                                       int offset, proto_tree *tree, 
593                                       guint16 subtype _U_);
594 static void dissect_aim_flap_err(tvbuff_t *tvb, packet_info *pinfo, 
595                                  int offset, proto_tree *tree);
596 static void dissect_aim_close_conn(tvbuff_t *tvb, packet_info *pinfo, 
597                                    int offset, proto_tree *tree);
598 static void dissect_aim_unknown_channel(tvbuff_t *tvb, packet_info *pinfo, 
599                                         int offset, proto_tree *tree);
600 static int dissect_aim_tlv(tvbuff_t *tvb, packet_info *pinfo, 
601                            int offset, proto_tree *tree, const aim_tlv *tlv);
602
603 /* Initialize the protocol and registered fields */
604 static int proto_aim = -1;
605 static int hf_aim_cmd_start = -1;
606 static int hf_aim_channel = -1;
607 static int hf_aim_seqno = -1;
608 static int hf_aim_data = -1;
609 static int hf_aim_data_len = -1;
610 static int hf_aim_signon_challenge_len = -1;
611 static int hf_aim_signon_challenge = -1;
612 static int hf_aim_fnac_family = -1;
613 static int hf_aim_fnac_subtype = -1;
614 static int hf_aim_fnac_subtype_signon = -1;
615 static int hf_aim_fnac_subtype_generic = -1;
616 static int hf_aim_fnac_subtype_location = -1;
617 static int hf_aim_fnac_subtype_buddylist = -1;
618 static int hf_aim_fnac_subtype_messaging = -1;
619 static int hf_aim_fnac_subtype_adverts = -1;
620 static int hf_aim_fnac_subtype_invitation = -1;
621 static int hf_aim_fnac_subtype_admin = -1;
622 static int hf_aim_fnac_subtype_popup = -1;
623 static int hf_aim_fnac_subtype_bos = -1;
624 static int hf_aim_fnac_subtype_userlookup = -1;
625 static int hf_aim_fnac_subtype_stats = -1;
626 static int hf_aim_fnac_subtype_translate = -1;
627 static int hf_aim_fnac_subtype_chatnav = -1;
628 static int hf_aim_fnac_subtype_chat = -1;
629 static int hf_aim_fnac_subtype_ssi = -1;
630 static int hf_aim_fnac_subtype_ssi_version = -1;
631 static int hf_aim_fnac_subtype_ssi_numitems = -1;
632 static int hf_aim_fnac_subtype_ssi_buddyname_len = -1;
633 static int hf_aim_fnac_subtype_ssi_buddyname = -1;
634 static int hf_aim_fnac_subtype_ssi_gid = -1;
635 static int hf_aim_fnac_subtype_ssi_bid = -1;
636 static int hf_aim_fnac_subtype_ssi_type = -1;
637 static int hf_aim_fnac_subtype_ssi_tlvlen = -1;
638 static int hf_aim_fnac_subtype_ssi_data = -1;
639 static int hf_aim_fnac_subtype_icq = -1;
640 static int hf_aim_fnac_flags = -1;
641 static int hf_aim_fnac_id = -1;
642 static int hf_aim_infotype = -1;
643 static int hf_aim_snac_location_request_user_info_infotype = -1;
644 static int hf_aim_buddyname_len = -1;
645 static int hf_aim_buddyname = -1;
646 static int hf_aim_userinfo_warninglevel = -1;
647 static int hf_aim_userinfo_tlvcount = -1;
648
649 /* Initialize the subtree pointers */
650 static gint ett_aim          = -1;
651 static gint ett_aim_fnac     = -1;
652 static gint ett_aim_tlv      = -1;
653 static gint ett_aim_ssi      = -1;
654
655 /* desegmentation of AIM over TCP */
656 static gboolean aim_desegment = TRUE;
657
658 /* Code to actually dissect the packets */
659 static int dissect_aim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
660 {
661 /* check, if this is really an AIM packet, they start with 0x2a */
662 /* XXX - I've seen some stuff starting with 0x5a followed by 0x2a */
663
664   if(tvb_bytes_exist(tvb, 0, 1) && tvb_get_guint8(tvb, 0) != 0x2a) {
665     /* Not an instant messenger packet, just happened to use the same port */
666     /* XXX - if desegmentation disabled, this might be a continuation
667        packet, not a non-AIM packet */
668     return 0;
669   }
670
671   tcp_dissect_pdus(tvb, pinfo, tree, aim_desegment, 6, get_aim_pdu_len,
672         dissect_aim_pdu);
673   return tvb_length(tvb);
674 }
675
676 static guint get_aim_pdu_len(tvbuff_t *tvb, int offset)
677 {
678   guint16 plen;
679
680   /*
681    * Get the length of the AIM packet.
682    */
683   plen = tvb_get_ntohs(tvb, offset + 4);
684
685   /*
686    * That length doesn't include the length of the header itself; add that in.
687    */
688   return plen + 6;
689 }
690
691 static void dissect_aim_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
692 {
693   /* Header fields */
694   unsigned char  hdr_channel;           /* channel ID */
695   unsigned short hdr_sequence_no;       /* Internal frame sequence number, not needed */
696   unsigned short hdr_data_field_length; /* length of data within frame */
697
698   int offset=0;
699
700 /* Set up structures we will need to add the protocol subtree and manage it */
701   proto_item *ti;
702   proto_tree *aim_tree = NULL;
703
704 /* Make entries in Protocol column and Info column on summary display */
705   if (check_col(pinfo->cinfo, COL_PROTOCOL))
706     col_set_str(pinfo->cinfo, COL_PROTOCOL, "AIM");
707
708   if (check_col(pinfo->cinfo, COL_INFO))
709     col_add_str(pinfo->cinfo, COL_INFO, "AOL Instant Messenger");
710
711   /* get relevant header information */
712   offset += 1;          /* XXX - put the identifier into the tree? */   
713   hdr_channel           = tvb_get_guint8(tvb, offset);
714   offset += 1;
715   hdr_sequence_no       = tvb_get_ntohs(tvb, offset);
716   offset += 2;
717   hdr_data_field_length = tvb_get_ntohs(tvb, offset);
718   offset += 2;
719
720 /* In the interest of speed, if "tree" is NULL, don't do any work not
721    necessary to generate protocol tree items. */
722   if (tree) {
723
724     ti = proto_tree_add_item(tree, proto_aim, tvb, 0, -1, FALSE);
725     aim_tree = proto_item_add_subtree(ti, ett_aim);
726     proto_tree_add_uint(aim_tree, hf_aim_cmd_start, tvb, 0, 1, '*');
727     proto_tree_add_uint(aim_tree, hf_aim_channel, tvb, 1, 1, hdr_channel);
728     proto_tree_add_uint(aim_tree, hf_aim_seqno, tvb, 2, 2, hdr_sequence_no);
729     proto_tree_add_uint(aim_tree, hf_aim_data_len, tvb, 4, 2, hdr_data_field_length);
730
731   }
732
733   switch(hdr_channel)
734   {
735     /* New connection request */
736     case CHANNEL_NEW_CONN:
737       dissect_aim_newconn(tvb, pinfo, offset, aim_tree);
738       break;
739     case CHANNEL_SNAC_DATA:
740       dissect_aim_snac(tvb, pinfo, offset, aim_tree);
741       break;
742     case CHANNEL_FLAP_ERR:
743       dissect_aim_flap_err(tvb, pinfo, offset, aim_tree);
744       break;
745     case CHANNEL_CLOSE_CONN:
746       dissect_aim_close_conn(tvb, pinfo, offset, aim_tree);
747       break;
748     default:
749       dissect_aim_unknown_channel(tvb, pinfo, offset, aim_tree);
750       break;
751   }
752
753 }
754
755
756 static int get_buddyname( char *name, tvbuff_t *tvb, int len_offset, int name_offset)
757 {
758   guint8 buddyname_length;
759
760   buddyname_length = tvb_get_guint8(tvb, len_offset);
761
762   if(buddyname_length > MAX_BUDDYNAME_LENGTH ) buddyname_length = MAX_BUDDYNAME_LENGTH;
763   tvb_get_nstringz0(tvb, name_offset, buddyname_length + 1, name);
764
765   return buddyname_length;
766 }
767
768
769 static void get_message( guchar *msg, tvbuff_t *tvb, int msg_offset, int msg_length)
770 {
771   int i,j,c;
772   int bracket = FALSE;
773   int max, tagchars = 0;
774   int new_offset = msg_offset;
775   int new_length = msg_length;
776
777
778
779   /* make sure nothing bigger than 1000 bytes is printed */
780   if( msg_length > 999 ) return;
781
782   memset( msg, '\0', 1000);
783   i = 0;
784   c = 0;
785
786   /* loop until HTML tag is reached - quick&dirty way to find start of message
787    * (it is nearly impossible to find the correct start offset for all client versions) */
788   while( (tagchars < 6) && (new_length > 5) )
789   {
790      j = tvb_get_guint8(tvb, new_offset);
791      if( ( (j == '<') && (tagchars == 0) ) ||
792          ( (j == 'h') && (tagchars == 1) ) ||
793          ( (j == 'H') && (tagchars == 1) ) ||
794          ( (j == 't') && (tagchars == 2) ) ||
795          ( (j == 'T') && (tagchars == 2) ) ||
796          ( (j == 'm') && (tagchars == 3) ) ||
797          ( (j == 'M') && (tagchars == 3) ) ||
798          ( (j == 'l') && (tagchars == 4) ) ||
799          ( (j == 'L') && (tagchars == 4) ) ||
800          ( (j == '>') && (tagchars == 5) ) ) tagchars++;
801      new_offset++;
802      new_length--;
803   }
804
805   /* set offset and length of message to after the first HTML tag */
806   msg_offset = new_offset;
807   msg_length = new_length;
808   max = msg_length - 1;
809   tagchars = 0;
810
811   /* find the rest of the message until either a </html> is reached or the end of the frame.
812    * All other HTML tags are stripped to display only the raw message (printable characters) */
813   while( (c < max) && (tagchars < 7) )
814   {
815      j = tvb_get_guint8(tvb, msg_offset+c);
816
817
818      /* make sure this is an HTML tag by checking the order of the chars */
819      if( ( (j == '<') && (tagchars == 0) ) ||
820          ( (j == '/') && (tagchars == 1) ) ||
821          ( (j == 'h') && (tagchars == 2) ) ||
822          ( (j == 'H') && (tagchars == 2) ) ||
823          ( (j == 't') && (tagchars == 3) ) ||
824          ( (j == 'T') && (tagchars == 3) ) ||
825          ( (j == 'm') && (tagchars == 4) ) ||
826          ( (j == 'M') && (tagchars == 4) ) ||
827          ( (j == 'l') && (tagchars == 5) ) ||
828          ( (j == 'L') && (tagchars == 5) ) ||
829          ( (j == '>') && (tagchars == 6) ) ) tagchars++;
830
831 #ifdef STRIP_TAGS
832      if( j == '<' ) bracket = TRUE;
833      if( j == '>' ) bracket = FALSE;
834      if( (isprint(j) ) && (bracket == FALSE) && (j != '>'))
835 #else
836      if( isprint(j) )
837 #endif
838      {
839        msg[i] = j;
840        i++;
841      }
842      c++;
843   }
844 }
845
846 static void dissect_aim_newconn(tvbuff_t *tvb, packet_info *pinfo, 
847                                 int offset, proto_tree *tree)
848 {
849   if (check_col(pinfo->cinfo, COL_INFO)) 
850     col_add_fstr(pinfo->cinfo, COL_INFO, "New Connection");
851   if (tvb_length_remaining(tvb, offset) > 0)
852     proto_tree_add_item(tree, hf_aim_data, tvb, offset, -1, FALSE);
853 }
854
855 static void dissect_aim_snac(tvbuff_t *tvb, packet_info *pinfo, 
856                              int offset, proto_tree *aim_tree)
857 {
858   guint16 family;
859   guint16 subtype;
860   guint16 flags;
861   guint32 id;
862   proto_item *ti1;
863   proto_tree *aim_tree_fnac = NULL;
864   int orig_offset;
865
866   orig_offset = offset;
867   family = tvb_get_ntohs(tvb, offset);
868   offset += 2;
869   subtype = tvb_get_ntohs(tvb, offset);
870   offset += 2;
871   flags = tvb_get_ntohs(tvb, offset);
872   offset += 2;
873   id = tvb_get_ntohl(tvb, offset);
874   offset += 4;
875   
876   if (check_col(pinfo->cinfo, COL_INFO)) {
877     col_add_fstr(pinfo->cinfo, COL_INFO, "SNAC data");
878   }
879   if( aim_tree )
880     {
881       offset = orig_offset;
882       ti1 = proto_tree_add_text(aim_tree, tvb, 6, 10, "FNAC");
883       aim_tree_fnac = proto_item_add_subtree(ti1, ett_aim_fnac);
884
885       proto_tree_add_item (aim_tree_fnac, hf_aim_fnac_family,
886                            tvb, offset, 2, FALSE);
887       offset += 2;
888
889       /* Dissect the subtype based on the family */
890       dissect_aim_snac_fnac_subtype(tvb, offset, aim_tree_fnac, family);
891       offset += 2;
892
893       proto_tree_add_uint(aim_tree_fnac, hf_aim_fnac_flags, tvb, offset, 
894                           2, flags);
895       offset += 2;
896       proto_tree_add_uint(aim_tree_fnac, hf_aim_fnac_id, tvb, offset,
897                           4, id);
898       offset += 4;
899     }
900
901   if (check_col(pinfo->cinfo, COL_INFO))
902     col_append_fstr(pinfo->cinfo, COL_INFO, ", Family: %s",
903                     val_to_str(family, aim_fnac_family_ids,
904                                "Unknown Family ID=0x%04x"));
905   
906   switch(family)
907     {
908     case FAMILY_SIGNON:
909       dissect_aim_snac_signon(tvb, pinfo, offset, aim_tree, subtype);
910       break;
911     case FAMILY_GENERIC:
912       dissect_aim_snac_generic(tvb, pinfo, offset, aim_tree, subtype);
913       break;
914     case FAMILY_BUDDYLIST:
915       dissect_aim_snac_buddylist(tvb, pinfo, offset, aim_tree, subtype);
916       break;
917     case FAMILY_LOCATION:
918       dissect_aim_snac_location(tvb, pinfo, offset, aim_tree, subtype);
919       break;
920     case FAMILY_ADVERTS:
921       dissect_aim_snac_adverts(tvb, pinfo, offset, aim_tree, subtype);
922       break;
923     case FAMILY_USERLOOKUP:
924       dissect_aim_snac_userlookup(tvb, pinfo, offset, aim_tree, subtype);
925       break;
926     case FAMILY_CHAT:
927       dissect_aim_snac_chat(tvb, pinfo, offset, aim_tree, subtype);
928       break;
929     case FAMILY_MESSAGING:
930       dissect_aim_snac_messaging(tvb, pinfo, offset, aim_tree, subtype);
931       break;
932     case FAMILY_SSI:
933       dissect_aim_snac_ssi(tvb, pinfo, offset, aim_tree, subtype);
934       break;
935     }
936 }
937
938 static void dissect_aim_snac_signon(tvbuff_t *tvb, packet_info *pinfo, 
939                                     int offset, proto_tree *tree, 
940                                     guint16 subtype)
941 {
942   switch(subtype)
943     {
944     case FAMILY_SIGNON_LOGON:
945       dissect_aim_snac_signon_logon(tvb, pinfo, offset, tree);
946       break;
947     case FAMILY_SIGNON_LOGON_REPLY:
948       dissect_aim_snac_signon_logon_reply(tvb, pinfo, offset, tree);
949       break;
950     case FAMILY_SIGNON_SIGNON:
951       dissect_aim_snac_signon_signon(tvb, pinfo, offset, tree);
952       break;
953     case FAMILY_SIGNON_SIGNON_REPLY:
954       dissect_aim_snac_signon_signon_reply(tvb, pinfo, offset, tree);
955       break;
956     }
957 }
958
959 static void dissect_aim_snac_signon_logon(tvbuff_t *tvb, packet_info *pinfo, 
960                                           int offset, proto_tree *tree)
961 {
962   while (tvb_length_remaining(tvb, offset) > 0) {
963     offset = dissect_aim_tlv(tvb, pinfo, offset, tree, aim_signon_signon_tlv);
964   }
965 }
966
967 static void dissect_aim_snac_signon_logon_reply(tvbuff_t *tvb, 
968                                                 packet_info *pinfo, 
969                                                 int offset, proto_tree *tree)
970 {
971     if (check_col(pinfo->cinfo, COL_INFO)) 
972       col_append_fstr(pinfo->cinfo, COL_INFO, ", Login information reply");
973
974     while (tvb_length_remaining(tvb, offset) > 0) {
975       offset = dissect_aim_tlv(tvb, pinfo, offset, tree, 
976                                aim_signon_logon_reply_tlv);
977     }
978 }
979
980 static void dissect_aim_snac_signon_signon(tvbuff_t *tvb, packet_info *pinfo, 
981                                            int offset, proto_tree *tree)
982 {
983   guint8 buddyname_length = 0;
984   char buddyname[MAX_BUDDYNAME_LENGTH + 1];
985
986   /* Info Type */
987   proto_tree_add_item(tree, hf_aim_infotype, tvb, offset, 2, FALSE);
988   offset += 2;
989
990   /* Unknown */
991   offset += 1;
992
993   /* Buddy Name */
994   buddyname_length = get_buddyname( buddyname, tvb, offset, offset + 1 );
995   
996   if (check_col(pinfo->cinfo, COL_INFO)) {
997     col_append_fstr(pinfo->cinfo, COL_INFO, " Username: %s", buddyname);
998   }
999   
1000   if(tree) {
1001     proto_tree_add_text(tree, tvb, offset + 1, buddyname_length, 
1002                         "Screen Name: %s", buddyname);
1003   }
1004   
1005   offset += buddyname_length + 1;
1006 }
1007
1008 static void dissect_aim_snac_signon_signon_reply(tvbuff_t *tvb, 
1009                                                  packet_info *pinfo, 
1010                                                  int offset, proto_tree *tree)
1011 {
1012   guint16 challenge_length = 0;
1013
1014   if (check_col(pinfo->cinfo, COL_INFO)) 
1015     col_append_fstr(pinfo->cinfo, COL_INFO, ", Sign-on reply");
1016
1017   /* Logon Challenge Length */
1018   challenge_length = tvb_get_ntohs(tvb, offset);
1019   proto_tree_add_item(tree, hf_aim_signon_challenge_len, tvb, offset, 2, FALSE);
1020   offset += 2;
1021
1022   /* Challenge */
1023   proto_tree_add_item(tree, hf_aim_signon_challenge, tvb, offset, challenge_length, FALSE);
1024   offset += challenge_length;
1025 }
1026
1027 static void dissect_aim_snac_generic(tvbuff_t *tvb, packet_info *pinfo, 
1028                                     int offset, proto_tree *tree, 
1029                                     guint16 subtype)
1030 {
1031   switch(subtype)
1032     {
1033     case FAMILY_GENERIC_ERROR:
1034       if (check_col(pinfo->cinfo, COL_INFO)) 
1035         col_add_fstr(pinfo->cinfo, COL_INFO, "Generic Error");
1036       break;
1037     case FAMILY_GENERIC_CLIENTREADY:
1038       if (check_col(pinfo->cinfo, COL_INFO)) 
1039         col_add_fstr(pinfo->cinfo, COL_INFO, 
1040                      "Client is now online and ready for normal function");
1041       break;
1042     case FAMILY_GENERIC_SERVERREADY:
1043       if (check_col(pinfo->cinfo, COL_INFO)) 
1044         col_add_fstr(pinfo->cinfo, COL_INFO, 
1045                      "Server is now ready for normal functions");
1046       break;
1047     case FAMILY_GENERIC_SERVICEREQ:
1048       if (check_col(pinfo->cinfo, COL_INFO)) 
1049         col_add_fstr(pinfo->cinfo, COL_INFO, 
1050                      "Request for new service (server will redirect client)");
1051       break;
1052     case FAMILY_GENERIC_REDIRECT:
1053       if (check_col(pinfo->cinfo, COL_INFO)) 
1054         col_add_fstr(pinfo->cinfo, COL_INFO, "Redirect response");
1055       break;
1056     case FAMILY_GENERIC_RATEINFOREQ:
1057       if (check_col(pinfo->cinfo, COL_INFO)) 
1058         col_add_fstr(pinfo->cinfo, COL_INFO, "Request Rate Information");
1059       break;
1060     case FAMILY_GENERIC_RATEINFO:
1061       if (check_col(pinfo->cinfo, COL_INFO)) 
1062         col_add_fstr(pinfo->cinfo, COL_INFO, "Rate information response");
1063       break;
1064     case FAMILY_GENERIC_RATEINFOACK:
1065       if (check_col(pinfo->cinfo, COL_INFO))
1066         col_add_fstr(pinfo->cinfo, COL_INFO, "Rate Information Response Ack");
1067       break;
1068     case FAMILY_GENERIC_RATECHANGE:
1069       if (check_col(pinfo->cinfo, COL_INFO))
1070         col_add_fstr(pinfo->cinfo, COL_INFO, "Rate Change");
1071       break;
1072     case FAMILY_GENERIC_SERVERPAUSE:
1073       if (check_col(pinfo->cinfo, COL_INFO))
1074         col_add_fstr(pinfo->cinfo, COL_INFO, "Server Pause");
1075       break;
1076     case FAMILY_GENERIC_SERVERRESUME:
1077       if (check_col(pinfo->cinfo, COL_INFO))
1078         col_add_fstr(pinfo->cinfo, COL_INFO, "Server Resume");
1079       break;
1080     case FAMILY_GENERIC_REQSELFINFO:
1081       if (check_col(pinfo->cinfo, COL_INFO))
1082         col_add_fstr(pinfo->cinfo, COL_INFO, "Request Self Info");
1083       break;
1084     case FAMILY_GENERIC_SELFINFO:
1085       if (check_col(pinfo->cinfo, COL_INFO))
1086         col_add_fstr(pinfo->cinfo, COL_INFO, "Self Info");
1087       break;
1088     case FAMILY_GENERIC_EVIL:
1089       if (check_col(pinfo->cinfo, COL_INFO))
1090         col_add_fstr(pinfo->cinfo, COL_INFO, "Evil");
1091       break;
1092     case FAMILY_GENERIC_SETIDLE:
1093       if (check_col(pinfo->cinfo, COL_INFO))
1094         col_add_fstr(pinfo->cinfo, COL_INFO, "Set Idle");
1095       break;
1096     case FAMILY_GENERIC_MIGRATIONREQ:
1097       if (check_col(pinfo->cinfo, COL_INFO))
1098         col_add_fstr(pinfo->cinfo, COL_INFO, "Request Migration");
1099       break;
1100     case FAMILY_GENERIC_MOTD:
1101       if (check_col(pinfo->cinfo, COL_INFO))
1102         col_add_fstr(pinfo->cinfo, COL_INFO, "MOTD");
1103       break;
1104     case FAMILY_GENERIC_SETPRIVFLAGS:
1105       if (check_col(pinfo->cinfo, COL_INFO))
1106         col_add_fstr(pinfo->cinfo, COL_INFO, "Set Privilege Flags");
1107       break;
1108     case FAMILY_GENERIC_WELLKNOWNURL:
1109       if (check_col(pinfo->cinfo, COL_INFO))
1110         col_add_fstr(pinfo->cinfo, COL_INFO, "Well Known URL");
1111       break;
1112     case FAMILY_GENERIC_NOP:
1113       if (check_col(pinfo->cinfo, COL_INFO)) 
1114         col_add_fstr(pinfo->cinfo, COL_INFO, "No-op");
1115       break;
1116     case FAMILY_GENERIC_DEFAULT:
1117       if (check_col(pinfo->cinfo, COL_INFO))
1118         col_add_fstr(pinfo->cinfo, COL_INFO, "Generic Default");
1119       break;
1120     }
1121
1122   /* Show the undissected payload */
1123   if (tvb_length_remaining(tvb, offset) > 0)
1124     proto_tree_add_item(tree, hf_aim_data, tvb, offset, -1, FALSE);
1125 }
1126
1127 static void dissect_aim_snac_buddylist(tvbuff_t *tvb, packet_info *pinfo, 
1128                                        int offset, proto_tree *tree, 
1129                                        guint16 subtype)
1130 {
1131   guint8 buddyname_length = 0;
1132   char buddyname[MAX_BUDDYNAME_LENGTH + 1];
1133   guint16 tlv_count = 0;
1134
1135   switch(subtype)
1136     {
1137     case FAMILY_BUDDYLIST_ERROR:
1138       if (check_col(pinfo->cinfo, COL_INFO)) 
1139         col_add_fstr(pinfo->cinfo, COL_INFO, "Buddylist - Error");
1140       break;
1141        
1142    case FAMILY_BUDDYLIST_REQRIGHTS:
1143       if (check_col(pinfo->cinfo, COL_INFO)) 
1144         col_add_fstr(pinfo->cinfo, COL_INFO, "Request Rights information");
1145       break;
1146       
1147     case FAMILY_BUDDYLIST_RIGHTSINFO:
1148       if (check_col(pinfo->cinfo, COL_INFO)) 
1149         col_add_fstr(pinfo->cinfo, COL_INFO, "Rights information");
1150       break;
1151       
1152     case FAMILY_BUDDYLIST_ADDBUDDY:
1153       if (check_col(pinfo->cinfo, COL_INFO)) 
1154         col_add_fstr(pinfo->cinfo, COL_INFO, "Add to Buddylist");
1155       break;
1156       
1157     case FAMILY_BUDDYLIST_REMBUDDY:
1158       if (check_col(pinfo->cinfo, COL_INFO)) 
1159         col_add_fstr(pinfo->cinfo, COL_INFO, "Remove from Buddylist");
1160       break;
1161       
1162     case FAMILY_BUDDYLIST_ONCOMING:
1163       buddyname_length = get_buddyname( buddyname, tvb, offset, offset + 1 );
1164
1165       if (check_col(pinfo->cinfo, COL_INFO)) {
1166         col_add_fstr(pinfo->cinfo, COL_INFO, "Oncoming Buddy");
1167         col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", buddyname);
1168       }
1169       
1170       if (tree) {
1171         proto_tree_add_text(tree, tvb, offset + 1, buddyname_length, 
1172                             "Screen Name: %s", buddyname);
1173       }
1174       offset += buddyname_length + 1;
1175
1176       /* Warning level */
1177       proto_tree_add_item(tree, hf_aim_userinfo_warninglevel, tvb, offset, 
1178                           2, FALSE);
1179       offset += 2;
1180       
1181       /* TLV Count */
1182       tlv_count = tvb_get_ntohs(tvb, offset);
1183       proto_tree_add_item(tree, hf_aim_userinfo_tlvcount, tvb, offset, 
1184                           2, FALSE);
1185       offset += 2;
1186
1187       while (tvb_length_remaining(tvb, offset) > 0) {
1188         offset = dissect_aim_tlv(tvb, pinfo, offset, tree, 
1189                                  aim_fnac_family_buddylist_oncoming_tlv);
1190       }
1191
1192       break;
1193       
1194     case FAMILY_BUDDYLIST_OFFGOING:
1195       buddyname_length = get_buddyname( buddyname, tvb, offset, offset + 1 );
1196       
1197       if (check_col(pinfo->cinfo, COL_INFO)) {
1198         col_add_fstr(pinfo->cinfo, COL_INFO, "Offgoing Buddy");
1199         col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", buddyname);
1200       }
1201       
1202       if (tree) {
1203         proto_tree_add_text(tree, tvb, offset + 1, buddyname_length, 
1204                             "Screen Name: %s", buddyname);
1205       }
1206       offset += buddyname_length + 1;
1207
1208       /* Warning level */
1209       proto_tree_add_item(tree, hf_aim_userinfo_warninglevel, tvb, offset, 
1210                           2, FALSE);
1211       offset += 2;
1212       
1213       /* TLV Count */
1214       tlv_count = tvb_get_ntohs(tvb, offset);
1215       proto_tree_add_item(tree, hf_aim_userinfo_tlvcount, tvb, offset, 
1216                           2, FALSE);
1217       offset += 2;
1218
1219       break;
1220     }
1221
1222   /* Show the undissected payload */
1223   if (tvb_length_remaining(tvb, offset) > 0)
1224     proto_tree_add_item(tree, hf_aim_data, tvb, offset, -1, FALSE);
1225 }
1226
1227 static void dissect_aim_snac_location(tvbuff_t *tvb, packet_info *pinfo, 
1228                                       int offset, proto_tree *tree, 
1229                                       guint16 subtype)
1230 {
1231   switch(subtype)
1232     {
1233     case FAMILY_LOCATION_ERROR:
1234       if (check_col(pinfo->cinfo, COL_INFO)) 
1235         col_add_fstr(pinfo->cinfo, COL_INFO, "Location - Error");
1236       break;
1237     case FAMILY_LOCATION_REQRIGHTS:
1238       if (check_col(pinfo->cinfo, COL_INFO)) 
1239         col_add_fstr(pinfo->cinfo, COL_INFO, "Request Rights Information");
1240       break;
1241     case FAMILY_LOCATION_RIGHTSINFO:
1242       if (check_col(pinfo->cinfo, COL_INFO)) 
1243         col_add_fstr(pinfo->cinfo, COL_INFO, "Rights Information");
1244       break;
1245     case FAMILY_LOCATION_SETUSERINFO:
1246       if (check_col(pinfo->cinfo, COL_INFO)) 
1247         col_add_fstr(pinfo->cinfo, COL_INFO, "Set User Information");
1248       break;
1249     case FAMILY_LOCATION_REQUSERINFO:
1250       if (check_col(pinfo->cinfo, COL_INFO)) 
1251         col_add_fstr(pinfo->cinfo, COL_INFO, "Request User Information");
1252       dissect_aim_snac_location_request_user_information(tvb, offset, tree);
1253       break;
1254     case FAMILY_LOCATION_USERINFO:
1255       if (check_col(pinfo->cinfo, COL_INFO)) 
1256         col_add_fstr(pinfo->cinfo, COL_INFO, "User Information");
1257       dissect_aim_snac_location_user_information(tvb, pinfo, offset, tree);
1258       break;
1259     case FAMILY_LOCATION_WATCHERSUBREQ:
1260       if (check_col(pinfo->cinfo, COL_INFO)) 
1261         col_add_fstr(pinfo->cinfo, COL_INFO, "Watcher Subrequest");
1262       break;
1263     case FAMILY_LOCATION_WATCHERNOT:
1264       if (check_col(pinfo->cinfo, COL_INFO)) 
1265         col_add_fstr(pinfo->cinfo, COL_INFO, "Watcher Notification");
1266       break;
1267     case FAMILY_LOCATION_DEFAULT:
1268       if (check_col(pinfo->cinfo, COL_INFO)) 
1269         col_add_fstr(pinfo->cinfo, COL_INFO, "Location Default");
1270       break;
1271     }
1272 }
1273
1274 static void dissect_aim_snac_location_request_user_information(tvbuff_t *tvb, 
1275                                                           int offset,
1276                                                           proto_tree *tree)
1277 {
1278   guint8 buddyname_length = 0;
1279
1280   /* Info Type */
1281   proto_tree_add_item(tree, hf_aim_snac_location_request_user_info_infotype, 
1282                       tvb, offset, 2, FALSE);
1283   offset += 2;
1284
1285   /* Buddy Name length */
1286   buddyname_length = tvb_get_guint8(tvb, offset);
1287   proto_tree_add_item(tree, hf_aim_buddyname_len, tvb, offset, 1, FALSE);
1288   offset += 1;
1289   
1290   /* Buddy name */
1291   proto_tree_add_item(tree, hf_aim_buddyname, tvb, offset, buddyname_length, FALSE);
1292   offset += buddyname_length;
1293
1294   /* Show the undissected payload */
1295   if (tvb_length_remaining(tvb, offset) > 0)
1296     proto_tree_add_item(tree, hf_aim_data, tvb, offset, -1, FALSE);
1297 }
1298
1299 static void dissect_aim_snac_location_user_information(tvbuff_t *tvb, 
1300                                                        packet_info *pinfo _U_, 
1301                                                   int offset, proto_tree *tree)
1302 {
1303   guint8 buddyname_length = 0;
1304   guint16 tlv_count = 0;
1305   guint16 i = 0;
1306
1307   /* Buddy Name length */
1308   buddyname_length = tvb_get_guint8(tvb, offset);
1309   proto_tree_add_item(tree, hf_aim_buddyname_len, tvb, offset, 1, FALSE);
1310   offset += 1;
1311   
1312   /* Buddy name */
1313   proto_tree_add_item(tree, hf_aim_buddyname, tvb, offset, buddyname_length, FALSE);
1314   offset += buddyname_length;
1315
1316   /* Warning level */
1317   proto_tree_add_item(tree, hf_aim_userinfo_warninglevel, tvb, offset, 2, FALSE);
1318   offset += 2;
1319
1320   /* TLV Count */
1321   tlv_count = tvb_get_ntohs(tvb, offset);
1322   proto_tree_add_item(tree, hf_aim_userinfo_tlvcount, tvb, offset, 2, FALSE);
1323   offset += 2;
1324
1325   /* Dissect the TLV array containing general user status  */
1326   while (i++ < tlv_count) {
1327     offset = dissect_aim_tlv(tvb, pinfo, offset, tree, 
1328                              aim_fnac_family_buddylist_oncoming_tlv);
1329   }
1330
1331   /* Dissect the TLV array containing the away message (or whatever info was
1332      specifically requested) */
1333   while (tvb_length_remaining(tvb, offset) > 0) {
1334     offset = dissect_aim_tlv(tvb, pinfo, offset, tree, 
1335                              aim_fnac_family_location_userinfo_tlv);
1336   }
1337 }
1338
1339 static void dissect_aim_snac_adverts(tvbuff_t *tvb _U_, 
1340                                      packet_info *pinfo _U_, 
1341                                      int offset _U_, proto_tree *tree _U_, 
1342                                      guint16 subtype)
1343 {
1344   switch(subtype)
1345     {
1346     case FAMILY_ADVERTS_ERROR:
1347       if (check_col(pinfo->cinfo, COL_INFO)) 
1348         col_add_fstr(pinfo->cinfo, COL_INFO, "Advertisements - Error");
1349       break;
1350     case FAMILY_ADVERTS_REQUEST:
1351       if (check_col(pinfo->cinfo, COL_INFO)) 
1352         col_add_fstr(pinfo->cinfo, COL_INFO, "Advertisement Request");
1353       break;
1354     case FAMILY_ADVERTS_DATA:
1355       if (check_col(pinfo->cinfo, COL_INFO)) 
1356         col_add_fstr(pinfo->cinfo, COL_INFO, "Advertisement data (GIF)");
1357       break;
1358     }
1359
1360   /* Show the undissected payload */
1361   if (tvb_length_remaining(tvb, offset) > 0)
1362     proto_tree_add_item(tree, hf_aim_data, tvb, offset, -1, FALSE);
1363 }
1364
1365 static void dissect_aim_snac_userlookup(tvbuff_t *tvb _U_, packet_info *pinfo, 
1366                                         int offset _U_, proto_tree *tree _U_, 
1367                                         guint16 subtype)
1368 {
1369   switch(subtype)
1370     {
1371     case FAMILY_USERLOOKUP_ERROR:
1372       if (check_col(pinfo->cinfo, COL_INFO)) 
1373         col_add_fstr(pinfo->cinfo, COL_INFO, 
1374                      "Search - Error (could be: not found)");
1375       break;
1376     case FAMILY_USERLOOKUP_SEARCHEMAIL:
1377       if (check_col(pinfo->cinfo, COL_INFO)) 
1378         col_add_fstr(pinfo->cinfo, COL_INFO, 
1379                      "Search for Screen Name by e-mail");
1380       break;
1381     case FAMILY_USERLOOKUP_SEARCHRESULT:
1382       if (check_col(pinfo->cinfo, COL_INFO)) 
1383         col_add_fstr(pinfo->cinfo, COL_INFO, "Screen Name Search Result");
1384       break;
1385     }
1386
1387   /* Show the undissected payload */
1388   if (tvb_length_remaining(tvb, offset) > 0)
1389     proto_tree_add_item(tree, hf_aim_data, tvb, offset, -1, FALSE);
1390 }
1391
1392 static void dissect_aim_snac_chat(tvbuff_t *tvb, packet_info *pinfo, 
1393                                   int offset _U_, proto_tree *tree, 
1394                                   guint16 subtype)
1395 {
1396   guint8 buddyname_length = 0;
1397   char buddyname[MAX_BUDDYNAME_LENGTH + 1];
1398   guchar msg[1000];
1399
1400   switch(subtype)
1401     {
1402     case FAMILY_CHAT_OUTGOINGMSG:
1403       /* channel message from client */
1404       get_message( msg, tvb, 40 + buddyname_length, tvb_length(tvb) 
1405                    - 40 - buddyname_length );
1406       
1407       if (check_col(pinfo->cinfo, COL_INFO)) {
1408         col_add_fstr(pinfo->cinfo, COL_INFO, "Chat Message ");
1409         col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", msg);
1410       }
1411       break;
1412       
1413     case FAMILY_CHAT_INCOMINGMSG:
1414       /* channel message to client */
1415       buddyname_length = get_buddyname( buddyname, tvb, 30, 31 );
1416       get_message( msg, tvb, 36 + buddyname_length, tvb_length(tvb) 
1417                    - 36 - buddyname_length );
1418       
1419       if (check_col(pinfo->cinfo, COL_INFO)) {
1420         col_add_fstr(pinfo->cinfo, COL_INFO, "Chat Message ");
1421         col_append_fstr(pinfo->cinfo, COL_INFO, "from: %s", buddyname);
1422         col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", msg);
1423       }
1424       
1425       if(tree) {
1426         proto_tree_add_text(tree, tvb, 31, buddyname_length, 
1427                             "Screen Name: %s", buddyname);
1428       }
1429       break;
1430     }
1431 }
1432
1433 static void dissect_aim_snac_messaging(tvbuff_t *tvb, packet_info *pinfo, 
1434                                        int offset, proto_tree *tree, 
1435                                        guint16 subtype)
1436 {
1437   guint8 buddyname_length = 0;
1438   char buddyname[MAX_BUDDYNAME_LENGTH + 1];
1439   guchar msg[1000];
1440
1441   switch(subtype)
1442     {    
1443     case FAMILY_MESSAGING_OUTGOING:
1444
1445       /* Unknown */
1446       offset += 10;
1447
1448       buddyname_length = get_buddyname( buddyname, tvb, offset, offset + 1 );
1449
1450       /* djh - My test suggest that this is broken.  Need to give this a
1451          closer look @@@@@@@@@ */
1452       get_message( msg, tvb, 36 + buddyname_length, tvb_length(tvb) - 36
1453                    - buddyname_length );
1454       
1455       if (check_col(pinfo->cinfo, COL_INFO)) {
1456         col_add_fstr(pinfo->cinfo, COL_INFO, "Message ");
1457         col_append_fstr(pinfo->cinfo, COL_INFO, "to: %s", buddyname);
1458         col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", msg);
1459       }
1460       
1461       if(tree) {
1462         proto_tree_add_text(tree, tvb, 27, buddyname_length, 
1463                             "Screen Name: %s", buddyname);
1464       }
1465       
1466       break;
1467       
1468     case FAMILY_MESSAGING_INCOMING:
1469
1470       /* Unknown */
1471       offset += 10;
1472
1473       buddyname_length = get_buddyname( buddyname, tvb, offset, offset + 1 );
1474
1475       /* djh - My test suggest that this is broken.  Need to give this a
1476          closer look @@@@@@@@@ */      
1477       get_message( msg, tvb, 36 + buddyname_length,  tvb_length(tvb) - 36
1478                    - buddyname_length);
1479       
1480       if (check_col(pinfo->cinfo, COL_INFO)) {
1481         col_add_fstr(pinfo->cinfo, COL_INFO, "Message");
1482         col_append_fstr(pinfo->cinfo, COL_INFO, " from: %s", buddyname);
1483         
1484         col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", msg);
1485       }
1486       
1487       if(tree) {
1488         proto_tree_add_text(tree, tvb, 27, buddyname_length, 
1489                             "Screen Name: %s", buddyname);
1490       }
1491       break;
1492     }
1493 }
1494
1495 static void dissect_aim_snac_ssi(tvbuff_t *tvb, packet_info *pinfo _U_, 
1496                                  int offset, proto_tree *tree, 
1497                                  guint16 subtype _U_)
1498 {
1499   switch(subtype)
1500     {    
1501     case FAMILY_SSI_LIST:
1502       dissect_aim_snac_ssi_list(tvb, pinfo, offset, tree, subtype);
1503       break;
1504     default:
1505       /* Show the undissected payload */
1506       if (tvb_length_remaining(tvb, offset) > 0)
1507         proto_tree_add_item(tree, hf_aim_data, tvb, offset, -1, FALSE);
1508     }
1509 }
1510
1511 static void dissect_aim_snac_ssi_list(tvbuff_t *tvb, packet_info *pinfo _U_, 
1512                                       int offset, proto_tree *tree, 
1513                                       guint16 subtype _U_)
1514 {
1515   guint16 buddyname_length = 0;
1516   guint16 tlv_len = 0;
1517   proto_item *ti;
1518   proto_tree *ssi_entry = NULL;
1519
1520   /* SSI Version */
1521   proto_tree_add_item(tree, hf_aim_fnac_subtype_ssi_version, tvb, offset, 1,
1522                       FALSE);
1523   offset += 1;
1524   
1525   /* Number of items */
1526   proto_tree_add_item(tree, hf_aim_fnac_subtype_ssi_numitems, tvb, offset, 2,
1527                       FALSE);
1528   offset += 2;
1529   
1530   while (tvb_length_remaining(tvb, offset) > 4) {
1531     ti = proto_tree_add_text(tree, tvb, offset, 0, "SSI Entry");
1532     ssi_entry = proto_item_add_subtree(ti, ett_aim_ssi);
1533     
1534     /* Buddy Name Length */
1535     buddyname_length = tvb_get_ntohs(tvb, offset);
1536     proto_tree_add_item(ssi_entry, hf_aim_fnac_subtype_ssi_buddyname_len, 
1537                         tvb, offset, 2, FALSE);
1538     offset += 2;
1539     
1540     /* Buddy Name */
1541     if (buddyname_length > 0) {
1542       proto_tree_add_item(ssi_entry, hf_aim_fnac_subtype_ssi_buddyname, tvb, 
1543                           offset, buddyname_length, FALSE);
1544       offset += buddyname_length;
1545     }
1546     
1547     /* Buddy group ID */
1548     proto_tree_add_item(ssi_entry, hf_aim_fnac_subtype_ssi_gid, tvb, offset, 
1549                         2, FALSE);
1550     offset += 2;
1551     
1552     /* Buddy ID */
1553     proto_tree_add_item(ssi_entry, hf_aim_fnac_subtype_ssi_bid, tvb, offset, 
1554                         2, FALSE);
1555     offset += 2;
1556     
1557     /* Buddy Type */
1558     proto_tree_add_item(ssi_entry, hf_aim_fnac_subtype_ssi_type, tvb, offset,
1559                         2, FALSE);
1560     offset += 2;
1561     
1562     /* Size of the following TLV in bytes (as opposed to the number of 
1563        TLV objects in the chain) */
1564     tlv_len = tvb_get_ntohs(tvb, offset);
1565     proto_tree_add_item(ssi_entry, hf_aim_fnac_subtype_ssi_tlvlen, tvb, 
1566                         offset, 2, FALSE);
1567     offset += 2;
1568     
1569     /* For now, we just dump the TLV contents as-is, since there is not a
1570        TLV dissection utility that works based on total chain length */
1571     if (tlv_len > 0) {
1572       proto_tree_add_item(ssi_entry, hf_aim_data, tvb, offset, tlv_len, 
1573                           FALSE);
1574       offset += tlv_len;
1575     }
1576   }
1577 }
1578
1579 static void dissect_aim_snac_fnac_subtype(tvbuff_t *tvb, int offset, 
1580                                      proto_tree *tree, guint16 family)
1581 {
1582   /* Since the subtypes differ by family, we need to display the correct
1583      subtype based on the family.  If we don't know the family, or we do
1584      not have the subtypes enumerated for a known family, we just dump the
1585      subtype as-is */
1586
1587   switch (family)
1588     {
1589     case FAMILY_GENERIC:
1590       proto_tree_add_item (tree, hf_aim_fnac_subtype_generic,
1591                            tvb, offset, 2, FALSE);
1592       break;
1593     case FAMILY_LOCATION:
1594       proto_tree_add_item (tree, hf_aim_fnac_subtype_location,
1595                            tvb, offset, 2, FALSE);
1596       break;
1597     case FAMILY_BUDDYLIST:
1598       proto_tree_add_item (tree, hf_aim_fnac_subtype_buddylist,
1599                            tvb, offset, 2, FALSE);
1600       break;
1601     case FAMILY_MESSAGING:
1602       proto_tree_add_item (tree, hf_aim_fnac_subtype_messaging,
1603                            tvb, offset, 2, FALSE);
1604       break;
1605     case FAMILY_ADVERTS:
1606       proto_tree_add_item (tree, hf_aim_fnac_subtype_adverts,
1607                            tvb, offset, 2, FALSE);
1608       break;
1609     case FAMILY_INVITATION:
1610       proto_tree_add_item (tree, hf_aim_fnac_subtype_invitation,
1611                            tvb, offset, 2, FALSE);
1612       break;
1613     case FAMILY_ADMIN:
1614       proto_tree_add_item (tree, hf_aim_fnac_subtype_admin,
1615                            tvb, offset, 2, FALSE);
1616       break;
1617     case FAMILY_POPUP:
1618       proto_tree_add_item (tree, hf_aim_fnac_subtype_popup,
1619                            tvb, offset, 2, FALSE);
1620       break;
1621     case FAMILY_BOS:
1622       proto_tree_add_item (tree, hf_aim_fnac_subtype_bos,
1623                            tvb, offset, 2, FALSE);
1624       break;
1625     case FAMILY_USERLOOKUP:
1626       proto_tree_add_item (tree, hf_aim_fnac_subtype_userlookup,
1627                            tvb, offset, 2, FALSE);
1628       break;
1629     case FAMILY_STATS:
1630       proto_tree_add_item (tree, hf_aim_fnac_subtype_stats,
1631                            tvb, offset, 2, FALSE);
1632       break;
1633     case FAMILY_TRANSLATE:
1634       proto_tree_add_item (tree, hf_aim_fnac_subtype_translate,
1635                            tvb, offset, 2, FALSE);
1636       break;
1637     case FAMILY_CHAT_NAV:
1638       proto_tree_add_item (tree, hf_aim_fnac_subtype_chatnav,
1639                            tvb, offset, 2, FALSE);
1640       break;
1641     case FAMILY_CHAT:
1642       proto_tree_add_item (tree, hf_aim_fnac_subtype_chat,
1643                            tvb, offset, 2, FALSE);
1644       break;
1645     case FAMILY_SSI:
1646       proto_tree_add_item (tree, hf_aim_fnac_subtype_ssi,
1647                            tvb, offset, 2, FALSE);
1648       break;
1649     case FAMILY_ICQ:
1650       proto_tree_add_item (tree, hf_aim_fnac_subtype_icq,
1651                            tvb, offset, 2, FALSE);
1652       break;
1653     case FAMILY_SIGNON:
1654       proto_tree_add_item (tree, hf_aim_fnac_subtype_signon,
1655                            tvb, offset, 2, FALSE);
1656       break;
1657     case FAMILY_OFT:
1658     default:
1659       proto_tree_add_item(tree, hf_aim_fnac_subtype, tvb, offset, 2, FALSE);
1660       break;
1661
1662     }
1663 }
1664
1665 static void dissect_aim_flap_err(tvbuff_t *tvb, packet_info *pinfo, 
1666                                  int offset, proto_tree *tree)
1667 {
1668   if (check_col(pinfo->cinfo, COL_INFO)) {
1669     col_add_fstr(pinfo->cinfo, COL_INFO, "FLAP error");
1670   }
1671
1672   /* Show the undissected payload */
1673   if (tvb_length_remaining(tvb, offset) > 0)
1674     proto_tree_add_item(tree, hf_aim_data, tvb, offset, -1, FALSE);
1675 }
1676
1677 static void dissect_aim_close_conn(tvbuff_t *tvb, packet_info *pinfo, 
1678                                    int offset, proto_tree *tree)
1679 {
1680   if (check_col(pinfo->cinfo, COL_INFO)) {
1681     col_add_fstr(pinfo->cinfo, COL_INFO, "Close Connection");
1682   }
1683
1684   /* Show the undissected payload */
1685   if (tvb_length_remaining(tvb, offset) > 0)
1686     proto_tree_add_item(tree, hf_aim_data, tvb, offset, -1, FALSE);
1687 }
1688
1689 static void dissect_aim_unknown_channel(tvbuff_t *tvb, packet_info *pinfo, 
1690                                         int offset, proto_tree *tree)
1691 {
1692   if (check_col(pinfo->cinfo, COL_INFO)) {
1693     col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown Channel");
1694   }
1695
1696   /* Show the undissected payload */
1697   if (tvb_length_remaining(tvb, offset) > 0)
1698     proto_tree_add_item(tree, hf_aim_data, tvb, offset, -1, FALSE);
1699 }
1700
1701 /* Dissect a TLV value */
1702 static int dissect_aim_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, 
1703                            int offset, proto_tree *tree, const aim_tlv *tlv)
1704 {
1705   guint16 valueid;
1706   guint16 length;
1707   int i = 0;
1708   const aim_tlv *tmp;
1709   proto_item *ti1;
1710   proto_tree *tlv_tree;
1711   int orig_offset;
1712   guint16 value16;
1713   guint32 value32;
1714
1715   /* Record the starting offset so we can reuse it at the second pass */
1716   orig_offset = offset;
1717
1718   /* Get the value ID */
1719   valueid = tvb_get_ntohs(tvb, offset);
1720   offset += 2;
1721
1722   /* Figure out which entry applies from the tlv list */
1723   tmp = tlv;
1724   while (tmp[i].valueid) {
1725     if (tmp[i].valueid == valueid) {
1726       /* We found a match */
1727       break;
1728     }
1729     i++;
1730   }
1731
1732   /* At this point, we are either pointing at the correct record, or 
1733      we didn't find the record, and are pointing at the last item in the 
1734      list */
1735
1736   length = tvb_get_ntohs(tvb, offset);
1737   offset += 2;
1738   offset += length;
1739
1740   if (tree) {
1741     offset = orig_offset;
1742     
1743     /* Show the info in the top of the tree if it's one of the standard
1744        data types */
1745     if (tmp[i].datatype == FT_STRING && length > 0) {
1746       guint8 *buf;
1747       buf = tvb_get_string(tvb, offset + 4, length);
1748       ti1 = proto_tree_add_text(tree, tvb, offset, length + 4, 
1749                                 "%s: %s", tmp[i].desc, buf);
1750       g_free(buf);
1751     }
1752     else if (tmp[i].datatype == FT_UINT16) {
1753       value16 = tvb_get_ntohs(tvb, offset + 4);
1754       ti1 = proto_tree_add_text(tree, tvb, offset, length + 4, 
1755                                 "%s: %d", tmp[i].desc, value16);
1756     }
1757     else if (tmp[i].datatype == FT_UINT32) {
1758       value32 = tvb_get_ntohl(tvb, offset + 4);
1759       ti1 = proto_tree_add_text(tree, tvb, offset, length + 4, 
1760                                 "%s: %d", tmp[i].desc, value32);
1761     }
1762     else {
1763       ti1 = proto_tree_add_text(tree, tvb, offset, length + 4, 
1764                                 "%s", tmp[i].desc);
1765     }
1766
1767     tlv_tree = proto_item_add_subtree(ti1, ett_aim_tlv);
1768
1769     proto_tree_add_text(tlv_tree, tvb, offset, 2,
1770                         "Value ID: %s (0x%04x)", tmp[i].desc, valueid);
1771     offset += 2;
1772     
1773     proto_tree_add_text(tlv_tree, tvb, offset, 2,
1774                         "Length: %d", length);
1775     offset += 2;
1776
1777     ti1 = proto_tree_add_text(tlv_tree, tvb, offset, length,
1778                               "Value");
1779     offset += length;
1780   }
1781
1782   /* Return the new length */
1783   return offset;
1784 }
1785
1786
1787 /* Register the protocol with Ethereal */
1788 void
1789 proto_register_aim(void)
1790 {
1791
1792 /* Setup list of header fields */
1793   static hf_register_info hf[] = {
1794     { &hf_aim_cmd_start,
1795       { "Command Start", "aim.cmd_start", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }
1796     },
1797     { &hf_aim_channel,
1798       { "Channel ID", "aim.channel", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }
1799     },
1800     { &hf_aim_seqno,
1801       { "Sequence Number", "aim.seqno", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
1802     },
1803     { &hf_aim_data_len,
1804       { "Data Field Length", "aim.datalen", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
1805     },
1806     { &hf_aim_data,
1807       { "Data", "aim.data", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }
1808     },
1809     { &hf_aim_signon_challenge_len,
1810       { "Signon challenge length", "aim.signon.challengelen", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
1811     },
1812     { &hf_aim_signon_challenge,
1813       { "Signon challenge", "aim.signon.challenge", FT_STRING, BASE_HEX, NULL, 0x0, "", HFILL }
1814     },
1815     { &hf_aim_fnac_family,
1816       { "FNAC Family ID", "aim.fnac.family", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_ids), 0x0, "", HFILL }
1817     },
1818     { &hf_aim_fnac_subtype,
1819       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }
1820     },
1821     { &hf_aim_fnac_subtype_signon,
1822       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_signon), 0x0, "", HFILL }
1823     },
1824     { &hf_aim_fnac_subtype_generic,
1825       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_generic), 0x0, "", HFILL }
1826     },
1827     { &hf_aim_fnac_subtype_location,
1828       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_location), 0x0, "", HFILL }
1829     },
1830     { &hf_aim_fnac_subtype_buddylist,
1831       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_buddylist), 0x0, "", HFILL }
1832     },
1833     { &hf_aim_fnac_subtype_messaging,
1834       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_messaging), 0x0, "", HFILL }
1835     },
1836     { &hf_aim_fnac_subtype_adverts,
1837       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_adverts), 0x0, "", HFILL }
1838     },
1839     { &hf_aim_fnac_subtype_invitation,
1840       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_invitation), 0x0, "", HFILL }
1841     },
1842     { &hf_aim_fnac_subtype_admin,
1843       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_admin), 0x0, "", HFILL }
1844     },
1845     { &hf_aim_fnac_subtype_popup,
1846       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_popup), 0x0, "", HFILL }
1847     },
1848     { &hf_aim_fnac_subtype_bos,
1849       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_bos), 0x0, "", HFILL }
1850     },
1851     { &hf_aim_fnac_subtype_userlookup,
1852       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_userlookup), 0x0, "", HFILL }
1853     },
1854     { &hf_aim_fnac_subtype_stats,
1855       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_stats), 0x0, "", HFILL }
1856     },
1857     { &hf_aim_fnac_subtype_translate,
1858       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_translate), 0x0, "", HFILL }
1859     },
1860     { &hf_aim_fnac_subtype_chatnav,
1861       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_chatnav), 0x0, "", HFILL }
1862     },
1863     { &hf_aim_fnac_subtype_chat,
1864       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_chat), 0x0, "", HFILL }
1865     },
1866     { &hf_aim_fnac_subtype_ssi,
1867       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_ssi), 0x0, "", HFILL }
1868     },
1869     { &hf_aim_fnac_subtype_ssi_version,
1870       { "SSI Version", "aim.fnac.ssi.version", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }
1871     },
1872     { &hf_aim_fnac_subtype_ssi_numitems,
1873       { "SSI Object count", "aim.fnac.ssi.numitems", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }
1874     },
1875     { &hf_aim_fnac_subtype_ssi_buddyname_len,
1876       { "SSI Buddy Name length", "aim.fnac.ssi.buddyname_len", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }
1877     },
1878     { &hf_aim_fnac_subtype_ssi_buddyname,
1879       { "Buddy Name", "aim.fnac.ssi.buddyname", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }
1880     },
1881     { &hf_aim_fnac_subtype_ssi_gid,
1882       { "SSI Buddy Group ID", "aim.fnac.ssi.gid", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }
1883     },
1884     { &hf_aim_fnac_subtype_ssi_bid,
1885       { "SSI Buddy ID", "aim.fnac.ssi.bid", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }
1886     },
1887     { &hf_aim_fnac_subtype_ssi_type,
1888       { "SSI Buddy type", "aim.fnac.ssi.type", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_ssi_types), 0x0, "", HFILL }
1889     },
1890     { &hf_aim_fnac_subtype_ssi_tlvlen,
1891       { "SSI TLV Len", "aim.fnac.ssi.tlvlen", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }
1892     },
1893     { &hf_aim_fnac_subtype_ssi_data,
1894       { "SSI Buddy Data", "aim.fnac.ssi.data", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }
1895     },
1896     { &hf_aim_fnac_subtype_icq,
1897       { "FNAC Subtype ID", "aim.fnac.subtype", FT_UINT16, BASE_HEX, VALS(aim_fnac_family_icq), 0x0, "", HFILL }
1898     },
1899     { &hf_aim_fnac_flags,
1900       { "FNAC Flags", "aim.fnac.flags", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }
1901     },
1902     { &hf_aim_fnac_id,
1903       { "FNAC ID", "aim.fnac.id", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }
1904     },
1905     { &hf_aim_infotype,
1906       { "Infotype", "aim.infotype", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }
1907     },
1908     { &hf_aim_snac_location_request_user_info_infotype,
1909       { "Infotype", "aim.snac.location.request_user_info.infotype", FT_UINT16,
1910         BASE_HEX, VALS(aim_snac_location_request_user_info_infotypes), 0x0,
1911         "", HFILL }
1912     },
1913     { &hf_aim_buddyname_len,
1914       { "Buddyname len", "aim.buddynamelen", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
1915     },
1916     { &hf_aim_buddyname,
1917       { "Buddy Name", "aim.buddyname", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }
1918     },
1919     { &hf_aim_userinfo_warninglevel,
1920       { "Warning Level", "aim.userinfo.warninglevel", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL },
1921     },
1922     { &hf_aim_userinfo_tlvcount,
1923       { "TLV Count", "aim.userinfo.tlvcount", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL },
1924     },
1925   };
1926
1927 /* Setup protocol subtree array */
1928   static gint *ett[] = {
1929     &ett_aim,
1930     &ett_aim_fnac,
1931     &ett_aim_tlv,
1932     &ett_aim_ssi,
1933   };
1934   module_t *aim_module;
1935
1936 /* Register the protocol name and description */
1937   proto_aim = proto_register_protocol("AOL Instant Messenger", "AIM", "aim");
1938
1939 /* Required function calls to register the header fields and subtrees used */
1940   proto_register_field_array(proto_aim, hf, array_length(hf));
1941   proto_register_subtree_array(ett, array_length(ett));
1942
1943   aim_module = prefs_register_protocol(proto_aim, NULL);
1944   prefs_register_bool_preference(aim_module, "desegment",
1945     "Desegment all AIM messages spanning multiple TCP segments",
1946     "Whether the AIM dissector should desegment all messages spanning multiple TCP segments",
1947     &aim_desegment);
1948 }
1949
1950 void
1951 proto_reg_handoff_aim(void)
1952 {
1953   dissector_handle_t aim_handle;
1954
1955   aim_handle = new_create_dissector_handle(dissect_aim, proto_aim);
1956   dissector_add("tcp.port", TCP_PORT_AIM, aim_handle);
1957 }