main.go (4479B)
1 package main 2 3 import ( 4 "bufio" 5 "flag" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "os" 10 "regexp" 11 "sort" 12 "strings" 13 "time" 14 15 "git.openbsd.org.ru/vasyahacker/openidec/ii" 16 ) 17 18 func open_db(path string) *ii.DB { 19 db := ii.OpenDB(path) 20 if db == nil { 21 fmt.Printf("Can no open db: %s\n", path) 22 os.Exit(1) 23 } 24 return db 25 } 26 27 func GetFile(path string) string { 28 var file *os.File 29 var err error 30 if path == "-" { 31 file = os.Stdin 32 } else { 33 file, err = os.Open(path) 34 if err != nil { 35 fmt.Printf("Can not open file %s: %s\n", path, err) 36 os.Exit(1) 37 } 38 defer file.Close() 39 } 40 b, err := ioutil.ReadAll(file) 41 if err != nil { 42 fmt.Printf("Can not read file %s: %s\n", path, err) 43 os.Exit(1) 44 } 45 return string(b) 46 } 47 48 var urlRegex = regexp.MustCompile(`(http|ftp|https|gemini)://[^ <>"]+`) 49 50 func gemini(f io.Writer, m *ii.Msg) { 51 fmt.Fprintln(f, "# "+m.Subj) 52 if m.To != "All" && m.To != m.From { 53 fmt.Fprintf(f, "To: %s\n\n", m.To) 54 } 55 d := time.Unix(m.Date, 0).Format("2006-01-02 15:04:05") 56 fmt.Fprintf(f, "by %s on %s\n\n", m.From, d) 57 temp := strings.Split(m.Text, "\n") 58 pre := false 59 xpm := false 60 link := 0 61 var links []string 62 for _, l := range temp { 63 l = strings.Replace(l, "\r", "", -1) 64 if pre { 65 if l == "====" { 66 l = "```" 67 pre = false 68 } 69 } else if xpm { 70 if strings.HasSuffix(l, "};") { 71 xpm = false 72 fmt.Fprintln(f, l) 73 fmt.Fprintln(f, "```") 74 continue 75 } 76 } else { 77 if l == "====" { 78 l = "```" 79 pre = true 80 } else if strings.HasPrefix(l, "/* XPM */") { 81 fmt.Fprintln(f, "```") 82 xpm = true 83 } 84 } 85 if !pre && !xpm { 86 l = string(urlRegex.ReplaceAllFunc([]byte(l), 87 func(line []byte) []byte { 88 link++ 89 s := string(line) 90 links = append(links, fmt.Sprintf("=> %s %s [%d]", 91 s, s, link)) 92 return []byte(fmt.Sprintf("%s [%d]", s, link)) 93 })) 94 } 95 fmt.Fprintln(f, l) 96 } 97 for _, v := range links { 98 fmt.Fprintln(f, v) 99 } 100 } 101 102 func str_esc(l string) string { 103 l = strings.Replace(l, "&", "&", -1) 104 l = strings.Replace(l, "<", "<", -1) 105 l = strings.Replace(l, ">", ">", -1) 106 return l 107 } 108 109 func main() { 110 ii.OpenLog(ioutil.Discard, os.Stdout, os.Stderr) 111 112 db_opt := flag.String("db", "./db", "II database path (directory)") 113 data_opt := flag.String("data", "./data", "Output path (directory)") 114 url_opt := flag.String("url", "localhost", "Url of station") 115 verbose_opt := flag.Bool("v", false, "Verbose") 116 title_opt := flag.String("title", "ii/idec networks", "Title") 117 author_opt := flag.String("author", "anonymous", "Author") 118 flag.Parse() 119 if *verbose_opt { 120 ii.OpenLog(os.Stdout, os.Stdout, os.Stderr) 121 } 122 123 args := flag.Args() 124 if len(args) < 1 { 125 fmt.Printf(`Help: %s [options] command [arguments] 126 Commands: 127 -data <path> gemini - generate gemini data 128 Options: 129 -db=<path> - database path 130 `, os.Args[0]) 131 os.Exit(1) 132 } 133 switch cmd := args[0]; cmd { 134 case "gemini": 135 db := open_db(*db_opt) 136 db.Lock() 137 defer db.Unlock() 138 if err := db.LoadIndex(); err != nil { 139 return 140 } 141 142 scanner := bufio.NewScanner(os.Stdin) 143 var mis []*ii.Msg 144 for scanner.Scan() { 145 mi := db.LookupFast(scanner.Text(), false) 146 if mi != nil { 147 mis = append(mis, db.Get(mi.Id)) 148 } 149 } 150 sort.SliceStable(mis, func(i, j int) bool { 151 return mis[i].Date > mis[j].Date 152 }) 153 data := strings.TrimSuffix(*data_opt, "/") 154 atom, err := os.Create(data + "/atom.xml") 155 if err != nil { 156 return 157 } 158 defer atom.Close() 159 fmt.Fprintf(atom, `<?xml version='1.0' encoding='UTF-8'?> 160 <feed xmlns="http://www.w3.org/2005/Atom"> 161 <id>gemini://%s/</id> 162 <title>%s</title> 163 <updated>%s</updated> 164 <author> 165 <name>%s</name> 166 </author> 167 <link href="gemini://%s/atom.xml" rel="self"/> 168 <link href="gemini://%s/" rel="alternate"/> 169 `, *url_opt, *title_opt, time.Now().Format(time.RFC3339), *author_opt, *url_opt, *url_opt) 170 for _, v := range mis { 171 m := v 172 if m != nil { 173 f, err := os.Create(data + "/" + m.MsgId + ".gmi") 174 if err == nil { 175 gemini(f, m) 176 d := time.Unix(m.Date, 0).Format("2006-01-02") 177 fmt.Println("=> /" + m.MsgId + ".gmi " + d + " - " + m.Subj) 178 } 179 f.Close() 180 fmt.Fprintf(atom, `<entry> 181 <id>gemini://%s/%s.gmi</id> 182 <title>%s</title> 183 <updated>%s</updated> 184 <link href="gemini://%s/%s.gmi" rel="alternate"/> 185 </entry> 186 `, *url_opt, m.MsgId, str_esc(m.Subj), 187 time.Unix(m.Date, 0).Format(time.RFC3339), *url_opt, m.MsgId) 188 } 189 } 190 fmt.Fprintf(atom, `</feed> 191 `) 192 default: 193 fmt.Printf("Wrong cmd: %s\n", cmd) 194 os.Exit(1) 195 } 196 }