// Copyright 2021, Henrik Sölver henrik.solver@gmail.com // SPDX-License-Identifier: BSD-3-Clause package main import ( "context" "flag" "fmt" "ippserver/packages/ipp" "ippserver/packages/mdnsserver" "net/http" "net/url" "sync" log "github.com/sirupsen/logrus" ) var ( loglevel string location string port uint printerURI string printerName string ippurl, httpurl *url.URL ) func init() { flag.StringVar(&loglevel, "loglevel", "info", "The wanted loglevel error/info/debug") flag.StringVar(&location, "location", "somewhere", "locaton of the printer as shown in mDNS") flag.UintVar(&port, "port", 1234, "tcp port") flag.StringVar(&printerURI, "printer", "", "URL to the real printer, typical ipp://printername.local:631/ipp/print") flag.StringVar(&printerName, "name", "ChroBroPrint", "Name of the printer advertised with mDNS") } func main() { var err error flag.Parse() customFormatter := new(log.TextFormatter) customFormatter.TimestampFormat = "2006-01-02 15:04:05" log.SetFormatter(customFormatter) customFormatter.FullTimestamp = true log.SetLevel(log.InfoLevel) ippurl, err = url.Parse(printerURI) if err != nil { fmt.Printf("Failed to parse printer URL %v", err.Error()) return } httpurl, _ = url.Parse(printerURI) httpurl.Scheme = "http" ctx, cancel := context.WithCancel(context.Background()) defer cancel() go mdnsserver.Run(ctx, location, uint16(port), printerName) http.HandleFunc("/ipp/print", handle) log.Infof("http server starting on :%v", port) err = http.ListenAndServe(fmt.Sprintf(":%v", port), nil) if err != nil { log.Fatal("ListenAndServe: " + err.Error()) } } var mut sync.Mutex var requestID uint32 func handle(w http.ResponseWriter, r *http.Request) { mut.Lock() requestID++ mut.Unlock() if r.Method != http.MethodPost { http.Error(w, "Unsupported method", http.StatusMethodNotAllowed) } request := ipp.NewRequest(0, 0) request.UnMarshal(r.Body) log.Infof("Upstream Request: id: %v op: %v", request.RequestID(), request.Operation()) var response *ipp.Response var err error switch request.Operation() { case ipp.GetPrinterAttributes: response = handleGetPrinterAttributes(request) case ipp.PrintJob: response, err = handlePrintJob(request, r.Body, requestID) case ipp.GetJobs: response, err = handleGetJobs(request, requestID) case ipp.ValidateJob: response = handleValidateJob(request) case ipp.GetJobAttributes: response, err = handleGetJobAttributes(request, requestID) default: response = ipp.NewResponse(ipp.ClientErrorBadRequest, request.RequestID()) } if err != nil { log.Errorf("Failed to handle request: %v", err.Error()) response = ipp.NewResponse(ipp.ServerErrorServiceUnavailable, request.RequestID()) } log.Infof("Upstream Response: %v", response.Header()) data := response.Marshal() w.Write(data) }