Protocol API¶
API reference for Gopher protocol types.
ItemType¶
ItemType
¶
Bases: str, Enum
Gopher item types.
Each item in a Gopher directory has a single-character type that indicates what kind of resource it represents. The canonical types are defined in RFC 1436, with additional types added by common extensions.
TEXT
class-attribute
instance-attribute
¶
Text file (item is a file that may be displayed).
DIRECTORY
class-attribute
instance-attribute
¶
Gopher directory (item leads to another menu).
CSO
class-attribute
instance-attribute
¶
CSO phone-book server (item refers to a name server).
DOS_BINARY
class-attribute
instance-attribute
¶
DOS binary archive (e.g., .zip files).
SEARCH
class-attribute
instance-attribute
¶
Index-Search server (item refers to a search engine).
BINARY
class-attribute
instance-attribute
¶
Binary file (client must read until connection closes).
is_informational
property
¶
Check if this item type is informational (not selectable).
from_char
classmethod
¶
Get ItemType from a single character.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
char
|
str
|
Single character representing the item type. |
required |
Returns:
| Type | Description |
|---|---|
ItemType
|
The corresponding ItemType. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the character is not a known item type. |
Source code in src/mototli/protocol/item_types.py
GopherRequest¶
GopherRequest
dataclass
¶
GopherRequest(
selector: str,
search_query: str | None = None,
request_type: RequestType = RequestType.STANDARD,
view_type: str | None = None,
client_ip: str | None = None,
)
Represents a Gopher protocol request.
A Gopher request consists of: - A selector string (path to the resource) - Optional search query (for type 7 search servers) - Optional Gopher+ modifier
The wire format is: selector[TAB search][TAB modifier]CRLF
Attributes:
| Name | Type | Description |
|---|---|---|
selector |
str
|
The resource selector (path). |
search_query |
str | None
|
Optional search query for type 7 servers. |
request_type |
RequestType
|
Gopher+ request type modifier. |
view_type |
str | None
|
Gopher+ specific view type to request. |
client_ip |
str | None
|
IP address of the client (server-side only). |
Examples:
__str__
¶
Return a human-readable string representation of the request.
Source code in src/mototli/protocol/request.py
from_line
classmethod
¶
Parse a Gopher request from a request line.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
line
|
bytes
|
The request line (without trailing CRLF). |
required |
Returns:
| Type | Description |
|---|---|
GopherRequest
|
A GopherRequest instance. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the request line is invalid or too long. |
Examples:
>>> request = GopherRequest.from_line(b"/search\tquery\t+")
>>> request.request_type
<RequestType.PLUS: '+'>
Source code in src/mototli/protocol/request.py
to_bytes
¶
Serialize the request to bytes for transmission.
Returns:
| Type | Description |
|---|---|
bytes
|
The request as bytes, ready to send over the network. |
Examples:
Source code in src/mototli/protocol/request.py
RequestType¶
RequestType
¶
Bases: str, Enum
Gopher+ request type modifiers.
These modifiers change the behavior of Gopher+ requests: - STANDARD: Normal Gopher request (no modifier) - PLUS: Request with Gopher+ attributes and content - ATTRIBUTES: Request Gopher+ attributes only (no content) - DIRECTORY: Request directory entry for the item
GopherResponse¶
GopherResponse
dataclass
¶
GopherResponse(
items: list[GopherItem] = list(),
raw_body: bytes | None = None,
is_directory: bool = True,
attributes: GopherAttributes | None = None,
)
Represents a complete Gopher protocol response.
A Gopher response can be either: - A directory listing (list of GopherItems) - Raw content (text file, binary, etc.)
Attributes:
| Name | Type | Description |
|---|---|---|
items |
list[GopherItem]
|
List of items for directory responses. |
raw_body |
bytes | None
|
Raw response body for non-directory responses. |
is_directory |
bool
|
Whether this is a directory listing. |
attributes |
GopherAttributes | None
|
Gopher+ attributes (if requested). |
Examples:
>>> response = GopherResponse(items=[
... GopherItem(ItemType.TEXT, "Hello", "/hello", "localhost"),
... ])
>>> response.is_directory
True
text
property
¶
Get the response body as text (for non-directory responses).
Returns:
| Type | Description |
|---|---|
str | None
|
The body decoded as UTF-8, or None for directory responses. |
__str__
¶
Return a human-readable representation.
Source code in src/mototli/protocol/response.py
from_bytes
classmethod
¶
Parse a Gopher response from raw bytes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
The raw response data. |
required |
is_directory
|
bool
|
Whether to parse as a directory listing. |
True
|
Returns:
| Type | Description |
|---|---|
GopherResponse
|
A GopherResponse instance. |
Examples:
>>> data = b"0Hello\t/hello\tlocalhost\t70\r\n.\r\n"
>>> response = GopherResponse.from_bytes(data)
>>> len(response.items)
1
Source code in src/mototli/protocol/response.py
to_bytes
¶
Serialize this response to bytes for transmission.
Returns:
| Type | Description |
|---|---|
bytes
|
The response as bytes, ready to send over the network. |
Source code in src/mototli/protocol/response.py
GopherItem¶
GopherItem
dataclass
¶
GopherItem(
item_type: ItemType,
display_text: str,
selector: str,
hostname: str,
port: int = DEFAULT_PORT,
gopher_plus: bool = False,
)
Represents a single item in a Gopher directory listing.
Each line in a Gopher directory follows this format: TYPE DISPLAY_TEXT TAB SELECTOR TAB HOSTNAME TAB PORT CRLF
Where TYPE is a single character indicating the item type.
Attributes:
| Name | Type | Description |
|---|---|---|
item_type |
ItemType
|
The type of this item (text, directory, etc.). |
display_text |
str
|
Human-readable text shown to the user. |
selector |
str
|
Path/selector to request this item. |
hostname |
str
|
Server hostname where this item is located. |
port |
int
|
Server port (default 70). |
gopher_plus |
bool
|
Whether this server supports Gopher+. |
Examples:
>>> item = GopherItem(
... item_type=ItemType.TEXT,
... display_text="About this server",
... selector="/about",
... hostname="example.com",
... )
>>> item.to_line()
b'0About this server\t/about\texample.com\t70\r\n'
__str__
¶
from_line
classmethod
¶
Parse a Gopher item from a directory listing line.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
line
|
bytes
|
A single line from a Gopher directory listing. |
required |
Returns:
| Type | Description |
|---|---|
GopherItem
|
A GopherItem instance. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the line is malformed. |
Examples:
>>> item = GopherItem.from_line(
... b"0About\t/about\texample.com\t70\r\n"
... )
>>> item.item_type
<ItemType.TEXT: '0'>
Source code in src/mototli/protocol/response.py
to_line
¶
Serialize this item to a directory listing line.
Returns:
| Type | Description |
|---|---|
bytes
|
The item as bytes, suitable for a Gopher response. |
Source code in src/mototli/protocol/response.py
GopherAttributes¶
GopherAttributes
dataclass
¶
GopherAttributes(
info: GopherItem | None = None,
admin: str | None = None,
admin_email: str | None = None,
mod_date: datetime | None = None,
creation_date: datetime | None = None,
views: list[ViewInfo] = list(),
abstract: str | None = None,
ask_fields: list[AskField] = list(),
raw: str = "",
)
Gopher+ attribute block.
Contains metadata about a Gopher+ item including administrative information, available views, and descriptions.
Attributes:
| Name | Type | Description |
|---|---|---|
info |
GopherItem | None
|
The +INFO line (parsed as GopherItem). |
admin |
str | None
|
Administrator name/description. |
admin_email |
str | None
|
Administrator email address. |
mod_date |
datetime | None
|
Last modification date. |
creation_date |
datetime | None
|
Creation date. |
views |
list[ViewInfo]
|
Available views/representations. |
abstract |
str | None
|
Item description/abstract. |
ask_fields |
list[AskField]
|
ASK block fields for forms. |
raw |
str
|
The raw attribute block text. |
Examples:
>>> attrs = GopherAttributes.parse('''
... +INFO: 0About this server\t/about\texample.com\t70
... +ADMIN:
... Admin: John Doe <john@example.com>
... +ABSTRACT:
... Information about this Gopher server.
... ''')
>>> attrs.abstract
'Information about this Gopher server.'
parse
classmethod
¶
Parse a Gopher+ attribute block.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
block
|
str
|
The raw attribute block text. |
required |
Returns:
| Type | Description |
|---|---|
GopherAttributes
|
A GopherAttributes instance. |
Source code in src/mototli/protocol/attributes.py
to_string
¶
Serialize this attribute block to a string.
Returns:
| Type | Description |
|---|---|
str
|
The attribute block as a string. |
Source code in src/mototli/protocol/attributes.py
ViewInfo¶
ViewInfo
dataclass
¶
ViewInfo(
mime_type: str,
language: str | None = None,
size: str | None = None,
size_bytes: int | None = None,
)
Represents a single view/representation in Gopher+.
Attributes:
| Name | Type | Description |
|---|---|---|
mime_type |
str
|
The MIME type of this view. |
language |
str | None
|
Optional language code. |
size |
str | None
|
Optional size in bytes (as string with units like "<10k>"). |
size_bytes |
int | None
|
Parsed size in bytes (if available). |
parse
classmethod
¶
Parse a view line from Gopher+ VIEWS block.
Format: MIME/type [language]:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
line
|
str
|
A single view specification line. |
required |
Returns:
| Type | Description |
|---|---|
ViewInfo
|
A ViewInfo instance. |
Examples:
Source code in src/mototli/protocol/attributes.py
to_string
¶
Serialize this view to a string.
Source code in src/mototli/protocol/attributes.py
Usage Examples¶
Working with ItemType¶
from mototli.protocol import ItemType
# Parse from character
item_type = ItemType.from_char("0") # ItemType.TEXT
item_type = ItemType.from_char("1") # ItemType.DIRECTORY
# Check categories
if item_type.is_text:
print("This is a text file")
elif item_type.is_binary:
print("This is a binary file")
elif item_type.is_directory:
print("This is a directory")
# Get character value
print(item_type.value) # "0", "1", etc.
Working with GopherRequest¶
from mototli.protocol import GopherRequest, RequestType
# Parse from wire format
request = GopherRequest.from_line(b"/gopher\r\n")
print(request.selector) # "/gopher"
print(request.request_type) # RequestType.NORMAL
# Gopher+ requests
request = GopherRequest.from_line(b"/gopher$\r\n")
print(request.request_type) # RequestType.ATTRIBUTE_ONLY
# Serialize to wire format
data = request.to_bytes()
Working with GopherResponse¶
from mototli.protocol import GopherResponse
# Parse directory response
data = b"0Text file\t/file.txt\tlocalhost\t70\r\n.\r\n"
response = GopherResponse.from_bytes(data, is_directory=True)
for item in response.items:
print(f"[{item.item_type.value}] {item.display_text}")
print(f" Selector: {item.selector}")
print(f" Host: {item.host}:{item.port}")
Working with GopherItem¶
from mototli.protocol import GopherItem, ItemType
# Create an item
item = GopherItem(
item_type=ItemType.TEXT,
display_text="My Text File",
selector="/file.txt",
host="localhost",
port=70
)
# Serialize to gophermap format
line = item.to_line()
Working with Attributes¶
from mototli.protocol import GopherAttributes
# Parse attribute block
block = b"+INFO: 0file.txt\t/file.txt\tlocalhost\t70\t+\r\n"
block += b"+ADMIN:\r\n Admin: Name <email>\r\n"
attrs = GopherAttributes.parse(block)
print(attrs.info.display_text)
print(attrs.admin.name)
print(attrs.admin.email)
Helper Functions¶
from mototli.protocol import create_info_item, create_error_item
# Create info line for gophermap
info = create_info_item("Welcome to my site!")
# Create error response
error = create_error_item("File not found")
Constants¶
See Also¶
- Item Types Reference - Type codes
- Gopher Protocol - Protocol overview
- Gopher+ Extensions - Gopher+ details