Skip to content

Commit

Permalink
Merge pull request #2 from ocelotsloth/goqrzCLI
Browse files Browse the repository at this point in the history
CLI: Add initial CLI Support
  • Loading branch information
ocelotsloth authored Oct 7, 2018
2 parents afc6cd5 + 18bcbce commit 6b46051
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 21 deletions.
42 changes: 27 additions & 15 deletions API.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,51 @@ import (
"net/http"
)

// GetSession takes user/pass and returns a valid session
func GetSession(user string, pass string, agent string) (Session, error) {
// GetSessionKey takes user/pass and returns a valid session
func GetSessionKey(user string, pass string, agent string) (string, error) {

xmlBytes, err := getXML(
fmt.Sprintf("http://xmldata.qrz.com/xml/1.33/?username=%s;password=%s;agent=%s",
user, pass, agent))
if err != nil {
return Session{}, err
return "", err
}

var database QRZDatabase
xml.Unmarshal(xmlBytes, &database)

newSession := database.Session
newSession.user = user
newSession.pass = pass

if newSession.Error != "" {
return newSession, errors.New(newSession.Error)
return "", errors.New(newSession.Error)
}

return newSession.Key, nil
}

// GetSession creates a session object from just a key
func GetSession(key string, agent string) (Session, error) {

xmlBytes, err := getXML(fmt.Sprintf("http://xmldata.qrz.com/xml/1.33/?s=%s;agent=%s", key, agent))
if err != nil {
return Session{}, err
}

return newSession, nil
var database QRZDatabase
xml.Unmarshal(xmlBytes, &database)

if database.Session.Error != "" {
return database.Session, errors.New(database.Session.Error)
}

return database.Session, nil
}

// GetCallsign takes a callsign and returns the QRZ information on that
// callsign.
func (CurrentSession *Session) GetCallsign(callsign string) (Callsign, error) {
func GetCallsign(key string, callsign string, agent string) (Callsign, error) {

xmlBytes, err := getXML(
fmt.Sprintf("http://xmldata.qrz.com/xml/1.33/?s=%s;callsign=%s",
CurrentSession.Key, callsign))
xmlBytes, err := getXML(fmt.Sprintf("http://xmldata.qrz.com/xml/1.33/?s=%s;callsign=%s;agent=%s", key, callsign, agent))
if err != nil {
return Callsign{}, err
}
Expand All @@ -54,15 +68,13 @@ func (CurrentSession *Session) GetCallsign(callsign string) (Callsign, error) {

// GetDXCC takes a dxcc id and returns the QRZ information on that
// region.
func (CurrentSession *Session) GetDXCC(dxcc string) (DXCC, error) {
func GetDXCC(key string, dxcc string, agent string) (DXCC, error) {

if dxcc == "all" {
return DXCC{}, errors.New("get all DXCC not implemented in this function")
}

xmlBytes, err := getXML(
fmt.Sprintf("http://xmldata.qrz.com/xml/1.33/?s=%s;dxcc=%s",
CurrentSession.Key, dxcc))
xmlBytes, err := getXML(fmt.Sprintf("http://xmldata.qrz.com/xml/1.33/?s=%s;dxcc=%s;agent=%s", key, dxcc, agent))
if err != nil {
return DXCC{}, err
}
Expand Down
2 changes: 1 addition & 1 deletion Callsign.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type Callsign struct {
Lat string `xml:"lat"` // lattitude of address (signed decimal) S < 0 > N
Lon string `xml:"lon"` // longitude of address (signed decimal) W < 0 > E
GridLocator string `xml:"grid"` // grid locator
Country string `xml:"county"` // county name (USA)
County string `xml:"county"` // county name (USA)
FIPSIdentifier string `xml:"fips"` // FIPS county identifier (USA)
DXCCCountryName string `xml:"land"` // DXCC country name of the callsign
EffectiveDate string `xml:"efdate"` // license effective date (USA)
Expand Down
44 changes: 42 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,46 @@ qrzSession.GetCallsign("KN4IJZ")

Documentation for the returned datatypes can be found via godoc or within the source code.

## Future Plan
## GoQRZ Command Line Interface

I plan to implement a simple cli interface which will allow for simple scripting of QRZ lookups from the command line. Look out for updates to this library.
Included in this library is a CLI tool which can be used to query QRZ for information on callsigns and DXCC entities.

### Install GoQRZ CLI

There are two ways to install and use the CLI; compiling from source and downloading precompiled binaries.

#### From Source

The CLI can be compiled from source by running the following:

```shell
go get github.com/ocelotsloth/goqrz/goqrz
```

Provided your `GOPATH` is configured correctly you should now be able to run `goqrz` from the command line.

#### Precompiled Binaries

Look at the [releases](https://github.com/ocelotsloth/goqrz/releases) on this GitHub page for downloadable binaries. This utility can be cross-compiled to most any popular archetecture in use. Open an issue if you need an additional archetecture added to the list of precompiled binaries.

### CLI Usage

Before pulling data from the XML API, it is important to log in. **Ensure 2 factor authentication is enabled on your account before using this utility!** QRZ.com does not have encryption enabled on their XML endpoint, so it is imparative that this password be unique to QRZ.com. Be sure to change it frequently as well. This library does its best to remain secure by not storing your username or password between calls. Instead it provides two methods to store the session key.

#### Get Session Key

First, run `goqrz login -u <username> -p <password>` to receive your session key. The key is printed to stdout, so you can store it as an environment variable (store it to `GOQRZ_KEY`) or by passing the key to each subsequent call via the `--key` flag.

#### Query Data

There are two queries currently implemented: callsigns and dxcc zones.

##### Callsigns

To retrieve callsign data, use the command `goqrz callsign [--key=<sessionKey>] Callsign [AdditionalCallsigns...]`. To be efficient, please consider batching your callsign requests to one single call to the `goqrz` CLI. This will reduce the overhead with setting up the connection to QRZ.com.

Data is returned as JSON. I personally recommend using `jq` to further deal with the data.

##### DXCC Zones

DXCC data can be retrieved in the exact same fasion as Callsigns, except with the following syntax: `goqrz dxcc [--key=<sessionKey>] DXCCID [AdditionalDXCCIDs...]`
3 changes: 1 addition & 2 deletions Session.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ type Session struct {
GMTime string `xml:"GMTime"` // Time stamp for this message
Message string `xml:"Message"` // An informational message for the user
Error string `xml:"Error"` // XML system error message
user string // Username (Generally Callsign), private variable
pass string // Password, private variable
Remark string `xml:"Remark"` // Remarks are sometimes helpful diagnostic messages from QRZ.com
agent string // Agent ID, private variable
}
113 changes: 112 additions & 1 deletion goqrz/main.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,116 @@
package main

import (
"encoding/json"
"errors"
"fmt"
"log"
"os"

"github.com/ocelotsloth/goqrz"
"github.com/urfave/cli"
)

func main() {
return
app := cli.NewApp()
app.Name = "goqrz"
app.Usage = "Search QRZ.com database via CLI"
app.Version = "0.1.0"

app.Commands = []cli.Command{
{
Name: "login",
Aliases: []string{"l"},
Usage: "login to generate session token (saves to environment)",
Flags: []cli.Flag{
cli.StringFlag{
Name: "user, u",
Usage: "QRZ.com Username",
},
cli.StringFlag{
Name: "pass, p",
Usage: "QRZ.com Password",
},
},
Action: func(c *cli.Context) error {
sessionKey, err := goqrz.GetSessionKey(c.String("user"), c.String("pass"), "goqrz")
if err != nil {
return err
}
fmt.Println(sessionKey)
return nil
},
},
{
Name: "callsign",
Aliases: []string{"c"},
Usage: "callsign [--key=session_key] Call1 [Call2...]",
Flags: []cli.Flag{
cli.StringFlag{
Name: "key, k",
Usage: "Session key from login command (or use GOQRZ_KEY environment variable)",
},
},
Action: func(c *cli.Context) error {
key := c.String("key")
if key == "" {
key = os.Getenv("GOQRZ_KEY")
if key == "" {
return errors.New("no session key specified")
}
}
for _, arg := range c.Args() {
callsign, err := goqrz.GetCallsign(key, arg, "goqrz-cli")
if err != nil {
return err
}
callJSON, err := json.Marshal(callsign)
if err != nil {
return err
}
fmt.Println(string(callJSON))
}

return nil
},
},
{
Name: "dxcc",
Aliases: []string{"d"},
Usage: "dxcc [--key=session_key] dxccID1 [dxccID2...]",
Flags: []cli.Flag{
cli.StringFlag{
Name: "key, k",
Usage: "Session key from login command (or use GOQRZ_KEY environment variable)",
},
},
Action: func(c *cli.Context) error {
key := c.String("key")
if key == "" {
key = os.Getenv("GOQRZ_KEY")
if key == "" {
return errors.New("no session key specified")
}
}
for _, arg := range c.Args() {
dxcc, err := goqrz.GetDXCC(key, arg, "goqrz-cli")
if err != nil {
return err
}
dxccJSON, err := json.Marshal(dxcc)
if err != nil {
return err
}
fmt.Println(string(dxccJSON))
}

return nil
},
},
}

err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}

0 comments on commit 6b46051

Please sign in to comment.