# TOC Protocol Specification Version: TOC 1.0 / TOC 2.0 This document is a 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 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). 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 | User 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() ```