diff --git a/application/controllers/api.php b/application/controllers/api.php
new file mode 100644
index 00000000..397f17bc
--- /dev/null
+++ b/application/controllers/api.php
@@ -0,0 +1,141 @@
+load->model('logbook_model');
+ $data['data'] = array();
+
+ // load the view
+ //$this->load->view('layout/header');
+ $this->load->view('api/index', $data);
+ //$this->load->view('layout/footer');
+ }
+
+ // FUNCTION: search()
+ // Handle search requests
+ /*
+ Okay, so here's how it works in a nutshell...
+
+ *******************************************************************
+ Because this is effectively just a filter between the query string
+ and a MySQL statement, if done wrong we're just asking for pain.
+
+ DO NOT alter any of the filtering statements without fully
+ understanding what you're doing. CodeIgniter provides some
+ protection against unwanted characters in the query string, but
+ this should in no way be relied upon for safety.
+ *******************************************************************
+
+ Example query:-
+ .../search/query[Call~M0*(and)(Locator~I*(or)Locator~J*)]/limit[10]/fields[distinct(Call),Locator]/order[Call(asc)]
+
+ There's four parts to this query, separated with forward slashes. It's effectively a heavily-sanitised
+ MySQL query, hence the hideous search and replace code blocks below.
+
+ FIELDS
+ ------
+ Straightforward - input is sanitised and passed on - in the example, this ends up as "DISTINCT (Call),Locator",
+ which is then the first argument to 'SELECT'
+
+ QUERY
+ -----
+ This forms the 'WHERE' clause.
+
+ * '(and)' and '(or)' are expanded out to ' AND ' and ' OR '
+ * Parentheses are preserved
+ * '~' is expanded out to ' LIKE '
+ * '*' is translated to '%'
+ * Values are encapsulated in quote marks
+
+ So in the example, this translates to "WHERE Call LIKE 'M0%' AND (Locator LIKE 'I%' OR Locator LIKE 'J%')"
+
+ ORDER
+ -----
+ Sanitised, so our example ends up as "ORDER BY Call ASC".
+
+ LIMIT
+ -----
+ Straightforward - what's between the square brackets is passed as an argument to 'LIMIT'
+
+ Finally, once this has been done, each field name is translated to the MySQL column name.
+ */
+
+ function search()
+ {
+ // Load the API and Logbook models
+ $this->load->model('api_model');
+ $this->load->model('logbook_model');
+
+ // Retrieve the arguments from the query string
+ $arguments = $this->_retrieve();
+
+ // Call the parser within the API model to build the query
+ $query = $this->api_model->parse($arguments);
+
+ // Execute the query, and retrieve the results
+ $s = $this->logbook_model->api_search_query($query);
+ $results = $s['results'];
+
+ // Cycle through the results, and translate between MySQL column names
+ // and more friendly, descriptive names
+ $a = 0;
+ if($results->num_rows != 0)
+ {
+ foreach ($results->result() as $row) {
+ $record = (array)$row;
+ $r[$a]['rid'] = $a;
+ while (list($key, $val) = each($record)) {
+ $r[$a][$this->api_model->name($key)] = $val;
+ }
+ $a++;
+ }
+ // Add the result record to the main results array
+ $data['data']['search_Result']['results'] = $r;
+ }
+ else
+ {
+ // We've got no results, so make this empty for completeness
+ $data['data']['search_Result']['results'] = "";
+ }
+
+ // Add some debugging information to the XML output
+ $data['data']['queryInfo']['call'] = "search";
+ $data['data']['queryInfo']['dbQuery'] = $s['query'];
+ $data['data']['queryInfo']['numResults'] = $a;
+ $data['data']['queryInfo']['executionTime'] = $s['time'];
+
+ // Load the XML output view
+ $this->load->view('api/index', $data);
+ }
+
+ // FUNCTION: _retrieve()
+ // Pull the search query arguments from the query string
+ private function _retrieve()
+ {
+ // This whole function could probably have been done in one line... if this was Perl.
+ $arguments = array();
+
+ // Retrieve each arguments
+ $query = preg_grep("/^query\[(.*)\]$/", $this->uri->segments);
+ $limit = preg_grep("/^limit\[(.*)\]$/", $this->uri->segments);
+ $order = preg_grep("/^order\[(.*)\]$/", $this->uri->segments);
+ $fields = preg_grep("/^fields\[(.*)\]$/", $this->uri->segments);
+
+ // Strip each argument
+ $arguments['query'] = substr(array_pop($query), 6);
+ $arguments['query'] = substr($arguments['query'], 0, strlen($arguments['query']) - 1);
+ $arguments['limit'] = substr(array_pop($limit), 6);
+ $arguments['limit'] = substr($arguments['limit'], 0, strlen($arguments['limit']) - 1);
+ $arguments['order'] = substr(array_pop($order), 6);
+ $arguments['order'] = substr($arguments['order'], 0, strlen($arguments['order']) - 1);
+ $arguments['fields'] = substr(array_pop($fields), 7);
+ $arguments['fields'] = substr($arguments['fields'], 0, strlen($arguments['fields']) - 1);
+
+ // Return the arguments
+ return $arguments;
+ }
+}
diff --git a/application/controllers/auth.php b/application/controllers/auth.php
new file mode 100644
index 00000000..e6b04486
--- /dev/null
+++ b/application/controllers/auth.php
@@ -0,0 +1,95 @@
+load->model('auth_model');
+
+ echo "
";
+ echo "Querying for user...\n";
+ $u = $this->auth_model->get("m0vkga");
+ print_r($u);
+ echo "Test hashing\n";
+ echo $this->auth_model->test();
+
+ }
+ /*
+ $this->load->model('note');
+ $data['notes'] = $this->note->list_all();
+
+ $this->load->view('layout/header');
+ $this->load->view('notes/main', $data);
+ $this->load->view('layout/footer');
+ }
+
+ function add() {
+
+ $this->load->model('note');
+
+ $this->load->library('form_validation');
+
+ $this->form_validation->set_rules('title', 'Note Title', 'required');
+ $this->form_validation->set_rules('content', 'Content', 'required');
+
+
+ if ($this->form_validation->run() == FALSE)
+ {
+ $this->load->view('layout/header');
+ $this->load->view('notes/add');
+ $this->load->view('layout/footer');
+ }
+ else
+ {
+ $this->note->add();
+
+ redirect('notes');
+ }
+ }
+
+ function view($id) {
+ $this->load->model('note');
+
+ $data['note'] = $this->note->view($id);
+
+ // Display
+ $this->load->view('layout/header');
+ $this->load->view('notes/view',$data);
+ $this->load->view('layout/footer');
+ }
+
+ function edit($id) {
+ $this->load->model('note');
+ $data['id'] = $id;
+
+ $data['note'] = $this->note->view($id);
+
+ $this->load->library('form_validation');
+
+ $this->form_validation->set_rules('title', 'Note Title', 'required');
+ $this->form_validation->set_rules('content', 'Content', 'required');
+
+
+ if ($this->form_validation->run() == FALSE)
+ {
+ $this->load->view('layout/header');
+ $this->load->view('notes/edit', $data);
+ $this->load->view('layout/footer');
+ }
+ else
+ {
+ $this->note->edit();
+
+ redirect('notes');
+ }
+ }
+
+ function delete($id) {
+ $this->load->model('note');
+ $this->note->delete($id);
+
+ redirect('notes');
+ }
+*/
+}
diff --git a/application/models/api_model.php b/application/models/api_model.php
new file mode 100644
index 00000000..54cd4581
--- /dev/null
+++ b/application/models/api_model.php
@@ -0,0 +1,319 @@
+_columnName[$col])
+ {
+ return $this->_columnName[$col]['Name'];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ // FUNCTION: string description(string $column)
+ // Returns the description for a MySQL column name
+ function description($col)
+ {
+ if($this->_columnName[$col])
+ {
+ if($this->_columnName[$col]['Description'] != "")
+ {
+ return $this->_columnName[$col]['Description'];
+ }
+ else
+ {
+ return "No description available";
+ }
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ // FUNCTION: string name(string $name)
+ // Converts a friendly name to a MySQL column name
+ function column($name)
+ {
+ while ($column = current($this->_columnName))
+ {
+ if($this->_columnName[key($this->_columnName)]['Name'] == $name)
+ {
+ return key($this->_columnName);
+ }
+ next($this->_columnName);
+ }
+
+ return 0;
+ }
+
+ // FUNCTION: string parse(array $arguments)
+ // Converts an array of arguments into a MySQL query string
+ // See documentation for search() under the API controller for more details
+ function parse($arguments)
+ {
+ // Initialise our string
+ $q = "SELECT ";
+
+ // Cycle through the fields, converting friendly names to MySQL column names
+ if($arguments['fields'] != "") {
+ $field = "";
+ $fields = explode(",", $arguments['fields']);
+ foreach ($fields as $f) {
+ if($field != "") {
+ $field .= ",";
+ }
+ // Add field to the query, with '++' placeholders for later translation
+ $field .= "++$f++";
+ }
+ // Handle any DISTINCT arguments
+ $field = str_replace("++distinct(", "DISTINCT(++", $field);
+ $field = str_replace(")++", "++)", $field);
+ // Add the MySQL column name to the query
+ $q .= $field." ";
+ } else {
+ // If no fields are specified, display all fields
+ $q .= "* ";
+ }
+
+ // Append the table we're pulling data from
+ $q .= "FROM ".$this->config->item('table_name');
+
+ // Parse the 'query' string, which is converted into a standard MySQL 'WHERE'
+ // clause.
+ // $s and $r can be refactored into single array definitions, but during
+ // development it's easier to list them in this way for quick reference.
+ if($arguments['query'] != "")
+ {
+ $q .= " WHERE ";
+ $s = null;
+ $r = null;
+ // (and), becomes ' AND '
+ $s[0] = '/(and)/';
+ // (or), becomes ' OR '
+ $s[1] = '/(or)/';
+ // <, >, [ and ] all translated from their urlencoded forms
+ $s[2] = '/%3C/';
+ $s[3] = '/%3E/';
+ $s[4] = '/%5B/';
+ $s[5] = '/%5D/';
+ // FieldName=, which becomes '++FieldName++ = '
+ $s[6] = '/([a-zA-Z0-9\-\_\*\(\)\=\~]+)=/';
+ // =Value, which becomes '= 'Value''
+ $s[7] = '/=([a-zA-Z0-9\-\_\*\(\)\=\~]+)/';
+ // now(), which becomes 'UNIX_TIMESTAMP(NOW())'
+ $s[8] = '/now()/';
+ // (, and ), which are translated to their non-HTML entity forms,
+ // and with added padding
+ $s[9] = '/(/';
+ $s[10] = '/)/';
+ // FieldName~, becomes '++FieldName++ LIKE~'
+ $s[11] = '/([a-zA-Z0-9\-\_\*\(\)\=\~]+)~/';
+ // ~Value, becomes ' 'Value''
+ $s[12] = '/~([a-zA-Z0-9\-\_\*\(\)\=\~]+)/';
+ // *, which becomes '%'
+ $s[13] = '/\*/';
+
+ $r[0] = ' AND ';
+ $r[1] = ' OR ';
+ $r[2] = ' < ';
+ $r[3] = ' > ';
+ $r[4] = '[';
+ $r[5] = ']';
+ $r[6] = '++$1++ =';
+ $r[7] = '= \'$1\'';
+ $r[8] = 'UNIX_TIMESTAMP(NOW())';
+ $r[9] = '( ';
+ $r[10] = ' )';
+ $r[11] = '++$1++ LIKE~';
+ $r[12] = ' \'$1\'';
+ $r[13] = '%';
+
+ // Bulk replace everything
+ $q .= preg_replace($s, $r, $arguments['query']);
+ }
+
+ // Parse any order arguments
+ if($arguments['order'] != "")
+ {
+ $q .= " ORDER BY ";
+
+ $s = null;
+ $r = null;
+ $s[0] = '/(/';
+ $s[1] = '/)/';
+ $s[2] = '/([a-zA-Z0-9\-\_]+)([,\(]{1}|$)/';
+ $s[3] = '/\(asc\)/';
+ $s[4] = '/\(desc\)/';
+ $s[5] = '/,$/';
+
+ $r[0] = '(';
+ $r[1] = ')';
+ $r[2] = '++$1++ $2';
+ $r[3] = ' ASC ';
+ $r[4] = ' DESC ';
+ $r[5] = '';
+
+ $q .= preg_replace($s, $r, $arguments['order']);
+
+ }
+
+ // Do search/replace on field names, to convert from friendly names
+ // to MySQL column names
+ while (list($key, $val) = each($this->_columnName)) {
+ $q = str_replace("++".$val['Name']."++", $key, $q);
+ }
+
+ // Parse any limit arguments
+ if($arguments['limit'] != "")
+ {
+ // Add the limit arguments, removing any characters other than numbers and commas
+ $q .= " LIMIT " . preg_replace(array("/[^0-9\,]/","/,$/"), "", $arguments['limit']);
+ }
+ else
+ {
+ // If no limit argument is given, default to the first 20 results
+ $q .= " LIMIT 0,20";
+ }
+
+ return $q;
+ }
+
+ // ARRAY: $_columnName
+ // An array matching MySQL column names to friendly names, descriptions and types
+ private $_columnName = array(
+ 'COL_PRIMARY_KEY' => array('Name' => 'ID', 'Description' => 'Unique QSO ID', 'Type' => 'I'),
+ 'COL_ADDRESS' => array('Name' => 'Address', 'Description' => 'Operator\'s address', 'Type' => 'S'),
+ 'COL_AGE' => array('Name' => 'Age', 'Description' => 'Operator\'s age', 'Type' => 'I'),
+ 'COL_A_INDEX' => array('Name' => 'AIndex', 'Description' => 'Solar A Index', 'Type' => 'I'),
+ 'COL_ANT_AZ' => array('Name' => 'AntennaAzimuth', 'Description' => 'Antenna azimuth', 'Type' => 'I'),
+ 'COL_ANT_EL' => array('Name' => 'AntennaElevation', 'Description' => 'Antenna elevation', 'Type' => 'I'),
+ 'COL_ANT_PATH' => array('Name' => 'AntennaPath', 'Description' => 'Antenna path', 'Type' => ''),
+ 'COL_ARRL_SECT' => array('Name' => 'ARRLSection', 'Description' => 'ARRL Section', 'Type' => ''),
+ 'COL_BAND' => array('Name' => 'Band', 'Description' => 'Band', 'Type' => ''),
+ 'COL_BAND_RX' => array('Name' => 'BandRX', 'Description' => '', 'Type' => ''),
+ 'COL_BIOGRAPHY' => array('Name' => 'Biography', 'Description' => '', 'Type' => ''),
+ 'COL_CALL' => array('Name' => 'Call', 'Description' => '', 'Type' => ''),
+ 'COL_CHECK' => array('Name' => 'UNK_CHECK', 'Description' => '', 'Type' => ''),
+ 'COL_CLASS' => array('Name' => 'Class', 'Description' => '', 'Type' => ''),
+ 'COL_CNTY' => array('Name' => 'County', 'Description' => '', 'Type' => ''),
+ 'COL_COMMENT' => array('Name' => 'Comment', 'Description' => '', 'Type' => ''),
+ 'COL_CONT' => array('Name' => 'Continent', 'Description' => '', 'Type' => ''),
+ 'COL_CONTACTED_OP' => array('Name' => 'UNK_CONTACTED_OP', 'Description' => '', 'Type' => ''),
+ 'COL_CONTEST_ID' => array('Name' => 'ContestID', 'Description' => '', 'Type' => ''),
+ 'COL_COUNTRY' => array('Name' => 'Country', 'Description' => '', 'Type' => ''),
+ 'COL_CQZ' => array('Name' => 'CQZone', 'Description' => '', 'Type' => ''),
+ 'COL_DISTANCE' => array('Name' => 'Distance', 'Description' => '', 'Type' => ''),
+ 'COL_DXCC' => array('Name' => 'DXCC', 'Description' => '', 'Type' => ''),
+ 'COL_EMAIL' => array('Name' => 'EMail', 'Description' => '', 'Type' => ''),
+ 'COL_EQ_CALL' => array('Name' => 'UNK_EQ_CALL', 'Description' => '', 'Type' => ''),
+ 'COL_EQSL_QSLRDATE' => array('Name' => 'EQSLRecievedDate', 'Description' => '', 'Type' => ''),
+ 'COL_EQSL_QSLSDATE' => array('Name' => 'EQSLSentDate', 'Description' => '', 'Type' => ''),
+ 'COL_EQSL_QSL_RCVD' => array('Name' => 'EQSLRecieved', 'Description' => '', 'Type' => ''),
+ 'COL_EQSL_QSL_SENT' => array('Name' => 'EQSLSent', 'Description' => '', 'Type' => ''),
+ 'COL_EQSL_STATUS' => array('Name' => 'EQSLStatus', 'Description' => '', 'Type' => ''),
+ 'COL_FORCE_INIT' => array('Name' => 'UNK_FORCE_INIT', 'Description' => '', 'Type' => ''),
+ 'COL_FREQ' => array('Name' => 'Frequency', 'Description' => '', 'Type' => ''),
+ 'COL_FREQ_RX' => array('Name' => 'FrequencyRX', 'Description' => '', 'Type' => ''),
+ 'COL_GRIDSQUARE' => array('Name' => 'Locator', 'Description' => '', 'Type' => ''),
+ 'COL_HEADING' => array('Name' => 'Heading', 'Description' => '', 'Type' => ''),
+ 'COL_IOTA' => array('Name' => 'IOTA', 'Description' => '', 'Type' => ''),
+ 'COL_ITUZ' => array('Name' => 'ITUZone', 'Description' => '', 'Type' => ''),
+ 'COL_K_INDEX' => array('Name' => 'KIndex', 'Description' => '', 'Type' => ''),
+ 'COL_LAT' => array('Name' => 'Latitude', 'Description' => '', 'Type' => ''),
+ 'COL_LON' => array('Name' => 'Longitude', 'Description' => '', 'Type' => ''),
+ 'COL_LOTW_QSLRDATE' => array('Name' => 'LOTWRecievedDate', 'Description' => '', 'Type' => ''),
+ 'COL_LOTW_QSLSDATE' => array('Name' => 'LOTWSentDate', 'Description' => '', 'Type' => ''),
+ 'COL_LOTW_QSL_RCVD' => array('Name' => 'LOTWRecieved', 'Description' => '', 'Type' => ''),
+ 'COL_LOTW_QSL_SENT' => array('Name' => 'LOTWSent', 'Description' => '', 'Type' => ''),
+ 'COL_LOTW_STATUS' => array('Name' => 'LOTWStatus', 'Description' => '', 'Type' => ''),
+ 'COL_MAX_BURSTS' => array('Name' => 'MaxBursts', 'Description' => '', 'Type' => ''),
+ 'COL_MODE' => array('Name' => 'Mode', 'Description' => '', 'Type' => ''),
+ 'COL_MS_SHOWER' => array('Name' => 'MSShower', 'Description' => '', 'Type' => ''),
+ 'COL_MY_CITY' => array('Name' => 'MyCity', 'Description' => '', 'Type' => ''),
+ 'COL_MY_CNTY' => array('Name' => 'MyCounty', 'Description' => '', 'Type' => ''),
+ 'COL_MY_COUNTRY' => array('Name' => 'MyCountry', 'Description' => '', 'Type' => ''),
+ 'COL_MY_CQ_ZONE' => array('Name' => 'MyCQZone', 'Description' => '', 'Type' => ''),
+ 'COL_MY_GRIDSQUARE' => array('Name' => 'MyLocator', 'Description' => '', 'Type' => ''),
+ 'COL_MY_IOTA' => array('Name' => 'MyIOTA', 'Description' => '', 'Type' => ''),
+ 'COL_MY_ITU_ZONE' => array('Name' => 'MyITUZone', 'Description' => '', 'Type' => ''),
+ 'COL_MY_LAT' => array('Name' => 'MyLatitude', 'Description' => '', 'Type' => ''),
+ 'COL_MY_LON' => array('Name' => 'MyLongitude', 'Description' => '', 'Type' => ''),
+ 'COL_MY_NAME' => array('Name' => 'MyName', 'Description' => '', 'Type' => ''),
+ 'COL_MY_POSTAL_CODE' => array('Name' => 'MyPostalCode', 'Description' => '', 'Type' => ''),
+ 'COL_MY_RIG' => array('Name' => 'MyRig', 'Description' => '', 'Type' => ''),
+ 'COL_MY_SIG' => array('Name' => 'MySig', 'Description' => '', 'Type' => ''),
+ 'COL_MY_SIG_INFO' => array('Name' => 'MySigInfo', 'Description' => '', 'Type' => ''),
+ 'COL_MY_STATE' => array('Name' => 'MyState', 'Description' => '', 'Type' => ''),
+ 'COL_MY_STREET' => array('Name' => 'MyStreet', 'Description' => '', 'Type' => ''),
+ 'COL_NAME' => array('Name' => 'Name', 'Description' => '', 'Type' => ''),
+ 'COL_NOTES' => array('Name' => 'Notes', 'Description' => '', 'Type' => ''),
+ 'COL_NR_BURSTS' => array('Name' => 'NumBursts', 'Description' => '', 'Type' => ''),
+ 'COL_NR_PINGS' => array('Name' => 'NumPings', 'Description' => '', 'Type' => ''),
+ 'COL_OPERATOR' => array('Name' => 'Operator', 'Description' => '', 'Type' => ''),
+ 'COL_OWNER_CALLSIGN' => array('Name' => 'OwnerCallsign', 'Description' => '', 'Type' => ''),
+ 'COL_PFX' => array('Name' => 'Prefix', 'Description' => '', 'Type' => ''),
+ 'COL_PRECEDENCE' => array('Name' => 'Precedence', 'Description' => '', 'Type' => ''),
+ 'COL_PROP_MODE' => array('Name' => 'PropMode', 'Description' => '', 'Type' => ''),
+ 'COL_PUBLIC_KEY' => array('Name' => 'PublicKey', 'Description' => '', 'Type' => ''),
+ 'COL_QSLMSG' => array('Name' => 'QSLMessage', 'Description' => '', 'Type' => ''),
+ 'COL_QSLRDATE' => array('Name' => 'QSLRecievedDate', 'Description' => '', 'Type' => ''),
+ 'COL_QSLSDATE' => array('Name' => 'QSLSentDate', 'Description' => '', 'Type' => ''),
+ 'COL_QSL_RCVD' => array('Name' => 'QSLRecieved', 'Description' => '', 'Type' => ''),
+ 'COL_QSL_RCVD_VIA' => array('Name' => 'QSLRecievedVia', 'Description' => '', 'Type' => ''),
+ 'COL_QSL_SENT' => array('Name' => 'QSLSent', 'Description' => '', 'Type' => ''),
+ 'COL_QSL_SENT_VIA' => array('Name' => 'QSLSentVia', 'Description' => '', 'Type' => ''),
+ 'COL_QSL_VIA' => array('Name' => 'QSLVia', 'Description' => '', 'Type' => ''),
+ 'COL_QSO_COMPLETE' => array('Name' => 'QSOComplete', 'Description' => '', 'Type' => ''),
+ 'COL_QSO_RANDOM' => array('Name' => 'QSORandom', 'Description' => '', 'Type' => ''),
+ 'COL_QTH' => array('Name' => 'QTH', 'Description' => '', 'Type' => ''),
+ 'COL_RIG' => array('Name' => 'Rig', 'Description' => '', 'Type' => ''),
+ 'COL_RST_RCVD' => array('Name' => 'ReportRecieved', 'Description' => '', 'Type' => ''),
+ 'COL_RST_SENT' => array('Name' => 'ReportSent', 'Description' => '', 'Type' => ''),
+ 'COL_RX_PWR' => array('Name' => 'RXPower', 'Description' => '', 'Type' => ''),
+ 'COL_SAT_MODE' => array('Name' => 'SatMode', 'Description' => '', 'Type' => ''),
+ 'COL_SAT_NAME' => array('Name' => 'SatName', 'Description' => '', 'Type' => ''),
+ 'COL_SFI' => array('Name' => 'SFI', 'Description' => '', 'Type' => ''),
+ 'COL_SIG' => array('Name' => 'Sig', 'Description' => '', 'Type' => ''),
+ 'COL_SIG_INFO' => array('Name' => 'SigInfo', 'Description' => '', 'Type' => ''),
+ 'COL_SRX' => array('Name' => 'UNK_SRX', 'Description' => '', 'Type' => ''),
+ 'COL_STX' => array('Name' => 'UNK_STX', 'Description' => '', 'Type' => ''),
+ 'COL_SRX_STRING' => array('Name' => 'UNK_SRX_STRING', 'Description' => '', 'Type' => ''),
+ 'COL_STX_STRING' => array('Name' => 'UNK_STX_STRING', 'Description' => '', 'Type' => ''),
+ 'COL_STATE' => array('Name' => 'State', 'Description' => '', 'Type' => ''),
+ 'COL_STATION_CALLSIGN' => array('Name' => 'StationCall', 'Description' => '', 'Type' => ''),
+ 'COL_SWL' => array('Name' => 'SWL', 'Description' => '', 'Type' => ''),
+ 'COL_TEN_TEN' => array('Name' => 'TenTen', 'Description' => '', 'Type' => ''),
+ 'COL_TIME_OFF' => array('Name' => 'TimeOff', 'Description' => '', 'Type' => ''),
+ 'COL_TIME_ON' => array('Name' => 'TimeOn', 'Description' => '', 'Type' => ''),
+ 'COL_TX_PWR' => array('Name' => 'TXPower', 'Description' => '', 'Type' => ''),
+ 'COL_WEB' => array('Name' => 'Website', 'Description' => '', 'Type' => ''),
+ 'COL_USER_DEFINED_0' => array('Name' => 'UNK_USER_DEFINED_0', 'Description' => '', 'Type' => ''),
+ 'COL_USER_DEFINED_1' => array('Name' => 'UNK_USER_DEFINED_1', 'Description' => '', 'Type' => ''),
+ 'COL_USER_DEFINED_2' => array('Name' => 'UNK_USER_DEFINED_2', 'Description' => '', 'Type' => ''),
+ 'COL_USER_DEFINED_3' => array('Name' => 'UNK_USER_DEFINED_3', 'Description' => '', 'Type' => ''),
+ 'COL_USER_DEFINED_4' => array('Name' => 'UNK_USER_DEFINED_4', 'Description' => '', 'Type' => ''),
+ 'COL_USER_DEFINED_5' => array('Name' => 'UNK_USER_DEFINED_5', 'Description' => '', 'Type' => ''),
+ 'COL_USER_DEFINED_6' => array('Name' => 'UNK_USER_DEFINED_6', 'Description' => '', 'Type' => ''),
+ 'COL_USER_DEFINED_7' => array('Name' => 'UNK_USER_DEFINED_7', 'Description' => '', 'Type' => ''),
+ 'COL_USER_DEFINED_8' => array('Name' => 'UNK_USER_DEFINED_8', 'Description' => '', 'Type' => ''),
+ 'COL_USER_DEFINED_9' => array('Name' => 'UNK_USER_DEFINED_9', 'Description' => '', 'Type' => ''),
+ 'COL_CREDIT_GRANTED' => array('Name' => 'UNK_CREDIT_GRANTED', 'Description' => '', 'Type' => ''),
+ 'COL_CREDIT_SUBMITTED' => array('Name' => 'UNK_CREDIT_SUBMITTED', 'Description' => '', 'Type' => ''),
+ );
+
+}
+
+?>
diff --git a/application/models/auth_model.php b/application/models/auth_model.php
new file mode 100644
index 00000000..3d46c02f
--- /dev/null
+++ b/application/models/auth_model.php
@@ -0,0 +1,95 @@
+_hash("password");
+ echo "Password hashed is '".$hash."\n";
+ echo "Does 'password' match '$hash'? result is ".$this->_auth("password", $hash)."\n";
+
+ }
+
+ // Retrieve a user
+ function get($username) {
+ $this->db->where('user_name', $username);
+ $r = $this->db->get($this->config->item('auth_table'));
+ if($r->num_rows == 1) {
+ return $r->result();
+ } else {
+ return 0;
+ }
+ }
+
+ function exists($username) {
+ if($this->get($username)->num_rows == 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ function add($username, $password, $email, $type) {
+ if(!$this->exists($username)) {
+ $data = array(
+ 'user_name' => $username,
+ 'user_password' => $this->_hash($password),
+ 'user_email' => $email,
+ 'user_type' => $type
+ );
+
+ $this->db->insert($this->config->item('auth_table'));
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ function authenticate($username, $password) {
+ $u = $this->get($username);
+ if($this->_hash($password, $u['user_password'])) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ function set($username, $data) {
+ $this->db->where('user_name', $username);
+ $this->db->update($this->config->item('auth_table', $data));
+ return 1;
+ }
+
+ private function _auth($password, $hash) {
+ $h = new PasswordHash(8, FALSE);
+ if($h->CheckPassword($password, $hash)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ private function _hash($password) {
+ $h = new PasswordHash(8, FALSE);
+ $hash = $h->HashPassword($password);
+ unset($h);
+
+ if(strlen($hash) < 20) {
+ return 0;
+ } else {
+ return $hash;
+ }
+ }
+
+}
+
+?>
diff --git a/application/third_party/PasswordHash.php b/application/third_party/PasswordHash.php
new file mode 100644
index 00000000..12958c7f
--- /dev/null
+++ b/application/third_party/PasswordHash.php
@@ -0,0 +1,253 @@
+ in 2004-2006 and placed in
+# the public domain. Revised in subsequent years, still public domain.
+#
+# There's absolutely no warranty.
+#
+# The homepage URL for this framework is:
+#
+# http://www.openwall.com/phpass/
+#
+# Please be sure to update the Version line if you edit this file in any way.
+# It is suggested that you leave the main version number intact, but indicate
+# your project name (after the slash) and add your own revision information.
+#
+# Please do not change the "private" password hashing method implemented in
+# here, thereby making your hashes incompatible. However, if you must, please
+# change the hash type identifier (the "$P$") to something different.
+#
+# Obviously, since this code is in the public domain, the above are not
+# requirements (there can be none), but merely suggestions.
+#
+class PasswordHash {
+ var $itoa64;
+ var $iteration_count_log2;
+ var $portable_hashes;
+ var $random_state;
+
+ function PasswordHash($iteration_count_log2, $portable_hashes)
+ {
+ $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+
+ if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
+ $iteration_count_log2 = 8;
+ $this->iteration_count_log2 = $iteration_count_log2;
+
+ $this->portable_hashes = $portable_hashes;
+
+ $this->random_state = microtime();
+ if (function_exists('getmypid'))
+ $this->random_state .= getmypid();
+ }
+
+ function get_random_bytes($count)
+ {
+ $output = '';
+ if (is_readable('/dev/urandom') &&
+ ($fh = @fopen('/dev/urandom', 'rb'))) {
+ $output = fread($fh, $count);
+ fclose($fh);
+ }
+
+ if (strlen($output) < $count) {
+ $output = '';
+ for ($i = 0; $i < $count; $i += 16) {
+ $this->random_state =
+ md5(microtime() . $this->random_state);
+ $output .=
+ pack('H*', md5($this->random_state));
+ }
+ $output = substr($output, 0, $count);
+ }
+
+ return $output;
+ }
+
+ function encode64($input, $count)
+ {
+ $output = '';
+ $i = 0;
+ do {
+ $value = ord($input[$i++]);
+ $output .= $this->itoa64[$value & 0x3f];
+ if ($i < $count)
+ $value |= ord($input[$i]) << 8;
+ $output .= $this->itoa64[($value >> 6) & 0x3f];
+ if ($i++ >= $count)
+ break;
+ if ($i < $count)
+ $value |= ord($input[$i]) << 16;
+ $output .= $this->itoa64[($value >> 12) & 0x3f];
+ if ($i++ >= $count)
+ break;
+ $output .= $this->itoa64[($value >> 18) & 0x3f];
+ } while ($i < $count);
+
+ return $output;
+ }
+
+ function gensalt_private($input)
+ {
+ $output = '$P$';
+ $output .= $this->itoa64[min($this->iteration_count_log2 +
+ ((PHP_VERSION >= '5') ? 5 : 3), 30)];
+ $output .= $this->encode64($input, 6);
+
+ return $output;
+ }
+
+ function crypt_private($password, $setting)
+ {
+ $output = '*0';
+ if (substr($setting, 0, 2) == $output)
+ $output = '*1';
+
+ $id = substr($setting, 0, 3);
+ # We use "$P$", phpBB3 uses "$H$" for the same thing
+ if ($id != '$P$' && $id != '$H$')
+ return $output;
+
+ $count_log2 = strpos($this->itoa64, $setting[3]);
+ if ($count_log2 < 7 || $count_log2 > 30)
+ return $output;
+
+ $count = 1 << $count_log2;
+
+ $salt = substr($setting, 4, 8);
+ if (strlen($salt) != 8)
+ return $output;
+
+ # We're kind of forced to use MD5 here since it's the only
+ # cryptographic primitive available in all versions of PHP
+ # currently in use. To implement our own low-level crypto
+ # in PHP would result in much worse performance and
+ # consequently in lower iteration counts and hashes that are
+ # quicker to crack (by non-PHP code).
+ if (PHP_VERSION >= '5') {
+ $hash = md5($salt . $password, TRUE);
+ do {
+ $hash = md5($hash . $password, TRUE);
+ } while (--$count);
+ } else {
+ $hash = pack('H*', md5($salt . $password));
+ do {
+ $hash = pack('H*', md5($hash . $password));
+ } while (--$count);
+ }
+
+ $output = substr($setting, 0, 12);
+ $output .= $this->encode64($hash, 16);
+
+ return $output;
+ }
+
+ function gensalt_extended($input)
+ {
+ $count_log2 = min($this->iteration_count_log2 + 8, 24);
+ # This should be odd to not reveal weak DES keys, and the
+ # maximum valid value is (2**24 - 1) which is odd anyway.
+ $count = (1 << $count_log2) - 1;
+
+ $output = '_';
+ $output .= $this->itoa64[$count & 0x3f];
+ $output .= $this->itoa64[($count >> 6) & 0x3f];
+ $output .= $this->itoa64[($count >> 12) & 0x3f];
+ $output .= $this->itoa64[($count >> 18) & 0x3f];
+
+ $output .= $this->encode64($input, 3);
+
+ return $output;
+ }
+
+ function gensalt_blowfish($input)
+ {
+ # This one needs to use a different order of characters and a
+ # different encoding scheme from the one in encode64() above.
+ # We care because the last character in our encoded string will
+ # only represent 2 bits. While two known implementations of
+ # bcrypt will happily accept and correct a salt string which
+ # has the 4 unused bits set to non-zero, we do not want to take
+ # chances and we also do not want to waste an additional byte
+ # of entropy.
+ $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+ $output = '$2a$';
+ $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
+ $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
+ $output .= '$';
+
+ $i = 0;
+ do {
+ $c1 = ord($input[$i++]);
+ $output .= $itoa64[$c1 >> 2];
+ $c1 = ($c1 & 0x03) << 4;
+ if ($i >= 16) {
+ $output .= $itoa64[$c1];
+ break;
+ }
+
+ $c2 = ord($input[$i++]);
+ $c1 |= $c2 >> 4;
+ $output .= $itoa64[$c1];
+ $c1 = ($c2 & 0x0f) << 2;
+
+ $c2 = ord($input[$i++]);
+ $c1 |= $c2 >> 6;
+ $output .= $itoa64[$c1];
+ $output .= $itoa64[$c2 & 0x3f];
+ } while (1);
+
+ return $output;
+ }
+
+ function HashPassword($password)
+ {
+ $random = '';
+
+ if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
+ $random = $this->get_random_bytes(16);
+ $hash =
+ crypt($password, $this->gensalt_blowfish($random));
+ if (strlen($hash) == 60)
+ return $hash;
+ }
+
+ if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
+ if (strlen($random) < 3)
+ $random = $this->get_random_bytes(3);
+ $hash =
+ crypt($password, $this->gensalt_extended($random));
+ if (strlen($hash) == 20)
+ return $hash;
+ }
+
+ if (strlen($random) < 6)
+ $random = $this->get_random_bytes(6);
+ $hash =
+ $this->crypt_private($password,
+ $this->gensalt_private($random));
+ if (strlen($hash) == 34)
+ return $hash;
+
+ # Returning '*' on error is safe here, but would _not_ be safe
+ # in a crypt(3)-like function used _both_ for generating new
+ # hashes and for validating passwords against existing hashes.
+ return '*';
+ }
+
+ function CheckPassword($password, $stored_hash)
+ {
+ $hash = $this->crypt_private($password, $stored_hash);
+ if ($hash[0] == '*')
+ $hash = crypt($password, $stored_hash);
+
+ return $hash == $stored_hash;
+ }
+}
+
+?>
diff --git a/application/views/api/index.php b/application/views/api/index.php
new file mode 100644
index 00000000..3b074cfb
--- /dev/null
+++ b/application/views/api/index.php
@@ -0,0 +1,117 @@
+createProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"/css/api.xsl\"");
+$xmlDoc->appendChild($xsl);
+
+// Get the method called, and build the root node
+$call = $data['queryInfo']['call'];
+$rootNode = $xmlDoc->createElement("HRDWebLogbook-API");
+$parentNode = $xmlDoc->appendChild($rootNode);
+
+// Get the results output
+$output = $data[$call."_Result"];
+
+// Add the queryInfo node
+$node = $xmlDoc->createElement("queryInfo");
+$queryElement = $parentNode->appendChild($node);
+$queryElement->setAttribute("timeStamp", date("r", time()));
+$queryElement->setAttribute("calledMethod", $data['queryInfo']['call']);
+//$queryElement->setAttribute("queryArgs", $queryArgsString);
+$queryElement->setAttribute("resultsCount", count($data['queryInfo']['numResults']));
+if(ENVIRONMENT == "development") {
+ $debugInfo = $xmlDoc->createElement("debugInfo");
+ $debugElement = $queryElement->appendChild($debugInfo);
+ $debugElement->setAttribute("dbQuery", $data['queryInfo']['dbQuery']);
+ $debugElement->setAttribute("clientVersion", $_SERVER['HTTP_USER_AGENT']);
+ $debugElement->setAttribute("requestURI", $_SERVER['REQUEST_URI']);
+ $debugElement->setAttribute("benchMark", $this->benchmark->marker['total_execution_time_start'].", ".$this->benchmark->marker['loading_time:_base_classes_start'].", ".$this->benchmark->marker['loading_time:_base_classes_end'].", ".$this->benchmark->marker['controller_execution_time_( api / search )_start']);
+}
+$queryElement->setAttribute("executionTime", $data['queryInfo']['executionTime']);
+$queryElement->setAttribute("logbookURL", $this->config->item('base_url'));
+
+// Add the main results node
+$node = $xmlDoc->createElement("elements");
+$elementsNode = $parentNode->appendChild($node);
+
+// Cycle through the results and add to the results node
+if($output['results'])
+{
+ foreach($output['results'] as $e) {
+ $node = $xmlDoc->createElement("element");
+ $element = $elementsNode->appendChild($node);
+
+ foreach($e as $attr) {
+ #while($attr = current($e)) {
+ if(is_array($attr))
+ {
+ foreach($attr as $subattr)
+ {
+ $node = $xmlDoc->createElement(key($e));
+ foreach($subattr as $subsubattr)
+ {
+ $node->setAttribute(key($subattr), $subsubattr);
+ next($subattr);
+ }
+ $element->appendChild($node);
+ }
+ }
+ else
+ {
+ $element->setAttribute(key($e), $attr);
+ }
+ next($e);
+ }
+ }
+}
+
+// Output formatted XML
+echo formatXmlString($xmlDoc->saveXML());
+
+// This function tidies up the outputted XML
+function formatXmlString($xml) {
+
+ // add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries)
+ $xml = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $xml);
+
+ // now indent the tags
+ $token = strtok($xml, "\n");
+ $result = ''; // holds formatted version as it is built
+ $pad = 0; // initial indent
+ $matches = array(); // returns from preg_matches()
+
+ // scan each line and adjust indent based on opening/closing tags
+ while ($token !== false) :
+
+ // test for the various tag states
+
+ // 1. open and closing tags on same line - no change
+ if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) :
+ $indent=0;
+ // 2. closing tag - outdent now
+ elseif (preg_match('/^<\/\w/', $token, $matches)) :
+ $pad--;
+ // 3. opening tag - don't pad this one, only subsequent tags
+ elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches)) :
+ $indent=1;
+ // 4. no indentation needed
+ else :
+ $indent = 0;
+ endif;
+
+ // pad the line with the required number of leading spaces
+ $line = str_pad($token, strlen($token)+$pad, ' ', STR_PAD_LEFT);
+ $result .= $line . "\n"; // add to the cumulative result, with linefeed
+ $token = strtok("\n"); // get the next token
+ $pad += $indent; // update the pad size for subsequent lines
+ endwhile;
+
+ return $result;
+}
+
+?>
diff --git a/application/views/auth/add.php b/application/views/auth/add.php
new file mode 100644
index 00000000..cde42eb4
--- /dev/null
+++ b/application/views/auth/add.php
@@ -0,0 +1,70 @@
+
Add Note
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/views/auth/edit.php b/application/views/auth/edit.php
new file mode 100644
index 00000000..2030a10a
--- /dev/null
+++ b/application/views/auth/edit.php
@@ -0,0 +1,72 @@
+result() as $row) { ?>
+
Edit Note - title; ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/views/auth/main.php b/application/views/auth/main.php
new file mode 100644
index 00000000..85ec58ac
--- /dev/null
+++ b/application/views/auth/main.php
@@ -0,0 +1,24 @@
+
\ No newline at end of file
diff --git a/application/views/auth/view.php b/application/views/auth/view.php
new file mode 100644
index 00000000..eebd737f
--- /dev/null
+++ b/application/views/auth/view.php
@@ -0,0 +1,8 @@
+result() as $row) { ?>
+