# TOC Protocol Specification Version: TOC 1.0 / TOC 2.0 This document is the authoritative reference for the TOC (Talk to OSCAR Client) protocol as implemented by Open OSCAR Server. It covers both TOC 1.0 and TOC 2.0, and contains enough detail to build a fully-functional client from scratch. TOC is an ASCII-based protocol layered on top of FLAP (SFLAP) framing over TCP. It was originally designed by AOL to service the TiK (Tcl/Tk) and TIC (Java) AIM clients. TOC 2.0 extends the original protocol with server-side buddy lists, typing notifications, encoded messages, and richer buddy status information. --- ## Table of Contents 1. [Transport Layer (FLAP)](#1-transport-layer-flap) 2. [Connection & Authentication](#2-connection--authentication) 3. [Client → Server Commands (TOC 1)](#3-client--server-commands-toc-1) 4. [Client → Server Commands (TOC 2)](#4-client--server-commands-toc-2) 5. [Server → Client Messages (TOC 1)](#5-server--client-messages-toc-1) 6. [Server → Client Messages (TOC 2)](#6-server--client-messages-toc-2) 7. [Error Codes](#7-error-codes) 8. [Escaping & Encoding Rules](#8-escaping--encoding-rules) 9. [Capabilities (UUIDs)](#9-capabilities-uuids) 10. [Complete Session Examples](#10-complete-session-examples) --- ## 1. Transport Layer (FLAP) All TOC communication is wrapped in FLAP (SFLAP) frames over a single TCP connection. The default port is **9898**. ### 1.1 FLAP Header Every frame begins with a 6-byte binary header in **network byte order** (big-endian): | Offset | Size | Field | Description | |--------|------|-------|-------------| | 0 | 1 | Marker | Always `0x2A` (ASCII `*`) | | 1 | 1 | Frame Type | See below | | 2 | 2 | Sequence Number | Monotonically increasing per direction | | 4 | 2 | Data Length | Length of the payload that follows | The payload immediately follows the header at offset 6. ### 1.2 Frame Types | Value | Name | Description | |-------|------|-------------| | 1 | SIGNON | Connection initialization | | 2 | DATA | Normal command/response data | | 3 | ERROR | Not used by TOC | | 4 | SIGNOFF | Client disconnect | | 5 | KEEP_ALIVE | Heartbeat (no payload) | ### 1.3 SIGNON Frame Payload **Server → Client** (after the client sends `FLAPON`): | Offset | Size | Description | |--------|------|-------------| | 0 | 4 | FLAP version (always `0x00000001`) | **Client → Server** (response to the server's signon frame): | Offset | Size | Description | |--------|------|-------------| | 0 | 4 | FLAP version (`0x00000001`) | | 4 | 2 | TLV tag (`0x0001`) | | 6 | 2 | Screen name length (N) | | 8 | N | Normalized screen name (NOT null-terminated) | ### 1.4 DATA Frame Payload - **Client → Server:** The payload is the TOC command as a null-terminated ASCII string. The Data Length includes the null terminator. - **Server → Client:** The payload is the TOC response as an ASCII string. It is NOT null-terminated. The Data Length is the exact string length. ### 1.5 Sequence Numbers Each direction maintains an independent sequence counter starting at an arbitrary value (usually 0 for clients). The counter increments by 1 for each frame sent. When it reaches 65535 it wraps to 0. ### 1.6 Maximum Lengths - **Client → Server:** 2048 bytes maximum per command. Exceeding this drops the connection. - **Server → Client:** 8192 bytes maximum per message. --- ## 2. Connection & Authentication ### 2.1 Connection Handshake ``` Client Server | | | --- TCP connect (port 9898) ---> | | --- "FLAPON\r\n\r\n" ---------> | | <-- FLAP SIGNON frame ---------- | | --- FLAP SIGNON frame ---------> | | --- toc_signon/toc2_login -----> | | <-- SIGN_ON --------------------- | | <-- CONFIG/CONFIG2 -------------- | | <-- NICK ------------------------ | | --- toc_add_buddy (optional) ---> | | --- toc_add_permit (optional) --> | | --- toc_init_done --------------> | | <-- UPDATE_BUDDY (for each --- | | online buddy) | ``` Step by step: 1. Open a TCP connection to the server (default port 9898). 2. Send the string `FLAPON\r\n\r\n` (10 bytes). Alternatively, `FLAPON\n\n` (8 bytes) is also accepted. 3. Server responds with a FLAP SIGNON frame (frame type 1) containing the 4-byte FLAP version. 4. Client sends a FLAP SIGNON frame back containing: the 4-byte FLAP version, a TLV with tag `0x0001` holding the normalized screen name. 5. Client sends the login command as a FLAP DATA frame (frame type 2). 6. On success, the server sends `SIGN_ON`, then `CONFIG`/`CONFIG2`, then `NICK`. On failure, the server sends an `ERROR` and/or drops the connection. 7. Client optionally sends buddy list and permit/deny setup. 8. Client sends `toc_init_done` to go online. This MUST be sent within 30 seconds of the signon command. ### 2.2 Password Roasting Passwords are "roasted" before transmission to prevent cleartext on the wire (this is obfuscation, not encryption). **Roasting String:** `Tic/Toc` **Algorithm:** 1. XOR each byte of the password with the corresponding byte of the roasting string (cycling through the string). 2. Convert the result to lowercase hexadecimal. 3. Prepend `0x`. **Example:** The password `password` roasts to `0x2408105c23001130`. ```python def roast_password(password): roast = "Tic/Toc" result = [] for i, ch in enumerate(password): xored = ord(ch) ^ ord(roast[i % len(roast)]) result.append(f"{xored:02x}") return "0x" + "".join(result) ``` ### 2.3 TOC 1 Signon ``` toc_signon ``` | Parameter | Description | |-----------|-------------| | authorizer_host | Auth server hostname (e.g. `login.oscar.aol.com`). Ignored by Open OSCAR Server but required. | | authorizer_port | Auth server port (e.g. `5190`). Ignored but required. | | screen_name | Normalized screen name | | roasted_password | Password roasted as described above | | language | Language string (e.g. `english`) | | version | Client version string, max 50 characters (e.g. `"TIC:MyClient"`) | **Example:** ``` toc_signon login.oscar.aol.com 5190 toctest1 0x2408105c23001130 english "TIC:MyClient 1.0" ``` On success, the server replies with: ``` SIGN_ON:TOC1.0 CONFIG: NICK: ``` ### 2.4 TOC 2 Signon (toc2_signon) Same syntax as `toc_signon`. The server replies with `SIGN_ON:TOC2.0` and `CONFIG2` instead of `CONFIG`. TOC 2 features (server-side buddy list, `UPDATE_BUDDY2`, `IM_IN2`, etc.) are enabled. ``` toc2_signon login.oscar.aol.com 5190 toctest1 0x2408105c23001130 english "TIC:MyClient 1.0" ``` ### 2.5 TOC 2 Login (toc2_login) Extends `toc2_signon` with additional trailing parameters and enables encoded message variants (`IM_IN_ENC2`, `CHAT_IN_ENC`). ``` toc2_login 160 US "" "" 3 0 30303 -kentucky -utf8 ``` | Parameter | Description | |-----------|-------------| | (first 6) | Same as `toc_signon` | | 160 US "" "" 3 0 30303 -kentucky -utf8 | Fixed parameters (send verbatim) | | code | Login code: `7696 * ascii(screen_name[0]) * ascii(password[0])` | The version string MUST start with `TIC:` (e.g. `"TIC:MyClient"`). **Code calculation example:** ```python def login_code(screen_name, password): return 7696 * ord(screen_name[0]) * ord(password[0]) ``` For screen name `toctest1` (first char `t` = 116) and password `testpass1` (first char `t` = 116): `7696 * 116 * 116 = 103,547,776`. **Example:** ``` toc2_login login.oscar.aol.com 5190 toctest1 0x2408105c23001130 english "TIC:MyClient" 160 US "" "" 3 0 30303 -kentucky -utf8 103547776 ``` On success: ``` SIGN_ON:TOC2.0 NICK:toctest1 CONFIG2: ``` --- ## 3. Client → Server Commands (TOC 1) All client commands are lowercase, space-separated, and sent as FLAP DATA frames (null-terminated). Arguments containing spaces should be enclosed in quotes. Screen names must be **normalized** (lowercased, spaces removed). Message content must be **escaped** (see [Escaping Rules](#8-escaping--encoding-rules)). ### toc_init_done Tells the server the client is ready to go online. Must be sent within 30 seconds of the signon command, and only after `SIGN_ON` is received. ``` toc_init_done ``` ### toc_send_im Send an instant message to a user. The message may contain basic HTML. ``` toc_send_im [auto] ``` | Parameter | Description | |-----------|-------------| | destination_user | Normalized screen name of the recipient | | message | Quoted, escaped message (may contain HTML) | | auto | Optional literal string `auto` to mark as auto-response | **Examples:** ``` toc_send_im toctest2 "Hello there!" toc_send_im toctest2 "I am away right now" auto toc_send_im toctest2 "Check out \$100 deals" ``` ### toc_add_buddy Add one or more buddies to the buddy list. This subscribes to their presence updates. Does not modify saved config (TOC 1 only — use `toc_set_config` to persist). ``` toc_add_buddy [ ...] ``` **Example:** ``` toc_add_buddy toctest2 joe mike ``` ### toc_remove_buddy Remove one or more buddies from the buddy list. Does not modify saved config. ``` toc_remove_buddy [ ...] ``` **Example:** ``` toc_remove_buddy toctest2 ``` ### toc_set_config Save the buddy list configuration on the server. The config is a line-oriented format where the first character is the item type, followed by a space, then the value. Enclose the entire config in quotes. ``` toc_set_config ``` **Config item types:** | Prefix | Description | |--------|-------------| | `g` | Buddy group name. All buddies until the next `g` or end of config belong to this group. | | `b` | Buddy screen name | | `p` | Permit list entry | | `d` | Deny list entry | | `m` | Permit/Deny mode: `1`=Permit All, `2`=Deny All, `3`=Permit Some, `4`=Deny Some | **Example:** ``` toc_set_config "m 1 g Buddies b toctest2 b joe g Coworkers b mike d spammer123 " ``` ### toc_get_status Query the online status of a user. Returns an `UPDATE_BUDDY` message if online, or an `ERROR` if the user is not available. ``` toc_get_status ``` **Example:** ``` toc_get_status toctest2 ``` ### toc_set_info Set the user's profile information (HTML). ``` toc_set_info ``` **Example:** ``` toc_set_info "Hello! I love AIM." ``` ### toc_get_info Request a user's profile. The server responds with a `GOTO_URL` containing a URL to view the profile, or an `ERROR`. ``` toc_get_info ``` **Example:** ``` toc_get_info toctest2 ``` ### toc_set_away Set or clear the away message. If a message is provided, the user's unavailable flag is set. If omitted, the flag is cleared. ``` toc_set_away [] ``` **Examples:** ``` toc_set_away "Gone fishing! BRB" toc_set_away ``` ### toc_set_idle Set the idle time in seconds. If 0, the user is marked as active. The server auto-increments the idle counter, so only call this once. ``` toc_set_idle ``` **Examples:** ``` toc_set_idle 300 toc_set_idle 0 ``` ### toc_set_caps Declare the client's capabilities. All supported capabilities must be sent at once. Capabilities are represented as UUIDs (see [Capabilities](#9-capabilities-uuids)). ``` toc_set_caps [ [ ...]] ``` **Example:** ``` toc_set_caps 09461343-4C7F-11D1-8222-444553540000 09461345-4C7F-11D1-8222-444553540000 ``` ### toc_evil Warn (evil) another user. You can only warn users who have recently sent you an IM. ``` toc_evil ``` | Type | Effect | |------|--------| | `norm` | Normal warning (+20% to target's warning level, your identity revealed) | | `anon` | Anonymous warning (+10%, your identity hidden) | **Example:** ``` toc_evil spammer123 anon ``` ### toc_add_permit Add users to the permit list. If currently in deny mode, switches to permit mode first. With no arguments and in deny mode, switches to permit-none. ``` toc_add_permit [ [ ...]] ``` **Example:** ``` toc_add_permit toctest2 joe ``` ### toc_add_deny Add users to the deny (block) list. If currently in permit mode, switches to deny mode first. With no arguments and in permit mode, switches to deny-none. ``` toc_add_deny [ [ ...]] ``` **Example:** ``` toc_add_deny spammer123 ``` ### toc_chat_join Join a chat room on the specified exchange. Exchange should be `4` for standard chat rooms. The server responds with `CHAT_JOIN` on success or `ERROR` on failure. ``` toc_chat_join ``` **Example:** ``` toc_chat_join 4 "My Chat Room" ``` ### toc_chat_send Send a message to a chat room. Use the chat room ID received in the `CHAT_JOIN` response. Since reflection is always on, you will receive your own message back as a `CHAT_IN`. ``` toc_chat_send ``` **Example:** ``` toc_chat_send 0 "Hello everyone!" ``` ### toc_chat_whisper Send a private message within a chat room directed at a specific user. ``` toc_chat_whisper ``` **Example:** ``` toc_chat_whisper 0 toctest2 "Can you see this?" ``` ### toc_chat_invite Invite one or more users to a chat room you are currently in. ``` toc_chat_invite [ ...] ``` **Example:** ``` toc_chat_invite 0 "Come join us!" toctest2 joe ``` ### toc_chat_accept Accept a chat invitation received via `CHAT_INVITE`. The server will respond with `CHAT_JOIN`. ``` toc_chat_accept ``` **Example:** ``` toc_chat_accept 5 ``` ### toc_chat_leave Leave a chat room. ``` toc_chat_leave ``` **Example:** ``` toc_chat_leave 0 ``` ### toc_set_dir Set directory information. Fields are colon-separated within a quoted string. ``` toc_set_dir ``` **Fields (colon-separated):** `"first_name":"middle_name":"last_name":"maiden_name":"city":"state":"country":"email":"allow_web_search"` **Example:** ``` toc_set_dir "John":"":"Doe":"":"New York":"NY":"US":"john@example.com":"" ``` ### toc_get_dir Get a user's directory information. Returns a `GOTO_URL` or `ERROR`. ``` toc_get_dir ``` **Example:** ``` toc_get_dir toctest2 ``` ### toc_dir_search Search the user directory by field. Returns a `GOTO_URL` or `ERROR`. ``` toc_dir_search ``` **Fields (colon-separated):** `"first_name":"middle_name":"last_name":"maiden_name":"city":"state":"country":"email"` You can search by keyword by placing it in the 11th position: ``` toc_dir_search "::::::::":"":"search term" ``` **Example:** ``` toc_dir_search "John":"":"Doe":"":"":"":"":"" ``` ### toc_format_nickname Reformat the capitalization/spacing of your screen name. Returns `ADMIN_NICK_STATUS` and `NICK` on success, or `ERROR` on failure. ``` toc_format_nickname ``` **Example:** ``` toc_format_nickname "TocTest1" ``` ### toc_change_passwd Change your password. Returns `ADMIN_PASSWD_STATUS` on success or `ERROR` on failure. Passwords are sent as plaintext (not roasted). Special characters must be backslash-escaped (see [Escaping Rules](#8-escaping--encoding-rules)). Note: Because passwords are sent in cleartext (unlike the roasted password at login), this command is not secure against network eavesdropping. ``` toc_change_passwd ``` **Examples:** ``` toc_change_passwd oldpass newpass toc_change_passwd "my old pass" "my new pass" toc_change_passwd oldpa\$\$ newpa\$\$ ``` ### toc_rvous_accept Accept a rendezvous proposal (e.g. file transfer) from another user. ``` toc_rvous_accept ``` | Parameter | Description | |-----------|-------------| | screen_name | The user who sent the proposal | | cookie | Base64-encoded cookie from the `RVOUS_PROPOSE` message | | service_uuid | UUID of the service being accepted | **Example:** ``` toc_rvous_accept toctest2 fUdgNuQ6AAA= 09461343-4C7F-11D1-8222-444553540000 ``` ### toc_rvous_cancel Cancel/decline a rendezvous proposal from another user. ``` toc_rvous_cancel ``` **Example:** ``` toc_rvous_cancel toctest2 fUdgNuQ6AAA= 09461343-4C7F-11D1-8222-444553540000 ``` --- ## 4. Client → Server Commands (TOC 2) TOC 2 commands use the `toc2_` prefix and operate on the server-side buddy list (feedbag) directly. Changes are automatically saved. ### toc2_send_im Same syntax as `toc_send_im`. ``` toc2_send_im [auto] ``` **Example:** ``` toc2_send_im toctest2 "Hey there!" ``` ### toc2_send_im_enc Send an encoded instant message. Supports encoding and language parameters. ``` toc2_send_im_enc "F" [auto] ``` | Parameter | Description | |-----------|-------------| | destination_user | Normalized screen name | | "F" | Unknown flag, always `F` | | encoding | Character encoding (e.g. `A` for ASCII) | | language | Language code (e.g. `en`) | | message | Quoted, escaped message | | auto | Optional `auto` for auto-response | **Example:** ``` toc2_send_im_enc toctest2 "F" A en "Hello from TOC2!" ``` ### toc2_set_pdmode Set the permit/deny privacy mode. ``` toc2_set_pdmode ``` | Mode | Description | |------|-------------| | 1 | Allow all (default) | | 2 | Block all | | 3 | Allow permit list only | | 4 | Block deny list only | | 5 | Allow buddy list only | **Example:** ``` toc2_set_pdmode 1 ``` ### toc2_new_group Create a new buddy list group. ``` toc2_new_group ``` **Example:** ``` toc2_new_group "Work Friends" ``` ### toc2_del_group Delete a buddy list group and all buddies within it. ``` toc2_del_group ``` **Example:** ``` toc2_del_group "Work Friends" ``` ### toc2_new_buddies Add buddies to the server-side buddy list using a config-format string. If the specified group does not exist, it will be created. ``` toc2_new_buddies ``` **Config format:** `{g:\nb:[:]\nb:\n}` Where `\n` is a literal linefeed character (ASCII 10, `0x0A`). Extended buddy format with alias and note: `b:::::::note` **Examples:** Add two buddies to the "Friends" group: ``` toc2_new_buddies "{g:Friends\nb:toctest2\nb:joe\n}" ``` Add a buddy with an alias: ``` toc2_new_buddies "{g:Friends\nb:toctest2:Test User 2\n}" ``` ### toc2_remove_buddy Remove one or more buddies from a group. The last argument is always the group name. ``` toc2_remove_buddy [ ...] ``` **Examples:** ``` toc2_remove_buddy toctest2 "Friends" toc2_remove_buddy toctest2 joe "Friends" ``` ### toc2_add_permit Add users to the permit list (feedbag-based). ``` toc2_add_permit [ ...] ``` **Example:** ``` toc2_add_permit toctest2 joe ``` ### toc2_remove_permit Remove users from the permit list. ``` toc2_remove_permit [ ...] ``` **Example:** ``` toc2_remove_permit toctest2 ``` ### toc2_add_deny Add users to the deny (block) list (feedbag-based). ``` toc2_add_deny [ ...] ``` **Example:** ``` toc2_add_deny spammer ``` ### toc2_remove_deny Remove users from the deny (block) list. ``` toc2_remove_deny [ ...] ``` **Example:** ``` toc2_remove_deny spammer ``` ### toc2_client_event Send a typing notification to another user. ``` toc2_client_event ``` | Status | Description | |--------|-------------| | 0 | Idle (no activity) | | 1 | Text entered (paused typing) | | 2 | Currently typing | **Example:** ``` toc2_client_event toctest2 2 ``` --- ## 5. Server → Client Messages (TOC 1) Server messages use colons as separators. Messages are NOT null-terminated. When parsing, be aware that message content (IMs, chat messages) may contain colons — split with a maximum field count appropriate to each command. ### SIGN_ON Sent after a successful login. ``` SIGN_ON: ``` **Example:** ``` SIGN_ON:TOC1.0 ``` ### CONFIG The user's saved configuration (buddy list, permit/deny). Only sent for TOC 1 logins. Config may be empty if none was previously saved. ``` CONFIG: ``` Config format uses space-separated item types (same format as `toc_set_config`): ``` CONFIG:m 1 g Buddies b toctest2 b joe d spammer123 ``` Config may be empty (`CONFIG:`) if no configuration has been saved. ### NICK The user's properly formatted screen name. ``` NICK: ``` **Example:** ``` NICK:TocTest1 ``` ### IM_IN An incoming instant message. ``` IM_IN::: ``` Everything after the third colon is the message (may contain additional colons). **Examples:** ``` IM_IN:TocTest2:F:Hello there! IM_IN:TocTest2:T:I am away from my computer right now. IM_IN:TocTest2:F:Bold and italic ``` ### UPDATE_BUDDY Buddy presence update. Handles arrivals, departures, and status changes. ``` UPDATE_BUDDY:::::: ``` | Field | Description | |-------|-------------| | screen_name | Formatted screen name | | online | `T` if online, `F` if offline | | warning_level | Warning percentage (0-100) | | signon_time | Unix epoch timestamp of signon | | idle_minutes | Minutes idle (0 = active) | | user_class | 2-3 character class string (see below) | **User class characters:** | Position | Char | Meaning | |----------|------|---------| | uc[0] | `' '` | Normal | | uc[0] | `'A'` | On AOL | | uc[1] | `' '` | Normal | | uc[1] | `'A'` | Admin | | uc[1] | `'U'` | Unconfirmed | | uc[1] | `'O'` | OSCAR Free (normal AIM user) | | uc[1] | `'C'` | Mobile/wireless | | uc[2] | `' '` | Available | | uc[2] | `'U'` | Unavailable (away) | **Examples:** ``` UPDATE_BUDDY:TocTest2:T:0:1711036800:0: O UPDATE_BUDDY:TocTest2:T:0:1711036800:0: U UPDATE_BUDDY:TocTest2:F:0:0:0: UPDATE_BUDDY:TocTest2:T:20:1711036800:5: OU ``` ### ERROR An error response. May include a screen name or sub-error code as a variable argument. ``` ERROR:[:] ``` **Example:** ``` ERROR:901:toctest2 ERROR:980 ``` See [Error Codes](#7-error-codes) for the full list. ### EVILED The user has been warned. ``` EVILED:: ``` If the warning was anonymous, the eviler field is empty. **Examples:** ``` EVILED:20:TocTest2 EVILED:10: ``` ### CHAT_JOIN Successfully joined a chat room. The chat room ID is an integer assigned by the server — store it for subsequent chat commands. ``` CHAT_JOIN:: ``` **Example:** ``` CHAT_JOIN:0:My Chat Room ``` ### CHAT_IN A message received in a chat room. ``` CHAT_IN:::: ``` **Example:** ``` CHAT_IN:0:TocTest2:F:Hello everyone! ``` ### CHAT_UPDATE_BUDDY Users have joined or left a chat room. The first message of this type for a room contains the initial user list. ``` CHAT_UPDATE_BUDDY:::[:...] ``` | Field | Description | |-------|-------------| | inside | `T` = users arrived, `F` = users departed | **Examples:** ``` CHAT_UPDATE_BUDDY:0:T:TocTest1:TocTest2 CHAT_UPDATE_BUDDY:0:F:TocTest2 ``` ### CHAT_INVITE An invitation to join a chat room. ``` CHAT_INVITE:::: ``` **Example:** ``` CHAT_INVITE:My Chat Room:5:TocTest2:Come join us! ``` ### CHAT_LEFT Confirmation that you have left a chat room. ``` CHAT_LEFT: ``` **Example:** ``` CHAT_LEFT:0 ``` ### GOTO_URL Directs the client to open a URL (for profiles, directory info, search results). ``` GOTO_URL:: ``` **Example:** ``` GOTO_URL:profile:info?cookie=abc123&user=toctest2&from=toctest1 ``` ### DIR_STATUS Result of a `toc_set_dir` command. ``` DIR_STATUS: ``` Return code 0 indicates success. ### ADMIN_NICK_STATUS Result of a `toc_format_nickname` command. ``` ADMIN_NICK_STATUS: ``` Return code 0 indicates success. **Example:** ``` ADMIN_NICK_STATUS:0 ``` ### ADMIN_PASSWD_STATUS Result of a `toc_change_passwd` command. ``` ADMIN_PASSWD_STATUS: ``` Return code 0 indicates success. ### RVOUS_PROPOSE Another user proposes a rendezvous (file transfer, etc.). ``` RVOUS_PROPOSE::::::::[::...] ``` | Field | Description | |-------|-------------| | user | Screen name of the proposer | | uuid | Service UUID (e.g. file transfer) | | cookie | Base64-encoded session cookie | | seq | Sequence number | | rvous_ip | Rendezvous IP address | | proposer_ip | Proposer's IP address | | verified_ip | Server-verified IP address | | port | Port number for direct connection | | tlv pairs | Additional base64-encoded TLV data | **Example:** ``` RVOUS_PROPOSE:TocTest2:09461343-4C7F-11D1-8222-444553540000:fUdgNuQ6AAA=:1:192.168.1.5:192.168.1.5:203.0.113.1:5190:10001:ABIAAgAAAAEA ``` ### PAUSE Server requests the client to pause. A new `SIGN_ON` will follow when the server is ready. The buddy list and permit/deny items must be resent, followed by `toc_init_done`. ``` PAUSE ``` --- ## 6. Server → Client Messages (TOC 2) TOC 2 extends the server messages with richer variants. When logged in via `toc2_signon` or `toc2_login`, these messages are sent instead of (or in addition to) their TOC 1 equivalents. ### SIGN_ON (TOC 2) ``` SIGN_ON:TOC2.0 ``` ### CONFIG2 Server-side buddy list configuration, sent at login. Fields are separated by linefeeds (`\n`, ASCII 10). Colons separate sub-fields within each line. ``` CONFIG2: ``` **Config line types:** | Prefix | Format | Description | |--------|--------|-------------| | `g:` | `g:` | Buddy group | | `b:` | `b:[:][:::::note]` | Buddy entry (with optional alias and note) | | `d:` | `d:` | Deny list entry | | `p:` | `p:` | Permit list entry | | `m:` | `m:` | Privacy mode (1-5, same as `toc2_set_pdmode`) | | `done:` | `done:` | End of config | **Example:** ``` CONFIG2:g:Buddies b:toctest2:Test User b:joe d:spammer m:1 done: ``` ### NICK (TOC 2) Same as TOC 1: ``` NICK: ``` ### IM_IN2 Incoming instant message (TOC 2 variant). Adds a whisper field. ``` IM_IN2:::: ``` **Example:** ``` IM_IN2:TocTest2:F:F:Hello from TOC2! ``` ### IM_IN_ENC2 Incoming encoded instant message (TOC 2 with `toc2_login`). Includes user class and language information. ``` IM_IN_ENC2::::::::: ``` | Field | Description | |-------|-------------| | user | Sender's screen name | | auto | `T` if auto-response, `F` otherwise | | unknown1 | Typically `F` | | unknown2 | Typically `T` | | user_class | Same as UPDATE_BUDDY user class (e.g. ` O `, ` OU`) | | unknown3 | Typically `F` | | unknown4 | Typically `L` | | language | Language code (e.g. `en`) | | message | The message content (may contain colons) | **Example:** ``` IM_IN_ENC2:TocTest2:F:F:T: O :F:L:en:Hello from TOC2! IM_IN_ENC2:TocTest2:T:F:T: OU:F:L:en:I am away right now. ``` ### UPDATE_BUDDY2 Buddy presence update (TOC 2). Same as `UPDATE_BUDDY` with a trailing field. ``` UPDATE_BUDDY2::::::: ``` The trailing unknown field is typically empty. **Examples:** ``` UPDATE_BUDDY2:TocTest2:T:0:1711036800:0: O : UPDATE_BUDDY2:TocTest2:F:0:0:0: : ``` ### BUDDY_CAPS2 Sent alongside `UPDATE_BUDDY2` to describe a buddy's capabilities. ``` BUDDY_CAPS2::,,... ``` Capabilities are UUIDs (see [Capabilities](#9-capabilities-uuids)). **Example:** ``` BUDDY_CAPS2:TocTest2:748f2420-6287-11d1-8222-444553540000,09461343-4c7f-11d1-8222-444553540000 ``` ### CHAT_IN_ENC Encoded chat message (TOC 2 with `toc2_login`). ``` CHAT_IN_ENC:::::: ``` The unknown field is typically `A`. **Example:** ``` CHAT_IN_ENC:0:TocTest2:F:A:en:Hello everyone! ``` ### NEW_BUDDY_REPLY2 Confirmation after adding a buddy via `toc2_new_buddies`. ``` NEW_BUDDY_REPLY2:: ``` | Action | Description | |--------|-------------| | `added` | Buddy was added successfully | | `auth` | ICQ authorization request sent | **Example:** ``` NEW_BUDDY_REPLY2:toctest2:added ``` ### CLIENT_EVENT2 Typing notification from another user. ``` CLIENT_EVENT2:: ``` | Status | Description | |--------|-------------| | 0 | No activity (stopped typing) | | 1 | Text entered (paused) | | 2 | Currently typing | **Example:** ``` CLIENT_EVENT2:TocTest2:2 ``` ### INSERTED2 Dynamic buddy list update — items added from another session. **Group added:** ``` INSERTED2:g: ``` **Buddy added:** ``` INSERTED2:b::: ``` **Deny list entry added:** ``` INSERTED2:d: ``` **Permit list entry added:** ``` INSERTED2:p: ``` **Examples:** ``` INSERTED2:g:New Group INSERTED2:b:My Friend:toctest2:Buddies INSERTED2:b::joe:Buddies INSERTED2:d:spammer INSERTED2:p:trusteduser ``` ### DELETED2 Dynamic buddy list update — items removed from another session. **Group deleted:** ``` DELETED2:g: ``` **Buddy deleted:** ``` DELETED2:b:: ``` **Deny list entry removed:** ``` DELETED2:d: ``` **Permit list entry removed:** ``` DELETED2:p: ``` **Examples:** ``` DELETED2:g:Old Group DELETED2:b:toctest2:Buddies DELETED2:d:spammer ``` ### BART2 Buddy icon (Buddy Art) information. Structure is not fully understood. ``` BART2:: ``` --- ## 7. Error Codes Errors are sent as `ERROR:[:]`. The variable argument (if present) is typically a screen name or sub-error code. ### General Errors | Code | Description | |------|-------------| | 901 | `$1` not currently available | | 902 | Warning of `$1` not currently available | | 903 | Message dropped, server speed limit exceeded | ### Admin Errors | Code | Description | |------|-------------| | 911 | Error validating input | | 912 | Invalid account | | 913 | Error encountered while processing request | | 914 | Service unavailable | ### Chat Errors | Code | Description | |------|-------------| | 950 | Chat in `$1` is unavailable | ### IM & Info Errors | Code | Description | |------|-------------| | 960 | Sending messages too fast to `$1` | | 961 | Missed an IM from `$1` because it was too big | | 962 | Missed an IM from `$1` because it was sent too fast | ### Directory Errors | Code | Description | |------|-------------| | 970 | Failure | | 971 | Too many matches | | 972 | Need more qualifiers | | 973 | Dir service temporarily unavailable | | 974 | Email lookup restricted | | 975 | Keyword ignored | | 976 | No keywords | | 977 | Language not supported | | 978 | Country not supported | | 979 | Failure unknown `$1` | ### Auth Errors | Code | Description | |------|-------------| | 980 | Incorrect nickname or password | | 981 | Service temporarily unavailable | | 982 | Warning level too high to sign on | | 983 | Connecting/disconnecting too frequently (wait 10 minutes) | | 989 | Unknown signon error `$1` | **Sub-error codes for 989:** | Sub-code | Description | |----------|-------------| | 0 | Signed on too soon | | 7 | Invalid screen name or password | | 17 | Suspended account | --- ## 8. Escaping & Encoding Rules ### 8.1 Client → Server (Encoding) When sending commands to the server, certain characters must be **backslash-escaped** whether inside quotes or not: | Character | Escaped | |-----------|---------| | `\` | `\\` | | `$` | `\$` | | `"` | `\"` | | `(` | `\(` | | `)` | `\)` | | `{` | `\{` | | `}` | `\}` | | `[` | `\[` | | `]` | `\]` | **Example:** To send the message `He said "hello" (wow) for $5`: ``` toc_send_im toctest2 "He said \"hello\" \(wow\) for \$5" ``` ### 8.2 Screen Name Normalization When sending screen names to the server, **normalize** them: 1. Convert to lowercase. 2. Remove all spaces. Example: `Toc Test 1` → `toctest1` ### 8.3 Server → Client (No Encoding) Server messages are NOT encoded. They use colons as delimiters. When parsing, limit the number of splits to avoid breaking messages that contain colons. ### 8.4 Null Termination - **Client → Server:** All FLAP DATA payloads MUST end with a null byte (`0x00`). Include it in the FLAP data length. - **Server → Client:** FLAP DATA payloads are NOT null-terminated. --- ## 9. Capabilities (UUIDs) Capabilities indicate which features a client supports. They are set via `toc_set_caps` and reported via `BUDDY_CAPS2`. ### Standard Capabilities | Name | UUID | |------|------| | Voice Chat | `09461341-4C7F-11D1-8222-444553540000` | | File Send | `09461343-4C7F-11D1-8222-444553540000` | | Image | `09461345-4C7F-11D1-8222-444553540000` | | Buddy Icon | `09461346-4C7F-11D1-8222-444553540000` | | Stocks | `09461347-4C7F-11D1-8222-444553540000` | | File Get | `09461348-4C7F-11D1-8222-444553540000` | | Games | `0946134A-4C7F-11D1-8222-444553540000` | | Send Buddy List | `0946134B-4C7F-11D1-8222-444553540000` | | AIM/ICQ Interop | `0946134D-4C7F-11D1-8222-444553540000` | | Chat | `748F2420-6287-11D1-8222-444553540000` | ### Short Capability Format Some clients send capabilities as short hex codes (1-4 hex digits). These expand to the full OSCAR capability UUID format: `0946XXYY-4C7F-11D1-8222-444553540000` where `XXYY` is the short code zero-padded to 4 hex digits. **Example:** Short cap `1343` → `09461343-4C7F-11D1-8222-444553540000` (File Send) --- ## 10. Complete Session Examples ### 10.1 TOC 1 Session (Minimal) This example shows a complete TOC 1 session: login, add a buddy, send a message, and disconnect. **Wire-level (showing FLAP framing conceptually):** ``` → TCP connect to server:9898 → "FLAPON\r\n\r\n" ← [FLAP SIGNON] version=1 → [FLAP SIGNON] version=1, TLV(1)="toctest1" → [FLAP DATA] toc_signon login.oscar.aol.com 5190 toctest1 0x2408105c23001130 english "TIC:Example" ← [FLAP DATA] SIGN_ON:TOC1.0 ← [FLAP DATA] CONFIG:m 1\ng Buddies\nb toctest2\n ← [FLAP DATA] NICK:toctest1 → [FLAP DATA] toc_add_buddy toctest2 → [FLAP DATA] toc_init_done ← [FLAP DATA] UPDATE_BUDDY:toctest2:T:0:1711036800:0: O → [FLAP DATA] toc_send_im toctest2 "Hello!" → [FLAP DATA] toc_set_away "Gone fishing" → [FLAP SIGNOFF] ``` ### 10.2 TOC 2 Session (toc2_login) ``` → TCP connect to server:9898 → "FLAPON\r\n\r\n" ← [FLAP SIGNON] version=1 → [FLAP SIGNON] version=1, TLV(1)="toctest1" → [FLAP DATA] toc2_login login.oscar.aol.com 5190 toctest1 0x2408105c23001130 english "TIC:Example" 160 US "" "" 3 0 30303 -kentucky -utf8 103547776 ← [FLAP DATA] SIGN_ON:TOC2.0 ← [FLAP DATA] NICK:toctest1 ← [FLAP DATA] CONFIG2:g:Buddies\nb:toctest2:Test User\nm:1\ndone:\n → [FLAP DATA] toc_init_done ← [FLAP DATA] UPDATE_BUDDY2:toctest2:T:0:1711036800:0: O : ← [FLAP DATA] BUDDY_CAPS2:toctest2:748f2420-6287-11d1-8222-444553540000 → [FLAP DATA] toc2_new_buddies "{g:Friends\nb:joe\n}" ← [FLAP DATA] NEW_BUDDY_REPLY2:joe:added → [FLAP DATA] toc2_send_im_enc toctest2 "F" A en "Hello from TOC2!" → [FLAP DATA] toc2_client_event toctest2 2 → [FLAP DATA] toc2_set_pdmode 1 → [FLAP SIGNOFF] ``` ### 10.3 Chat Session ``` → toc_chat_join 4 "Retro Chat" ← CHAT_JOIN:0:Retro Chat ← CHAT_UPDATE_BUDDY:0:T:toctest1 → toc_chat_send 0 "Hello room!" ← CHAT_IN:0:toctest1:F:Hello room! ← CHAT_UPDATE_BUDDY:0:T:toctest2 → toc_chat_invite 0 "Come chat!" joe → toc_chat_send 0 "Welcome toctest2!" ← CHAT_IN:0:toctest1:F:Welcome toctest2! → toc_chat_leave 0 ← CHAT_LEFT:0 ``` ### 10.4 Python Client Example A minimal Python client that connects, logs in, sends a message, and reads responses: ```python import socket import struct ROAST = "Tic/Toc" def roast_password(password): result = [] for i, ch in enumerate(password): xored = ord(ch) ^ ord(ROAST[i % len(ROAST)]) result.append(f"{xored:02x}") return "0x" + "".join(result) def send_flap(sock, frame_type, seq, payload): data = payload.encode("ascii") if isinstance(payload, str) else payload if frame_type == 2: data += b"\x00" # null-terminate DATA frames header = struct.pack("!BBHH", 0x2A, frame_type, seq, len(data)) sock.sendall(header + data) return seq + 1 def recv_flap(sock): header = b"" while len(header) < 6: chunk = sock.recv(6 - len(header)) if not chunk: raise ConnectionError("Connection closed") header += chunk marker, frame_type, seq, length = struct.unpack("!BBHH", header) payload = b"" while len(payload) < length: chunk = sock.recv(length - len(payload)) if not chunk: raise ConnectionError("Connection closed") payload += chunk return frame_type, seq, payload def normalize(screen_name): return screen_name.lower().replace(" ", "") def escape(text): for ch in r'\$"(){}[]': text = text.replace(ch, "\\" + ch) return text def main(): HOST = "127.0.0.1" PORT = 9898 USERNAME = "toctest1" PASSWORD = "testpass1" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT)) sock.settimeout(5) # Step 1: Send FLAPON sock.sendall(b"FLAPON\r\n\r\n") # Step 2: Receive server SIGNON frame frame_type, seq, payload = recv_flap(sock) assert frame_type == 1, f"Expected SIGNON frame, got {frame_type}" # Step 3: Send client SIGNON frame sn = normalize(USERNAME).encode("ascii") signon_payload = struct.pack("!IHH", 1, 1, len(sn)) + sn seq_out = send_flap(sock, 1, 0, signon_payload) # Step 4: Send toc_signon roasted = roast_password(PASSWORD) cmd = f'toc_signon login.oscar.aol.com 5190 {normalize(USERNAME)} {roasted} english "TIC:PythonTOC"' seq_out = send_flap(sock, 2, seq_out, cmd) # Step 5: Read responses for _ in range(10): try: frame_type, seq, payload = recv_flap(sock) if frame_type == 2: print(f"← {payload.decode('ascii', errors='replace')}") except socket.timeout: break # Step 6: Send init_done seq_out = send_flap(sock, 2, seq_out, "toc_init_done") # Step 7: Send a message msg = escape("Hello from Python!") seq_out = send_flap(sock, 2, seq_out, f'toc_send_im toctest2 "{msg}"') # Read any remaining responses for _ in range(10): try: frame_type, seq, payload = recv_flap(sock) if frame_type == 2: print(f"← {payload.decode('ascii', errors='replace')}") except socket.timeout: break # Disconnect send_flap(sock, 4, seq_out, b"") sock.close() if __name__ == "__main__": main() ```