2019-04-18 06:02:40 +00:00
|
|
|
/*********************************************************************
|
|
|
|
* Searching for disks
|
|
|
|
*********************************************************************/
|
|
|
|
|
|
|
|
#ifdef __ORCAC__
|
|
|
|
#pragma noroot
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <control.h>
|
|
|
|
#include <list.h>
|
2019-04-19 03:58:57 +00:00
|
|
|
#include <misctool.h>
|
2019-04-18 06:02:40 +00:00
|
|
|
#include <quickdraw.h>
|
|
|
|
#include <qdaux.h>
|
2019-04-19 03:58:57 +00:00
|
|
|
#include <window.h>
|
2019-04-19 23:22:57 +00:00
|
|
|
#include <tcpip.h>
|
2019-04-18 06:02:40 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "netdiskerror.h"
|
|
|
|
#include "asprintf.h"
|
|
|
|
#include "json.h"
|
|
|
|
#include "jsonutil.h"
|
|
|
|
|
|
|
|
#include "diskbrowser.h"
|
|
|
|
#include "disksearch.h"
|
|
|
|
#include "browserutil.h"
|
|
|
|
|
2019-04-19 03:58:57 +00:00
|
|
|
/* Rectangle of the disk list control */
|
|
|
|
static Rect diskListRect = {45, 10, 147, 386};
|
|
|
|
|
|
|
|
/* Current length in disk list */
|
2019-04-19 04:20:51 +00:00
|
|
|
static unsigned diskListLength = 0;
|
2019-04-19 03:58:57 +00:00
|
|
|
|
|
|
|
/* Number of current page of results from server */
|
|
|
|
int pageNum;
|
2019-04-18 06:02:40 +00:00
|
|
|
|
|
|
|
static boolean processDoc(json_value *docObj);
|
|
|
|
static char *EncodeQueryString(char *queryString);
|
|
|
|
|
2019-04-19 03:58:57 +00:00
|
|
|
struct diskListEntry moreResultsEntry = {moreResultsString , 0, "", ""};
|
2019-04-20 02:37:58 +00:00
|
|
|
struct diskListEntry noResultsEntry = {noResultsString , 0x60, "", ""};
|
2019-04-19 03:58:57 +00:00
|
|
|
|
|
|
|
static void InsertDiskListEntry(struct diskListEntry *entry);
|
|
|
|
|
2019-04-18 06:02:40 +00:00
|
|
|
/* Do a search */
|
2019-04-19 03:58:57 +00:00
|
|
|
void DoSearch(boolean getMore) {
|
2019-04-18 06:02:40 +00:00
|
|
|
static char queryBuf[257];
|
2019-04-19 03:58:57 +00:00
|
|
|
static boolean gsDisksOnly = true; /* User preference: IIGS disks only? */
|
2019-04-18 06:02:40 +00:00
|
|
|
|
|
|
|
char *searchURL = NULL;
|
|
|
|
enum NetDiskError result = 0;
|
|
|
|
|
2019-04-19 04:20:51 +00:00
|
|
|
unsigned initialDiskListLength = diskListLength;
|
2019-04-19 03:58:57 +00:00
|
|
|
|
2019-04-18 06:02:40 +00:00
|
|
|
WaitCursor();
|
|
|
|
|
2019-04-19 23:22:57 +00:00
|
|
|
TCPIPConnect(NULL);
|
|
|
|
|
2019-04-19 03:58:57 +00:00
|
|
|
if (!getMore) {
|
|
|
|
FreeJSON();
|
|
|
|
GetLETextByID(window, searchLine, (StringPtr)&queryBuf);
|
|
|
|
gsDisksOnly = (FindRadioButton(window, 2) == 0);
|
|
|
|
pageNum = 0;
|
|
|
|
} else {
|
|
|
|
if (pageNum >= MAX_PAGES - 1) {
|
|
|
|
InitCursor();
|
|
|
|
SysBeep();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pageNum++;
|
|
|
|
}
|
2019-04-18 06:02:40 +00:00
|
|
|
|
|
|
|
char *queryString = EncodeQueryString(queryBuf+1);
|
|
|
|
if (queryString == NULL) {
|
|
|
|
result = OUT_OF_MEMORY;
|
|
|
|
goto errorReturn;
|
|
|
|
}
|
|
|
|
|
|
|
|
asprintf(&searchURL,
|
|
|
|
"http://archive.org/advancedsearch.php?"
|
2019-04-20 02:32:20 +00:00
|
|
|
"q=emulator%%3A%s%s%s%s"
|
2019-04-18 06:02:40 +00:00
|
|
|
"&fl%%5B%%5D=identifier&fl%%5B%%5D=title"
|
|
|
|
"&fl%%5B%%5D=emulator_ext"
|
2019-04-19 04:36:53 +00:00
|
|
|
"&sort%%5B%%5D=titleSorter+asc"
|
2019-04-18 06:02:40 +00:00
|
|
|
"&rows=%i&page=%i&output=json",
|
|
|
|
gsDisksOnly ? "apple2gs" : "apple2%2A",
|
2019-04-20 02:32:20 +00:00
|
|
|
queryString[0] != '\0' ? "%20(" : "",
|
2019-04-18 06:02:40 +00:00
|
|
|
queryString,
|
2019-04-20 02:32:20 +00:00
|
|
|
queryString[0] != '\0' ? ")" : "",
|
2019-04-19 03:58:57 +00:00
|
|
|
PAGE_SIZE,
|
|
|
|
pageNum + 1);
|
2019-04-18 06:02:40 +00:00
|
|
|
if (searchURL == NULL) {
|
|
|
|
result = URL_TOO_LONG;
|
|
|
|
goto errorReturn;
|
|
|
|
}
|
|
|
|
free(queryString);
|
|
|
|
queryString = NULL;
|
|
|
|
|
2019-04-19 03:58:57 +00:00
|
|
|
if (!getMore) {
|
|
|
|
FreeJSON();
|
|
|
|
}
|
|
|
|
result = ReadJSONFromURL(searchURL, &json[pageNum]);
|
2019-04-18 06:02:40 +00:00
|
|
|
if (result != OPERATION_SUCCESSFUL)
|
|
|
|
goto errorReturn;
|
|
|
|
|
2019-04-19 03:58:57 +00:00
|
|
|
json_value *response =
|
|
|
|
findEntryInObject(json[pageNum], "response", json_object);
|
2019-04-18 06:02:40 +00:00
|
|
|
if (response == NULL) {
|
|
|
|
result = NOT_EXPECTED_CONTENTS;
|
|
|
|
goto errorReturn;
|
|
|
|
}
|
|
|
|
|
2019-04-19 03:58:57 +00:00
|
|
|
if (!getMore) {
|
|
|
|
diskListLength = 0;
|
|
|
|
} else {
|
|
|
|
diskListLength--;
|
|
|
|
}
|
2019-04-18 06:02:40 +00:00
|
|
|
json_value *docs = findEntryInObject(response, "docs", json_array);
|
|
|
|
if (docs == NULL) {
|
|
|
|
result = NOT_EXPECTED_CONTENTS;
|
|
|
|
goto errorReturn;
|
|
|
|
}
|
|
|
|
processArray(docs, json_object, processDoc);
|
|
|
|
|
2019-04-19 03:58:57 +00:00
|
|
|
if (!getMore) {
|
|
|
|
diskList[0].memFlag = 0x80;
|
|
|
|
}
|
|
|
|
|
|
|
|
json_value *numFoundValue =
|
|
|
|
findEntryInObject(response, "numFound", json_integer);
|
|
|
|
if (numFoundValue != NULL && numFoundValue->u.integer > diskListLength) {
|
|
|
|
InsertDiskListEntry(&moreResultsEntry);
|
2019-04-18 06:02:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Update state of controls once disk list is available */
|
|
|
|
HiliteControl(noHilite, disksListHandle);
|
|
|
|
SetCtlMoreFlags(
|
|
|
|
GetCtlMoreFlags(disksListHandle) | fCtlCanBeTarget | fCtlWantEvents,
|
|
|
|
disksListHandle);
|
|
|
|
|
|
|
|
NewList2(NULL, 1, (Ref) diskList, refIsPointer,
|
2019-04-19 03:58:57 +00:00
|
|
|
diskListLength, (Handle)disksListHandle);
|
2019-04-18 06:02:40 +00:00
|
|
|
|
2019-04-19 03:58:57 +00:00
|
|
|
if (getMore) {
|
|
|
|
if (diskListLength >= initialDiskListLength) {
|
|
|
|
SelectMember2(initialDiskListLength, (Handle)disksListHandle);
|
|
|
|
ValidRect(&diskListRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (diskListLength > 0) {
|
2019-04-18 06:02:40 +00:00
|
|
|
if (FindTargetCtl() != disksListHandle) {
|
|
|
|
MakeThisCtlTarget(disksListHandle);
|
|
|
|
CallCtlDefProc(disksListHandle, ctlChangeTarget, 0);
|
|
|
|
}
|
2019-04-20 02:37:58 +00:00
|
|
|
} else {
|
|
|
|
InsertDiskListEntry(&noResultsEntry);
|
|
|
|
NewList2(NULL, 1, (Ref) diskList, refIsPointer,
|
|
|
|
diskListLength, (Handle)disksListHandle);
|
2019-04-18 06:02:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free(searchURL);
|
|
|
|
InitCursor();
|
|
|
|
return;
|
|
|
|
|
|
|
|
errorReturn:
|
|
|
|
NewList2(NULL, 1, (Ref) diskList, refIsPointer, 0, (Handle)disksListHandle);
|
|
|
|
free(queryString);
|
|
|
|
free(searchURL);
|
|
|
|
InitCursor();
|
|
|
|
ShowErrorAlert(result, searchErrorAlert);
|
|
|
|
}
|
|
|
|
|
|
|
|
static boolean processDoc(json_value *docObj) {
|
2019-04-19 03:58:57 +00:00
|
|
|
if (diskListLength >= DISK_LIST_MAX_LENGTH)
|
2019-04-18 06:02:40 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (docObj == NULL || docObj->type != json_object)
|
|
|
|
return false;
|
|
|
|
json_value *id = findEntryInObject(docObj, "identifier", json_string);
|
|
|
|
json_value *title = findEntryInObject(docObj, "title", json_string);
|
|
|
|
json_value *ext = findEntryInObject(docObj, "emulator_ext", json_string);
|
|
|
|
if (id == NULL || title == NULL || ext == NULL)
|
|
|
|
return true;
|
2019-04-19 03:58:57 +00:00
|
|
|
diskList[diskListLength].idPtr = id->u.string.ptr;
|
2019-04-18 06:02:40 +00:00
|
|
|
// TODO character set translation
|
2019-04-19 03:58:57 +00:00
|
|
|
diskList[diskListLength].memPtr = title->u.string.ptr;
|
|
|
|
diskList[diskListLength].extPtr = ext->u.string.ptr;
|
|
|
|
diskList[diskListLength++].memFlag = 0;
|
2019-04-18 06:02:40 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *EncodeQueryString(char *queryString) {
|
|
|
|
long sizeNeeded;
|
|
|
|
|
|
|
|
char *encodedStr = NULL;
|
|
|
|
sizeNeeded = strlen(queryString);
|
|
|
|
if (sizeNeeded > 10000)
|
|
|
|
return NULL;
|
|
|
|
encodedStr = malloc(sizeNeeded*3 + 1);
|
|
|
|
if (encodedStr == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
char *s = encodedStr;
|
|
|
|
char c;
|
|
|
|
while ((c = *queryString++) != '\0') {
|
|
|
|
if (c > 0x7F) {
|
|
|
|
//TODO character set translation
|
|
|
|
c = '*';
|
|
|
|
}
|
|
|
|
if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')) {
|
|
|
|
*s++ = c;
|
|
|
|
} else {
|
|
|
|
snprintf(s, 4, "%%%02X", (unsigned char)c);
|
|
|
|
s+= 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*s = '\0';
|
|
|
|
return encodedStr;
|
|
|
|
}
|
2019-04-19 03:58:57 +00:00
|
|
|
|
|
|
|
static void InsertDiskListEntry(struct diskListEntry *entry) {
|
|
|
|
if (diskListLength >= DISK_LIST_MAX_LENGTH)
|
|
|
|
return;
|
|
|
|
|
|
|
|
diskList[diskListLength++] = *entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeJSON(void) {
|
|
|
|
for (int i = 0; i < MAX_PAGES; i++) {
|
|
|
|
if (json[i] != NULL) {
|
|
|
|
json_value_free(json[i]);
|
|
|
|
json[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|