2023-12-28 10:31:09 +00:00
|
|
|
// basic JASON API to BPQ Node
|
|
|
|
|
|
|
|
// Authentication is via Telnet USER records.
|
|
|
|
|
|
|
|
|
|
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
|
|
|
|
#include "CHeaders.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "tncinfo.h"
|
|
|
|
#include "asmstrucs.h"
|
|
|
|
#include "kiss.h"
|
|
|
|
|
|
|
|
// Constants
|
|
|
|
#define TOKEN_SIZE 32 // Length of the authentication token
|
|
|
|
#define TOKEN_EXPIRATION 7200 // Token expiration time in seconds (2 hours)
|
|
|
|
|
|
|
|
// Token data structure
|
|
|
|
typedef struct Token {
|
|
|
|
char token[TOKEN_SIZE + 1];
|
|
|
|
time_t expiration_time;
|
|
|
|
struct Token* next;
|
|
|
|
} Token;
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
typedef struct API
|
|
|
|
{
|
|
|
|
char *URL;
|
|
|
|
int URLLen;
|
2024-12-16 17:54:16 +00:00
|
|
|
int (* APIRoutine)(char * response, char * token, char * param);
|
2024-11-05 21:03:15 +00:00
|
|
|
int Auth;
|
|
|
|
} API;
|
|
|
|
|
|
|
|
// Auth defines
|
|
|
|
|
|
|
|
#define AuthNone 0
|
|
|
|
#define AuthUser 1
|
|
|
|
#define Auth BBSUser 2
|
|
|
|
#define AuthSysop 4
|
2023-12-28 10:31:09 +00:00
|
|
|
|
|
|
|
// Function prototypes
|
|
|
|
void handle_request(SOCKET client_socket, char * request, char * response);
|
|
|
|
int verify_token(const char* token);
|
|
|
|
void remove_expired_tokens();
|
|
|
|
char* fetch_data(const char* endpoint);
|
|
|
|
int request_token(char * response);
|
|
|
|
int send_http_response(char * response, const char* msg);
|
|
|
|
int create_json_response(char * response, char* access_token, int expires_in, char* scope);
|
|
|
|
void add_token_to_list(Token* token);
|
|
|
|
|
|
|
|
Token* find_token(const char* token);
|
|
|
|
Token* generate_token();
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
int sendPortList(char * response, char * token, char * Rest);
|
|
|
|
int sendNodeList(char * response, char * token, char * Rest);
|
|
|
|
int sendUserList(char * response, char * token, char * Rest);
|
|
|
|
int sendInfo(char * response, char * token, char * Rest);
|
|
|
|
int sendLinks(char * response, char * token, char * Rest);
|
|
|
|
int sendPortMHList(char * response, char * token, char * Rest);
|
2023-12-28 10:31:09 +00:00
|
|
|
|
2024-04-06 02:10:08 +01:00
|
|
|
void BuildPortMH(char * MHJSON, struct PORTCONTROL * PORT);
|
2023-12-28 10:31:09 +00:00
|
|
|
DllExport struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot);
|
|
|
|
|
|
|
|
// Token list
|
|
|
|
Token* token_list = NULL;
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
|
|
|
|
struct API APIList[] =
|
|
|
|
{
|
|
|
|
"/api/ports", 10, sendPortList, 0,
|
|
|
|
"/api/nodes", 10, sendNodeList, 0,
|
|
|
|
"/api/info", 9, sendInfo, 0,
|
|
|
|
"/api/links", 10, sendLinks, 0,
|
|
|
|
"/api/users", 10, sendUserList, 0,
|
|
|
|
"/api/mheard", 11, sendPortMHList, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
int APICount = sizeof(APIList) / sizeof(struct API);
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-12-28 10:31:09 +00:00
|
|
|
int xx()
|
|
|
|
{
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
// Remove expired tokens
|
|
|
|
remove_expired_tokens();
|
|
|
|
|
|
|
|
// Handle the client request
|
|
|
|
// handle_request();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int APIProcessHTTPMessage(char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE)
|
|
|
|
{
|
|
|
|
const char * auth_header = "Authorization: Bearer ";
|
|
|
|
char * token_begin = strstr(request, auth_header);
|
|
|
|
char token[TOKEN_SIZE + 1]= "";
|
2024-11-05 21:03:15 +00:00
|
|
|
int Flags = 0, n;
|
2023-12-28 10:31:09 +00:00
|
|
|
|
2024-04-06 02:10:08 +01:00
|
|
|
// Node Flags isn't currently used
|
2024-03-26 00:52:55 +00:00
|
|
|
|
2024-04-06 02:10:08 +01:00
|
|
|
char * Tok;
|
|
|
|
char * param;
|
|
|
|
|
|
|
|
if (token_begin)
|
2023-12-28 10:31:09 +00:00
|
|
|
{
|
2024-04-06 02:10:08 +01:00
|
|
|
// Using Auth Header
|
|
|
|
|
|
|
|
// Extract the token from the request (assuming it's present in the request headers)
|
|
|
|
|
|
|
|
if (token_begin == NULL)
|
|
|
|
{
|
|
|
|
Debugprintf("Invalid request: No authentication token provided.\n");
|
|
|
|
return send_http_response(response, "403 (Forbidden)");
|
|
|
|
}
|
2023-12-28 10:31:09 +00:00
|
|
|
|
2024-04-06 02:10:08 +01:00
|
|
|
token_begin += strlen(auth_header); // Move to the beginning of the token
|
|
|
|
strncpy(token, token_begin, TOKEN_SIZE);
|
|
|
|
token[TOKEN_SIZE] = '\0'; // Null-terminate the token
|
|
|
|
|
|
|
|
param = strlop(URL, '?');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-11-05 21:03:15 +00:00
|
|
|
// There may be a token as first param, but if auth not needed may be misisng
|
2024-04-06 02:10:08 +01:00
|
|
|
|
|
|
|
Tok = strlop(URL, '?');
|
|
|
|
param = strlop(Tok, '&');
|
|
|
|
|
|
|
|
if (Tok && strlen(Tok) == TOKEN_SIZE)
|
|
|
|
{
|
|
|
|
// assume auth token
|
|
|
|
|
|
|
|
strcpy(token, Tok);
|
|
|
|
}
|
2024-11-05 21:03:15 +00:00
|
|
|
else param = Tok;
|
2023-12-28 10:31:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
remove_expired_tokens(); // Tidy up
|
|
|
|
|
|
|
|
// Check if the request is for token generation
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
if (strcmp(Method, "OPTIONS") == 0)
|
|
|
|
{
|
|
|
|
// CORS Request
|
|
|
|
|
|
|
|
char Resp[] =
|
|
|
|
"HTTP/1.1 200 OK\r\n"
|
|
|
|
"Access-Control-Allow-Origin: *\r\n"
|
|
|
|
"Access-Control-Allow-Methods: POST, GET, OPTIONS\r\n"
|
|
|
|
"Access-Control-Allow-Headers: authorization";
|
|
|
|
|
|
|
|
return send_http_response(response, Resp);
|
|
|
|
}
|
|
|
|
|
2023-12-28 10:31:09 +00:00
|
|
|
if (strcmp(Method, "GET") != 0)
|
|
|
|
return send_http_response(response, "403 (Bad Method)");
|
|
|
|
|
|
|
|
if (_stricmp(URL, "/api/request_token") == 0)
|
|
|
|
return request_token(response);
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
/*
|
|
|
|
if (token[0] == 0)
|
2023-12-28 10:31:09 +00:00
|
|
|
{
|
|
|
|
// Extract the token from the request (assuming it's present in the request headers)
|
|
|
|
if (token_begin == NULL)
|
|
|
|
{
|
|
|
|
Debugprintf("Invalid request: No authentication token provided.\n");
|
|
|
|
return send_http_response(response, "403 (Forbidden)");
|
|
|
|
}
|
|
|
|
token_begin += strlen(auth_header); // Move to the beginning of the token
|
|
|
|
strncpy(token, token_begin, TOKEN_SIZE);
|
|
|
|
token[TOKEN_SIZE] = '\0'; // Null-terminate the token
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify the token
|
|
|
|
if (!verify_token(token))
|
|
|
|
{
|
|
|
|
Debugprintf("Invalid authentication token.\n");
|
|
|
|
return send_http_response(response, "401 Unauthorized");
|
|
|
|
}
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
*/
|
|
|
|
|
2023-12-28 10:31:09 +00:00
|
|
|
// Determine the requested API endpoint
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
for (n = 0; n < APICount; n++)
|
|
|
|
{
|
|
|
|
struct API * APIEntry;
|
|
|
|
char * rest;
|
|
|
|
|
|
|
|
APIEntry = &APIList[n];
|
|
|
|
|
|
|
|
if (_memicmp(URL, APIEntry->URL, APIEntry->URLLen) == 0)
|
|
|
|
{
|
|
|
|
rest = &request[4 + APIEntry->URLLen]; // Anything following?
|
|
|
|
|
|
|
|
if (rest[0] == ' ' || rest[0] == '/' || rest[0] == '?')
|
|
|
|
return APIEntry->APIRoutine(response, token, rest);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-12-28 10:31:09 +00:00
|
|
|
|
|
|
|
return send_http_response(response, "401 Invalid API Call");
|
|
|
|
}
|
|
|
|
|
|
|
|
int request_token(char * response)
|
|
|
|
{
|
|
|
|
Token * token = generate_token();
|
|
|
|
char scope[] = "create";
|
|
|
|
|
|
|
|
printf("Token generated: %s\n", token->token);
|
|
|
|
|
2024-10-11 15:37:11 +01:00
|
|
|
sprintf(response, "{\"access_token\":\"%s\", \"expires_at\":%ld,\"scope\":\"create\"}\r\n",
|
|
|
|
token->token, token->expiration_time);
|
2023-12-28 10:31:09 +00:00
|
|
|
|
|
|
|
return strlen(response);
|
|
|
|
}
|
|
|
|
|
|
|
|
Token * generate_token()
|
|
|
|
{
|
|
|
|
// Generate a random authentication token
|
2024-04-06 02:10:08 +01:00
|
|
|
|
2023-12-28 10:31:09 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
Token * token = malloc(sizeof(Token));
|
|
|
|
for (i = 0; i < TOKEN_SIZE; i++)
|
|
|
|
{
|
|
|
|
token->token[i] = 'A' + rand() % 26; // Random uppercase alphabet character
|
|
|
|
}
|
|
|
|
token->token[TOKEN_SIZE] = '\0'; // Null-terminate the token
|
|
|
|
token->expiration_time = time(NULL) + TOKEN_EXPIRATION; // Set token expiration time
|
|
|
|
add_token_to_list(token);
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to add the token to the token_list
|
2024-04-06 02:10:08 +01:00
|
|
|
|
2023-12-28 10:31:09 +00:00
|
|
|
void add_token_to_list(Token* token)
|
|
|
|
{
|
|
|
|
if (token_list == NULL)
|
|
|
|
{
|
|
|
|
token_list = token;
|
|
|
|
token->next = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Token* current = token_list;
|
|
|
|
|
|
|
|
while (current->next != NULL)
|
|
|
|
current = current->next;
|
|
|
|
|
|
|
|
current->next = token;
|
|
|
|
token->next = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int verify_token(const char* token)
|
|
|
|
{
|
|
|
|
// Find the token in the token list
|
|
|
|
Token * existing_token = find_token(token);
|
|
|
|
|
|
|
|
if (existing_token != NULL)
|
|
|
|
{
|
|
|
|
// Check if the token has expired
|
|
|
|
time_t current_time = time(NULL);
|
|
|
|
if (current_time > existing_token->expiration_time)
|
|
|
|
{
|
|
|
|
// Token has expired, remove it from the token list
|
|
|
|
remove_expired_tokens();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// Token is valid
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Token doesn't exist in the token list
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove_expired_tokens()
|
|
|
|
{
|
|
|
|
time_t current_time = time(NULL);
|
|
|
|
Token* current_token = token_list;
|
|
|
|
Token* prev_token = NULL;
|
|
|
|
Token* next_token;
|
|
|
|
|
|
|
|
while (current_token != NULL)
|
|
|
|
{
|
|
|
|
if (current_time > current_token->expiration_time)
|
|
|
|
{
|
|
|
|
// Token has expired, remove it from the token list
|
|
|
|
if (prev_token == NULL)
|
|
|
|
{
|
|
|
|
token_list = current_token->next;
|
|
|
|
} else {
|
|
|
|
prev_token->next = current_token->next;
|
|
|
|
}
|
|
|
|
next_token = current_token->next;
|
|
|
|
free(current_token);
|
|
|
|
current_token = next_token;
|
|
|
|
} else {
|
|
|
|
prev_token = current_token;
|
|
|
|
current_token = current_token->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Token * find_token(const char* token)
|
|
|
|
{
|
|
|
|
Token* current_token = token_list;
|
|
|
|
while (current_token != NULL)
|
|
|
|
{
|
|
|
|
if (strcmp(current_token->token, token) == 0)
|
|
|
|
{
|
|
|
|
return current_token;
|
|
|
|
}
|
|
|
|
current_token = current_token->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int send_http_response(char * response, const char* msg)
|
|
|
|
{
|
|
|
|
return sprintf(response, "HTTP/1.1 %s\r\nContent-Length: 0\r\nConnection: close\r\n\r\n", msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
{
|
|
|
|
"access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
|
|
|
|
"expires_in":3600,
|
|
|
|
"scope":"create"
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
{"ports":[
|
|
|
|
{"ID":"My Port", "Driver":"KISS", "Number":2, "State":"Active"),
|
|
|
|
{ ...},
|
|
|
|
{...}
|
|
|
|
]}
|
|
|
|
*/
|
|
|
|
|
|
|
|
extern int MasterPort[MAXBPQPORTS+1]; // Pointer to first BPQ port for a specific MPSK or UZ7HO host
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
int sendPortList(char * response, char * token, char * param)
|
2023-12-28 10:31:09 +00:00
|
|
|
{
|
|
|
|
char * Array = 0;
|
|
|
|
int ArrayLen = 0;
|
|
|
|
int ArrayPtr = 0;
|
|
|
|
|
|
|
|
struct _EXTPORTDATA * ExtPort;
|
|
|
|
struct PORTCONTROL * Port;
|
|
|
|
struct PORTCONTROL * SAVEPORT;
|
|
|
|
int PortNo;
|
|
|
|
|
|
|
|
int count;
|
|
|
|
char DLL[20];
|
|
|
|
char Status[32]="Unknown";
|
|
|
|
char ID[33];
|
|
|
|
char * ptr;
|
|
|
|
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], "{\"ports\":[\r\n");
|
|
|
|
|
|
|
|
for (count = 1; count <= NUMBEROFPORTS; count++)
|
|
|
|
{
|
|
|
|
Port = GetPortTableEntryFromSlot(count);
|
|
|
|
ExtPort = (struct _EXTPORTDATA *)Port;
|
|
|
|
PortNo = Port->PORTNUMBER;
|
|
|
|
|
|
|
|
if (Port->PORTTYPE == 0x10)
|
|
|
|
{
|
|
|
|
strcpy(DLL, ExtPort->PORT_DLL_NAME);
|
|
|
|
strlop(DLL, '.');
|
|
|
|
strlop(DLL, ' ');
|
|
|
|
}
|
|
|
|
else if (Port->PORTTYPE == 0)
|
|
|
|
strcpy(DLL, "ASYNC");
|
|
|
|
|
|
|
|
else if (Port->PORTTYPE == 22)
|
|
|
|
strcpy(DLL, "I2C");
|
|
|
|
|
|
|
|
else if (Port->PORTTYPE == 14)
|
|
|
|
strcpy(DLL, "INTERNAL");
|
|
|
|
|
|
|
|
else if (Port->PORTTYPE > 0 && Port->PORTTYPE < 14)
|
|
|
|
strcpy(DLL, "HDLC");
|
|
|
|
|
|
|
|
|
|
|
|
if (Port->PortStopped)
|
|
|
|
{
|
|
|
|
strcpy(Status, "Stopped");
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (Port->PORTTYPE == 0)
|
|
|
|
{
|
|
|
|
struct KISSINFO * KISS = (struct KISSINFO *)Port;
|
|
|
|
NPASYINFO KPort;
|
|
|
|
|
|
|
|
SAVEPORT = Port;
|
|
|
|
|
|
|
|
if (KISS->FIRSTPORT && KISS->FIRSTPORT != KISS)
|
|
|
|
{
|
|
|
|
// Not first port on device
|
|
|
|
|
|
|
|
Port = (struct PORTCONTROL *)KISS->FIRSTPORT;
|
|
|
|
KPort = KISSInfo[PortNo];
|
|
|
|
}
|
|
|
|
|
|
|
|
KPort = KISSInfo[PortNo];
|
|
|
|
|
|
|
|
if (KPort)
|
|
|
|
{
|
|
|
|
// KISS like - see if connected
|
|
|
|
|
|
|
|
if (Port->PORTIPADDR.s_addr || Port->KISSSLAVE)
|
|
|
|
{
|
|
|
|
// KISS over UDP or TCP
|
|
|
|
|
|
|
|
if (Port->KISSTCP)
|
|
|
|
{
|
|
|
|
if (KPort->Connected)
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
else
|
|
|
|
if (Port->KISSSLAVE)
|
|
|
|
strcpy(Status, "Listen");
|
|
|
|
else
|
|
|
|
strcpy(Status, "Closed");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
strcpy(Status, "UDP");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (KPort->idComDev) // Serial port Open
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
else
|
|
|
|
strcpy(Status, "Closed");
|
|
|
|
|
|
|
|
|
|
|
|
Port = SAVEPORT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Port->PORTTYPE == 14) // Loopback
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
|
|
|
|
else if (Port->PORTTYPE == 16) // External
|
|
|
|
{
|
|
|
|
if (Port->PROTOCOL == 10) // 'HF' Port
|
|
|
|
{
|
|
|
|
struct TNCINFO * TNC = TNCInfo[PortNo];
|
|
|
|
|
|
|
|
if (TNC)
|
|
|
|
{
|
|
|
|
switch (TNC->Hardware) // Hardware Type
|
|
|
|
{
|
|
|
|
case H_SCS:
|
|
|
|
case H_KAM:
|
|
|
|
case H_AEA:
|
|
|
|
case H_HAL:
|
|
|
|
case H_TRK:
|
|
|
|
case H_SERIAL:
|
|
|
|
|
|
|
|
// Serial
|
|
|
|
|
|
|
|
if (TNC->hDevice)
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
else
|
|
|
|
strcpy(Status, "Closed");
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case H_UZ7HO:
|
|
|
|
|
|
|
|
if (TNCInfo[MasterPort[PortNo]]->CONNECTED)
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
else
|
|
|
|
strcpy(Status, "Closed");
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case H_WINMOR:
|
|
|
|
case H_V4:
|
|
|
|
|
|
|
|
case H_MPSK:
|
|
|
|
case H_FLDIGI:
|
|
|
|
case H_UIARQ:
|
|
|
|
case H_ARDOP:
|
|
|
|
case H_VARA:
|
|
|
|
case H_KISSHF:
|
|
|
|
case H_WINRPR:
|
|
|
|
case H_FREEDATA:
|
|
|
|
|
|
|
|
// TCP
|
|
|
|
|
|
|
|
if (TNC->CONNECTED)
|
|
|
|
{
|
|
|
|
if (TNC->Streams[0].Attached)
|
|
|
|
strcpy(Status, "In Use");
|
|
|
|
else
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
strcpy(Status, "Closed");
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case H_TELNET:
|
|
|
|
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// External but not HF - AXIP, BPQETHER VKISS, ??
|
|
|
|
|
|
|
|
struct _EXTPORTDATA * EXTPORT = (struct _EXTPORTDATA *)Port;
|
|
|
|
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
strlop(Status, ' ');
|
|
|
|
strcpy(ID, Port->PORTDESCRIPTION);
|
|
|
|
ptr = &ID[29];
|
|
|
|
while (*(ptr) == ' ')
|
|
|
|
{
|
|
|
|
*(ptr--) = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], " {\"ID\":\"%s\", \"Driver\":\"%s\", \"Number\":%d,\"State\":\"%s\"},\r\n",
|
|
|
|
ID, DLL, Port->PORTNUMBER, Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayPtr -= 3; // remove trailing comma
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}\r\n");
|
|
|
|
|
|
|
|
return ArrayPtr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
{"Nodes":[
|
|
|
|
{"Call":"xx", "Alias":"xx", "Nbour1 ":"xx", "Quality":192),
|
|
|
|
{ ...},
|
|
|
|
{...}
|
|
|
|
]}
|
|
|
|
*/
|
|
|
|
|
|
|
|
extern int MaxNodes;
|
|
|
|
extern struct DEST_LIST * DESTS; // NODE LIST
|
|
|
|
extern int DEST_LIST_LEN;
|
|
|
|
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
int sendNodeList(char * response, char * token, char * param)
|
2023-12-28 10:31:09 +00:00
|
|
|
{
|
|
|
|
int ArrayPtr = 0;
|
|
|
|
|
|
|
|
int count, len, i;
|
|
|
|
char Normcall[10], Portcall[10];
|
|
|
|
char Alias[7];
|
|
|
|
struct DEST_LIST * Dests = DESTS ;
|
|
|
|
// struct ROUTE * Routes;
|
|
|
|
|
|
|
|
Dests = DESTS;
|
|
|
|
MaxNodes = MAXDESTS;
|
|
|
|
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], "{\"nodes\":[\r\n");
|
|
|
|
|
|
|
|
Dests-=1;
|
|
|
|
|
|
|
|
for (count = 0; count < MaxNodes; count++)
|
|
|
|
{
|
|
|
|
Dests+=1;
|
|
|
|
|
|
|
|
if (Dests->DEST_CALL[0] == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
len = ConvFromAX25(Dests->DEST_CALL, Normcall);
|
|
|
|
Normcall[len] = 0;
|
|
|
|
|
|
|
|
memcpy(Alias, Dests->DEST_ALIAS, 6);
|
|
|
|
|
|
|
|
Alias[6]=0;
|
|
|
|
|
|
|
|
for (i=0;i<6;i++)
|
|
|
|
{
|
|
|
|
if (Alias[i] == ' ')
|
|
|
|
Alias[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\":\"%s\", \"Alias\":\"%s\", \"Routes\":[", Normcall, Alias);
|
|
|
|
|
|
|
|
|
|
|
|
// Add an array with up to 6 objects (3 NR + 3 INP3 Neighbours
|
|
|
|
|
|
|
|
if (Dests->NRROUTE[0].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[0].ROUT_NEIGHBOUR->INP3Node == 0)
|
|
|
|
{
|
|
|
|
len = ConvFromAX25(Dests->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall);
|
|
|
|
Portcall[len] = 0;
|
|
|
|
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], "{\"Call\":\"%s\", \"Port\":%d, \"Quality\":%d},",
|
|
|
|
Portcall, Dests->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, Dests->NRROUTE[0].ROUT_QUALITY);
|
|
|
|
|
|
|
|
|
|
|
|
// if (Dests->NRROUTE[0].ROUT_OBSCOUNT > 127)
|
|
|
|
// {
|
|
|
|
// len=sprintf(&line[cursor],"! ");
|
|
|
|
// cursor+=len;
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
if (Dests->NRROUTE[1].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[1].ROUT_NEIGHBOUR->INP3Node == 0)
|
|
|
|
{
|
|
|
|
len=ConvFromAX25(Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall);
|
|
|
|
Portcall[len]=0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\":\"%s\", \"Port\":%d, \"Quality\":%d},",
|
|
|
|
Portcall, Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, Dests->NRROUTE[1].ROUT_QUALITY);
|
|
|
|
//if (Dests->NRROUTE[1].ROUT_OBSCOUNT > 127)
|
|
|
|
//{
|
|
|
|
//len=sprintf(&line[cursor],"! ");
|
|
|
|
//cursor+=len;
|
|
|
|
//}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Dests->NRROUTE[2].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[2].ROUT_NEIGHBOUR->INP3Node == 0)
|
|
|
|
{
|
|
|
|
len=ConvFromAX25(Dests->NRROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall);
|
|
|
|
Portcall[len]=0;
|
|
|
|
|
|
|
|
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\":\"%s\", \"Port\":%d, \"Quality\":%d},",
|
|
|
|
Portcall, Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, Dests->NRROUTE[1].ROUT_QUALITY);
|
|
|
|
|
|
|
|
//if (Dests->NRROUTE[2].ROUT_OBSCOUNT > 127)
|
|
|
|
//{
|
|
|
|
//len=sprintf(&line[cursor],"! ");
|
|
|
|
//cursor+=len;
|
|
|
|
|
|
|
|
}
|
|
|
|
ArrayPtr -= 1; // remove comma
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], "]},\r\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayPtr -= 3; // remove comma
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}");
|
|
|
|
|
|
|
|
return ArrayPtr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
int sendUserList(char * response, char * token, char * param)
|
2023-12-28 10:31:09 +00:00
|
|
|
{
|
|
|
|
int ArrayPtr = 0;
|
|
|
|
int n = MAXCIRCUITS;
|
|
|
|
TRANSPORTENTRY * L4 = L4TABLE;
|
2024-11-05 21:03:15 +00:00
|
|
|
// TRANSPORTENTRY * Partner;
|
2023-12-28 10:31:09 +00:00
|
|
|
int MaxLinks = MAXLINKS;
|
|
|
|
char State[12] = "", Type[12] = "Uplink";
|
|
|
|
char LHS[50] = "", MID[10] = "", RHS[50] = "";
|
2024-11-05 21:03:15 +00:00
|
|
|
// char Line[100];
|
2023-12-28 10:31:09 +00:00
|
|
|
char Normcall[10];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], "{\"users\":[\r\n");
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (L4->L4USER[0])
|
|
|
|
{
|
|
|
|
RHS[0] = MID[0] = 0;
|
|
|
|
|
|
|
|
len = ConvFromAX25(L4->L4USER, Normcall);
|
|
|
|
Normcall[len] = 0;
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\": \"%s\"},\r\n", Normcall);
|
2023-12-28 10:31:09 +00:00
|
|
|
L4++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ArrayPtr == 12) //empty list
|
|
|
|
{
|
|
|
|
ArrayPtr -=2;
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], "]}\r\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ArrayPtr -= 3; // remove trailing comma
|
|
|
|
ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}\r\n");
|
|
|
|
}
|
|
|
|
return ArrayPtr;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern char MYALIASLOPPED[];
|
|
|
|
extern char TextVerstring[];
|
|
|
|
extern char LOCATOR[];
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
int sendInfo(char * response, char * token, char * param)
|
2023-12-28 10:31:09 +00:00
|
|
|
{
|
|
|
|
char call[10];
|
|
|
|
|
|
|
|
memcpy(call, MYNODECALL, 10);
|
|
|
|
strlop(call, ' ');
|
|
|
|
|
|
|
|
sprintf(response, "{\"info\":{\"NodeCall\":\"%s\", \"Alias\":\"%s\", \"Locator\":\"%s\", \"Version\":\"%s\"}}\r\n",
|
|
|
|
call, MYALIASLOPPED, LOCATOR, TextVerstring);
|
|
|
|
|
|
|
|
return strlen(response);
|
|
|
|
}
|
2024-03-26 00:52:55 +00:00
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
int sendLinks(char * response, char * token, char * param)
|
2024-03-26 00:52:55 +00:00
|
|
|
{
|
|
|
|
struct _LINKTABLE * Links = LINKS;
|
|
|
|
int MaxLinks = MAXLINKS;
|
|
|
|
int count;
|
|
|
|
char Normcall1[10];
|
|
|
|
char Normcall2[10];
|
|
|
|
char State[12] = "", Type[12] = "Uplink";
|
|
|
|
int axState;
|
|
|
|
int cctType;
|
|
|
|
int ReplyLen = 0;
|
|
|
|
ReplyLen += sprintf(&response[ReplyLen],"{\"links\":[\r\n");
|
|
|
|
|
|
|
|
for (count=0; count<MaxLinks; count++)
|
|
|
|
{
|
|
|
|
if (Links->LINKCALL[0] != 0)
|
|
|
|
{
|
|
|
|
int len = ConvFromAX25(Links->LINKCALL, Normcall1);
|
|
|
|
Normcall1[len] = 0;
|
|
|
|
|
|
|
|
len = ConvFromAX25(Links->OURCALL, Normcall2);
|
|
|
|
Normcall2[len] = 0;
|
|
|
|
|
|
|
|
|
|
|
|
axState = Links->L2STATE;
|
|
|
|
|
|
|
|
if (axState == 2)
|
|
|
|
strcpy(State, "Connecting");
|
|
|
|
else if (axState == 3)
|
|
|
|
strcpy(State, "FRMR");
|
|
|
|
else if (axState == 4)
|
|
|
|
strcpy(State, "Closing");
|
|
|
|
else if (axState == 5)
|
|
|
|
strcpy(State, "Active");
|
|
|
|
else if (axState == 6)
|
|
|
|
strcpy(State, "REJ Sent");
|
|
|
|
|
|
|
|
cctType = Links->LINKTYPE;
|
|
|
|
|
|
|
|
if (cctType == 1)
|
|
|
|
strcpy(Type, "Uplink");
|
|
|
|
else if (cctType == 2)
|
|
|
|
strcpy(Type, "Downlink");
|
|
|
|
else if (cctType == 3)
|
|
|
|
strcpy(Type, "Node-Node");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ReplyLen += sprintf(&response[ReplyLen], "{\"farCall\": \"%s\",\"ourCall\": \"%s\", \"port\": \"%d\", \"state\": \"%s\", \"linkType\": \"%s\", \"ax25Version\": \"%d\"},\r\n",
|
|
|
|
Normcall1, Normcall2, Links->LINKPORT->PORTNUMBER,
|
|
|
|
State, Type, 2 - Links->VER1FLAG );
|
|
|
|
Links+=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ReplyLen < 13)
|
|
|
|
ReplyLen -= 2; // no links
|
|
|
|
else
|
|
|
|
ReplyLen -= 3; // remove trailing comma
|
|
|
|
|
|
|
|
ReplyLen+= sprintf(&response[ReplyLen], "\r\n]}\r\n");
|
|
|
|
|
|
|
|
return ReplyLen;
|
|
|
|
}
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
int sendPortMHList(char * response, char * token, char * param)
|
2024-03-26 00:52:55 +00:00
|
|
|
{
|
2024-11-05 21:03:15 +00:00
|
|
|
struct PORTCONTROL * PORTVEC ;
|
|
|
|
int n;
|
|
|
|
int port = 0;
|
2024-03-26 00:52:55 +00:00
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
if (param[0] = '?' || param[0] == '/')
|
|
|
|
port = atoi(¶m[1]);
|
|
|
|
|
|
|
|
PORTVEC = GetPortTableEntryFromPortNum(port);
|
2024-03-26 00:52:55 +00:00
|
|
|
response[0] = 0;
|
|
|
|
|
|
|
|
if (PORTVEC == 0)
|
|
|
|
return send_http_response(response, "401 Invalid API Call");
|
|
|
|
|
2024-11-05 21:03:15 +00:00
|
|
|
n = sprintf(response,"{\"mheard\":[\r\n");
|
|
|
|
|
|
|
|
BuildPortMH(&response[n], PORTVEC );
|
|
|
|
|
|
|
|
if (response[n] == 0) // No entries
|
|
|
|
{
|
|
|
|
response[strlen(response) - 2] = '\0'; // remove \r\n
|
|
|
|
strcat(response, "]}\r\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
response[strlen(response)-3 ] = '\0'; // remove ,\r\n
|
|
|
|
strcat(response, "\r\n]}\r\n");
|
2024-03-26 00:52:55 +00:00
|
|
|
// printf("MH for port %d:\r\n%s\r\n", PORTVEC->PORTNUMBER, response);
|
2024-11-05 21:03:15 +00:00
|
|
|
}
|
|
|
|
return strlen(response);
|
2024-03-26 00:52:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|