package commonsNet.nntp
import std.io.OutputStream
import std.console.Console
import std.collection.ArrayList
/**
* 包含消息检索和线程处理所需的基本状态的类。
*/
public class Article <: Threadable & ToString {
/**
* 遍历已连接的Article对象的线程树并将其打印出来的递归方法。
*
* @param article 文章树的根
*/
public static func printThread(article: Article): Unit {
printThread(article, 0, Console.stdOut)
}
/**
* 遍历已连接的Article对象的线程树并将其打印出来的递归方法。
*
* @param article 文章树的根
* @param depth 当前树的深度
*/
public static func printThread(article: Article, depth: Int64): Unit {
printThread(article, depth, Console.stdOut)
}
/**
* 遍历已连接的Article对象的线程树并将其打印出来的递归方法。
*
* @param article 文章树的根
* @param depth 当前树的深度
* @param ps 输出流
*/
public static func printThread(article: Article, depth: Int64, out: OutputStream): Unit {
for (i in 0..depth) {
out.write("==>".toArray())
}
out.write("${article.getSubject()}\t${article.getFrom()}\t${article.getArticleId()}\t\n".toArray())
if (let Some(kid) <- article.kid) {
printThread(kid, depth + 1, out)
}
if (let Some(next) <- article.next) {
printThread(next, depth, out)
}
}
/**
* 遍历已连接的Article对象的线程树并将其打印出来的递归方法。
*
* @param article 文章树的根
* @param ps 输出流
*/
public static func printThread(article: Article, out: OutputStream) {
printThread(article, 0, out)
}
private var articleNumber: Int64 = -1
private var subject: String = ""
private var date: String = ""
private var articleId: String = ""
private var simplifiedSubjectCache: String = ""
private var `from`: String = ""
private var references: ?ArrayList<String> = None
private var isReply: Bool = false
public var kid: ?Article = None
public var next: ?Article = None
public init() {
articleNumber = -1 // isDummy
}
/**
* 将消息id添加到此消息的引用列表(即回复)
* @param msgId 要添加的消息id
*/
public func addReference(msgId: String) {
if (msgId.isEmpty()) {
return
}
if (references == None) {
references = ArrayList<String>()
}
let refs = references.getOrThrow()
isReply = true
refs.appendAll(msgId.split(" "))
}
/**
* 清除主题缓存
*/
private func flushSubjectCache() {
simplifiedSubjectCache = ""
}
public func getArticleId() {
return articleId
}
public func getArticleNumber() {
return articleNumber
}
public func getDate() {
return date
}
public func getFrom() {
return `from`
}
/**
* 以字符串数组的形式返回引用的消息id
*
* @return 消息id数组
*/
public func getReferences(): Array<String> {
return references?.toArray() ?? []
}
public func getSubject() {
return subject
}
public override func isDummy() {
return articleNumber == -1
}
public override func makeDummy(): Threadable {
let dummy = Article()
dummy.setSubject("[Dummy]")
return dummy
}
public override func messageThreadId() {
return articleId
}
public override func messageThreadReferences() {
return getReferences()
}
public func setArticleId(string: String): Unit {
articleId = string
}
public func setArticleNumber(num: Int64): Unit {
articleNumber = num
}
public override func setChild(child: ?Threadable): Unit {
this.kid = if (let Some(x) <- child) {
x as Article
} else {
None
}
flushSubjectCache()
}
public func setDate(str: String): Unit {
date = str
}
public func setFrom(str: String): Unit {
`from` = str
}
public override func setNext(next: ?Threadable): Unit {
this.next = if (let Some(x) <- next) {
x as Article
} else {
None
}
flushSubjectCache()
}
public func setSubject(sub: String): Unit {
subject = sub
}
public override func simplifiedSubject(): String {
if (simplifiedSubjectCache.isEmpty()) {
simplifySubject()
}
return simplifiedSubjectCache
}
/**
* 尝试解析主题行中的一些典型回复标志,并将其删除
*/
private func simplifySubject(): Unit {
var start = 0
let subject = getSubject()
let len = subject.size
var done = false
while (!done) {
done = true
// skip whitespace
// "Re: " breaks this
while (start < len && subject[start] == b' ') {
start++;
}
if (start < len - 2 && (subject[start] == b'r' || subject[start] == b'R') && (subject[start + 1] == b'e' ||
subject[start + 1] == b'E')) {
if (subject[start + 2] == b':') {
start += 3 // Skip "Re:"
done = false
} else if (start < len - 2 && (subject[start + 2] == b'[' || subject[start + 2] == b'(')) {
var i = start + 3
while (i < len && subject[i] >= b'0' && subject[i] <= b'9') {
i++
}
if (i < len - 1 && (subject[i] == b']' || subject[i] == b')') && subject[i + 1] == b':') {
start = i + 2
done = false
}
}
}
if ("(no subject)" == simplifiedSubjectCache) {
simplifiedSubjectCache = ""
}
var end = len
while (end > start && subject[end - 1] < b' ') {
end--
}
if (start == 0 && end == len) {
simplifiedSubjectCache = subject
} else {
simplifiedSubjectCache = subject[start..end]
}
}
}
public override func subjectIsReply() {
return isReply
}
public func toString() {
return articleNumber.toString() + " " + articleId + " " + subject;
}
}