I/O in tin (updated 05/01/98) ---------- All critical I/O, be it NNTP data or not, should be done with tin_fgets() This handles data formatting, removes any trailing \n and \r and deals with timeouts, reconnections and user aborts. It always returns a full line of data - all memory management is handled internally. It supports the use of 'q' to cancel the operation and 'Q' to exit tin without error recovery. tin_errno will be set to !0 to flag errors. Currently the only supported error is 'user aborted with q'. Closing data streams should be done with TIN_FCLOSE(fp) as the NNTP socket should be kept open, whereas local spool fd's must be closed. TIN_FCLOSE() takes care of this. If you wish to quit reading an NNTP stream, then call drain_buffer(fp) to clear out any pending data on the NNTP socket. nntp_command(command, valid_response, rest_of_data) should be used for sending all generic NNTP command. It returns an fd to the open stream for reading the rest of the data. Example of a typical exchange: if ((fp = nntp_command ("GROUP comp.thing", OK_GROUP, NULL)) != NULL) { while ((ptr = tin_fgets(fp, FALSE)) != NULL) process_data(ptr); #ifdef NNTP_ABLE if (ptr) drain_buffer(fp); #endif /* NNTP_ABLE */ TIN_FCLOSE(fp); if (tin_errno) handle_abort(); } Hashing in tin (updated 05/01/98) -------------- All the main arrays in tin are dynamically managed by functions in memory.c They are preallocated to an initial size and then grown if the high water mark is exceeded. The main structures are: active[] An array of all the groups in the active file arts[] This is an array of the article headers for the current group. Only headers present in the overview (NOV) database are stored. base[] An array of integers that represent the index in arts[] of the current root article for each displayed thread. group_hash[] active[] is hashed for faster access. An entry of -1 denotes no group at this hashnode, >= 0 denotes an index into active[] Multiple groups on one node are chained via the .next field (another index ptr to active[]) my_group[] List of integer pointers into active[] These are the groups that actually appear on the selection screen msgids[] Hashed array of all the individual message-ids in arts[] All the Message-ID and Reference headers are broken down and stored here. They are linked together by parent, sibling and child pointers table[] Hash of the key text headers from the articles, to save space and speed up searches and compares. The functions that manipulate the above include: active.c: read_news_active_file() populates active[] using group_add() art.c: Many of the overview headers are stored with hash_str() base[] is populated by find_base() hashstr.c: hash_str() Hashes text strings In the article header, the following text is hashed: From: (including full name if supplied) Subject: list.c: init_group_hash() clears group_hash[] find_group_index() returns index of group in active[] group_find() returns a pointer to a group in active[] group_add() adds a group into active[] and hashes it in group_hash[] hash_groupname() returns hash key for a group This is also used to hash the actual filenames written in ~/.tin/.news (when not using NNTP) There is experimental code here for a (presumably) improved hash function that was never completed. main.c: Just the initializers for hashing memory.c: Dynamic array management. hash_reclaim() - free up table[] which holds the text cache refs.c: Handling for msgids[] When threading, each msgid in the hash has a pointer back to its article header in arts[] or ART_UNAVAILABLE if the article is not available select.c: my_group_add() adds a group to my_group[] my_group_find() returns the index of a group in my_group[]