+//
+// back end for the XOVER command , called for each message number
+//
+void nntp_xover_backend(long msgnum, void *userdata) {
+
+ struct listgroup_range *lr = (struct listgroup_range *)userdata;
+
+ // check range if supplied
+ if (msgnum < lr->lo) return;
+ if ((lr->hi != 0) && (msgnum > lr->hi)) return;
+
+ struct CtdlMessage *msg = CtdlFetchMessage(msgnum, 0, 1);
+ if (msg == NULL) {
+ return;
+ }
+
+ // Teh RFC says we need:
+ // -------------------------
+ // Subject header content
+ // From header content
+ // Date header content
+ // Message-ID header content
+ // References header content
+ // :bytes metadata item
+ // :lines metadata item
+
+ time_t msgtime = atol(msg->cm_fields[eTimestamp]);
+ char strtimebuf[26];
+ ctime_r(&msgtime, strtimebuf);
+
+ // here we go -- print the line o'data
+ cprintf("%ld\t%s\t%s <%s>\t%s\t%s\t%s\t100\t10\r\n",
+ msgnum,
+ msg->cm_fields[eMsgSubject],
+ msg->cm_fields[eAuthor],
+ msg->cm_fields[erFc822Addr],
+ strtimebuf,
+ msg->cm_fields[emessageId],
+ msg->cm_fields[eWeferences]
+ );
+
+ CM_Free(msg);
+}
+
+
+//
+//
+// XOVER is used by some clients, even if we don't offer it
+//
+void nntp_xover(const char *cmd) {
+ if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
+
+ citnntp *nntpstate = (citnntp *) CC->session_specific_data;
+ char range[256];
+ struct listgroup_range lr;
+
+ extract_token(range, cmd, 1, ' ', sizeof range);
+ lr.lo = atol(range);
+ if (lr.lo <= 0) {
+ lr.lo = nntpstate->current_article_number;
+ lr.hi = nntpstate->current_article_number;
+ }
+ else {
+ char *dash = strchr(range, '-');
+ if (dash != NULL) {
+ ++dash;
+ lr.hi = atol(dash);
+ if (lr.hi == 0) {
+ lr.hi = LONG_MAX;
+ }
+ if (lr.hi < lr.lo) {
+ lr.hi = lr.lo;
+ }
+ }
+ else {
+ lr.hi = lr.lo;
+ }
+ }
+
+ cprintf("224 Overview information follows\r\n");
+ CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, nntp_xover_backend, &lr);
+ cprintf(".\r\n");
+}
+
+