github.com/jancarloviray/community@v0.41.1-0.20170124221257-33a66c87cf2f/cmd/wordconvert/wordconvert.go (about) 1 // Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved. 2 // 3 // This software (Documize Community Edition) is licensed under 4 // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html 5 // 6 // You can operate outside the AGPL restrictions by purchasing 7 // Documize Enterprise Edition and obtaining a commercial license 8 // by contacting <sales@documize.com>. 9 // 10 // https://documize.com 11 12 // Package main contains a command line utility to convert multiple word documents using api.documize.com 13 package main 14 15 import ( 16 "archive/zip" 17 "bytes" 18 "crypto/tls" 19 "errors" 20 "flag" 21 "fmt" 22 "io" 23 "io/ioutil" 24 "mime/multipart" 25 "net" 26 "net/http" 27 "os" 28 "path" 29 "strings" 30 ) 31 32 const serverURLfmt = "https://%s/api/1/word" 33 34 var server = flag.String("s", "api.documize.com:443", "the server") 35 var outputDir = flag.String("o", ".", "specify the directory to hold the output") 36 var ignoreBadCert = flag.Bool("k", false, "ignore bad certificate errors") 37 var verbose = flag.Bool("v", false, "verbose progress messages") 38 var stayziped = flag.Bool("z", false, "do not automatically unzip content") 39 var token = flag.String("t", "", "authorization token (if you use your e-mail address here during preview period, we will tell you before changes are made)") 40 var ignoreErrs = flag.Bool("e", false, "report errors on individual files, but continue") 41 var version = flag.Bool("version", false, "display the version of this code") 42 43 // does the file have a valid extension 44 func validXtn(fn string) bool { 45 lcfn := strings.ToLower(fn) 46 for _, xtn := range []string{".doc", ".docx", ".pdf"} { 47 if strings.HasSuffix(lcfn, xtn) { 48 return true 49 } 50 } 51 return false 52 } 53 54 // errCanContinue is the mechanism to print errors yet continue, if that command line option is chosen 55 func errCanContinue(can bool, err error) bool { 56 if err == nil { 57 return false 58 } 59 fmt.Fprintln(os.Stderr, err) 60 if *ignoreErrs && can { 61 return true 62 } 63 os.Exit(0) 64 return true // never reached 65 } 66 67 func main() { 68 69 flag.Parse() 70 71 if *version { 72 fmt.Println("Version: 0.1 preview") 73 } 74 75 if *outputDir != "." { 76 if err := os.Mkdir(*outputDir, 0777); err != nil && !os.IsExist(err) { 77 errCanContinue(false, err) 78 } 79 } 80 81 host, _, err := net.SplitHostPort(*server) 82 errCanContinue(false, err) 83 84 tlc := &tls.Config{ 85 InsecureSkipVerify: *ignoreBadCert, 86 ServerName: host, 87 } 88 89 transport := &http.Transport{TLSClientConfig: tlc} 90 hclient := &http.Client{Transport: transport} 91 92 processFiles(hclient) 93 94 os.Exit(1) 95 } 96 97 func processFiles(hclient *http.Client) { 98 99 for _, fileName := range flag.Args() { 100 101 if validXtn(fileName) { 102 103 if *verbose { 104 fmt.Println("processing", fileName) 105 } 106 107 content, err := ioutil.ReadFile(fileName) 108 if errCanContinue(true, err) { 109 continue 110 } 111 112 bodyBuf := &bytes.Buffer{} 113 bodyWriter := multipart.NewWriter(bodyBuf) 114 115 _, fn := path.Split(fileName) 116 fileWriter, err := bodyWriter.CreateFormFile("wordfile", fn) // name as expected by the API 117 if errCanContinue(true, err) { 118 continue 119 } 120 121 _, err = io.Copy(fileWriter, bytes.NewReader(content)) 122 if errCanContinue(true, err) { 123 continue 124 } 125 126 contentType := bodyWriter.FormDataContentType() 127 err = bodyWriter.Close() 128 if errCanContinue(true, err) { 129 continue 130 } 131 132 target := fmt.Sprintf(serverURLfmt, *server) 133 if *token != "" { 134 target += "?token=" + *token // NOTE: after the preview phase, token will not be optional 135 } 136 137 req, err := http.NewRequest("POST", 138 target, 139 bodyBuf) 140 if errCanContinue(true, err) { 141 continue 142 } 143 144 req.Header.Set("Content-Type", contentType) 145 resp, err := hclient.Do(req) 146 if errCanContinue(true, err) { 147 continue 148 } 149 150 zipdata, err := ioutil.ReadAll(resp.Body) 151 if errCanContinue(true, err) { 152 continue 153 } 154 155 resp.Body.Close() // ignore error 156 157 if resp.StatusCode != http.StatusOK { 158 if errCanContinue(true, errors.New("server returned status: "+resp.Status)) { 159 continue 160 } 161 } 162 163 targetDir := *outputDir + "/" + fn + ".content" 164 if *stayziped { 165 if err := ioutil.WriteFile(targetDir+".zip", zipdata, 0666); err != nil { 166 if errCanContinue(true, err) { 167 continue 168 } 169 } 170 } else { 171 if errCanContinue(true, unzipFiles(zipdata, targetDir)) { 172 continue 173 } 174 } 175 176 } else { 177 178 if *verbose { 179 fmt.Println("ignored", fileName) 180 } 181 182 } 183 } 184 } 185 186 // simple unzip 187 func unzipFiles(zipdata []byte, targetDir string) error { 188 189 rdr, err := zip.NewReader(bytes.NewReader(zipdata), int64(len(zipdata))) 190 if err != nil { 191 return err 192 } 193 194 if err := os.Mkdir(targetDir, 0777); err != nil && !os.IsExist(err) { // make sure the target directory exists 195 return err 196 } 197 198 fileLoop: 199 for _, zf := range rdr.File { 200 frc, err := zf.Open() 201 if errCanContinue(true, err) { 202 continue 203 } 204 205 filedata, err := ioutil.ReadAll(frc) 206 if errCanContinue(true, err) { 207 continue 208 } 209 210 subTarget := targetDir + "/" + zf.Name 211 212 subDir := path.Dir(subTarget) 213 214 if subDir != targetDir { 215 rump := strings.TrimPrefix(subDir, targetDir) 216 tree := strings.Split(rump, "/") 217 built := "" 218 for _, thisPart := range tree[1:] { // make sure we have a directory at each level of the tree 219 built += "/" + thisPart 220 if err := os.Mkdir(targetDir+built, 0777); err != nil && !os.IsExist(err) { 221 if errCanContinue(true, err) { 222 continue fileLoop 223 } 224 } 225 } 226 } 227 228 if err := ioutil.WriteFile(subTarget, filedata, 0666); err != nil { 229 if errCanContinue(true, err) { 230 continue 231 } 232 } 233 234 if *verbose { 235 fmt.Println("wrote", subTarget) 236 } 237 frc.Close() 238 } 239 240 return nil 241 }