/* pdfdde.c -- control Adobe Acrobat under Windows.  Written by Fabrice
   Popineau many years ago, based on Adobe documentation.
   Modified by Akira Kakuto 2014-2016.
   Public domain.  */
#define  _WIN32_WINNT 0x0600
#include <afx.h>
#include <ddeml.h>
#include <dde.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <shellapi.h>

#include <getopt.h>

#define ACROBAT		"acroview"
#define ACROBATR10	"acroviewR10"
#define ACROBATA10	"acroviewA10"
#define ACROBATR11	"acroviewR11"
#define ACROBATA11	"acroviewA11"
#define ACROBATR15	"acroviewR15"
#define ACROBATA15	"acroviewA15"

#define SRV_NUM 7
char *SrvNam[SRV_NUM];

#define EVAL_TOPIC	"control"
#define RESULT_ITEM	"Result"
#define ERROR_ITEM	"Error"

/* Timeouts & delays */
#define CONNECT_DELAY		100		/* ms */
#define TRANSACTION_TIMEOUT	5000		/* ms */
#define MAX_INPUT_IDLE_WAIT     INFINITE	/* ms */

static DWORD DDEsession;
static HCONV DDEconversation;

/* The raw base name */
static char *argv0 = NULL;
static int nPage = 0;
static char *sFileName = NULL;
static int bAll = 0;
static int bServer = 0;
static int iDebug = 0;
static char *sGoto = NULL;
static char sLongFileName[256];
static int nPrefer = 0;
static char *sServerName = NULL;

const char *pdfdde_version_string = "0.6";

/* Test whether getopt found an option ``A''.
   Assumes the option index is in the variable `option_index', and the
   option table in a variable `long_options'.  */
#define ARGUMENT_IS(a) (_stricmp(long_options[option_index].name, a) == 0)
#define PROGRAM_IS(a) (_stricmp(a, argv0) == 0)

static struct option long_options [] = {
    { "rx",                  0, &nPrefer, 1},
    { "ax",                  0, &nPrefer, 2},
    { "rxi",                 0, &nPrefer, 3},
    { "axi",                 0, &nPrefer, 4},
    { "rxv",                 0, &nPrefer, 5},
    { "axv",                 0, &nPrefer, 6},
    { "r10",                 0, &nPrefer, 1},
    { "a10",                 0, &nPrefer, 2},
    { "r11",                 0, &nPrefer, 3},
    { "a11",                 0, &nPrefer, 4},
    { "r15",                 0, &nPrefer, 5},
    { "a15",                 0, &nPrefer, 6},
    { "debug",               0, 0, 0},
    { "help",                0, 0, 0},
    { "version",             0, 0, 0},
    { "file",                1, 0, 0},
    { "page",                1, 0, 0},
    { "goto",                1, 0, 0},
    { "all",                 0, 0, 0},
    {0, 0, 0, 0}
};


char *FindAcrobatModule()
{
    char buf[260];
    char path[260];
    char *program;
    HANDLE hFile;
    HINSTANCE hInst;
 
    program = (char *)malloc(MAX_PATH*sizeof(char));
    if (program == NULL) goto exit_1;

    buf[0] = path[0] = program[0] = '\0';
    
    if (GetTempPath(sizeof(path), path) != 0) {
	strcpy(buf, path);
    }


    strcat(buf, "dummy.pdf");
    
    hFile = CreateFile(buf, 
		       GENERIC_READ|GENERIC_WRITE, 
		       FILE_SHARE_READ | FILE_SHARE_WRITE, 
		       NULL,
		       OPEN_ALWAYS, 
		       FILE_ATTRIBUTE_NORMAL, 
		       NULL);
    
    CloseHandle(hFile);
    
    hInst = FindExecutable("dummy.pdf", path, program);
    
    DeleteFile(buf);
    
#if 0
    switch ((int)hInst) {
    case SE_ERR_FNF:
	fprintf(stdout, "File not found: %s\n", argv[1]);
	break;
    case SE_ERR_NOASSOC:
	fprintf(stdout, "No association for %s\n", argv[1]);
	break;
    default:
	fprintf(stdout, "File .pdf is opened by %s\n", program);
	break;
    }
#endif

    if (*program == '\0' || (GetFileAttributes(program) == 0xFFFFFFFF)) {
	program = NULL;
    }

exit_1:
    return program;

}

void CloseConversation (void)
{
    if (DDEconversation)
	DdeDisconnect(DDEconversation);
    if (DDEsession)
	DdeUninitialize(DDEsession);
}

void error(LPCTSTR fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fputc('\n', stderr);

    /* Tidy up */
    CloseConversation();
    exit(1);
}

void *emalloc(size_t len)
{
    void *p = malloc(len);

    if (p == NULL)
	error("Out of memory - cannot allocate %d bytes", len);

    return p;
}

int outstanding_requests;

HDDEDATA CALLBACK
Callback (UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2,
	  HDDEDATA hdata, DWORD dwData1, DWORD dwData2)
{
    if (uType == XTYP_ADVDATA) {
	DWORD len = DdeGetData(hdata, NULL, 0, 0);
	char *buf =(char *) _alloca(len + 1);
	DdeGetData(hdata, (LPBYTE)buf, len + 1, 0);
	
	if (--outstanding_requests == 0)
	    PostQuitMessage(0);
	
	return (HDDEDATA) DDE_FACK;
    }
    
    return (HDDEDATA) NULL;
}

int StartServer(LPCTSTR prog)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    
    /* To be sure ... */
    if (! prog) 
	return 1;

    ZeroMemory (&si, sizeof (si));
    si.cb = sizeof (si);
    if (!CreateProcess (NULL, (LPTSTR)prog, NULL, NULL, FALSE, 0,
			NULL, NULL, &si, &pi))
    {
	error("Could not start process %s", prog);
	return 1;
    }

    /* Wait for the process to enter an idle state */
    WaitForInputIdle (pi.hProcess, MAX_INPUT_IDLE_WAIT);

    /* Close the handles */
    CloseHandle (pi.hThread);
    CloseHandle (pi.hProcess);
    return 0;
}

HSZ DDEString(LPCTSTR str)
{
    HSZ hsz = DdeCreateStringHandle(DDEsession, str, CP_WINANSI);
    if (hsz == 0)
	error("Cannot create string for %s", str);
    return hsz;
}

void FreeString(HSZ hsz)
{
    DdeFreeStringHandle(DDEsession, hsz);
}

void OpenConversation(LPCTSTR topic_name)
{
    UINT ret;
    HSZ service;
    HSZ topic;
    int i, n;
    int nn = 0;
    
    ret = DdeInitialize(&DDEsession, (PFNCALLBACK)Callback, APPCMD_CLIENTONLY, 0);
    if (ret != DMLERR_NO_ERROR)
	error("Cannot start DDE");

    topic = DDEString(topic_name);

    if(nPrefer == 0) {
        if(sServerName)
          strcpy(SrvNam[0], sServerName);
        else
          strcpy(SrvNam[0], ACROBATA11);
        strcpy(SrvNam[1], ACROBATR11);
        strcpy(SrvNam[2], ACROBATA15);
        strcpy(SrvNam[3], ACROBATR15);
        strcpy(SrvNam[4], ACROBATA10);
        strcpy(SrvNam[5], ACROBATR10);
        strcpy(SrvNam[6], ACROBAT);
    } else if(nPrefer == 1) {
        if(sServerName)
          strcpy(SrvNam[0], sServerName);
        else
          strcpy(SrvNam[0], ACROBATR10);
        strcpy(SrvNam[1], ACROBATA10);
        strcpy(SrvNam[2], ACROBATR15);
        strcpy(SrvNam[3], ACROBATA15);
        strcpy(SrvNam[4], ACROBATR11);
        strcpy(SrvNam[5], ACROBATA11);
        strcpy(SrvNam[6], ACROBAT);
    } else if(nPrefer == 2) {
        if(sServerName)
          strcpy(SrvNam[0], sServerName);
        else
          strcpy(SrvNam[0], ACROBATA10);
        strcpy(SrvNam[1], ACROBATR10);
        strcpy(SrvNam[2], ACROBATA15);
        strcpy(SrvNam[3], ACROBATR15);
        strcpy(SrvNam[4], ACROBATA11);
        strcpy(SrvNam[5], ACROBATR11);
        strcpy(SrvNam[6], ACROBAT);
    } else if(nPrefer == 3) {
        if(sServerName)
          strcpy(SrvNam[0], sServerName);
        else
          strcpy(SrvNam[0], ACROBATR11);
        strcpy(SrvNam[1], ACROBATA11);
        strcpy(SrvNam[2], ACROBATR15);
        strcpy(SrvNam[3], ACROBATA15);
        strcpy(SrvNam[4], ACROBATR10);
        strcpy(SrvNam[5], ACROBATA10);
        strcpy(SrvNam[6], ACROBAT);
    } else if(nPrefer == 4) {
        if(sServerName)
          strcpy(SrvNam[0], sServerName);
        else
          strcpy(SrvNam[0], ACROBATA11);
        strcpy(SrvNam[1], ACROBATR11);
        strcpy(SrvNam[2], ACROBATA15);
        strcpy(SrvNam[3], ACROBATR15);
        strcpy(SrvNam[4], ACROBATA10);
        strcpy(SrvNam[5], ACROBATR10);
        strcpy(SrvNam[6], ACROBAT);
    } else if(nPrefer == 5) {
        if(sServerName)
          strcpy(SrvNam[0], sServerName);
        else
          strcpy(SrvNam[0], ACROBATR15);
        strcpy(SrvNam[1], ACROBATA15);
        strcpy(SrvNam[2], ACROBATR11);
        strcpy(SrvNam[3], ACROBATA11);
        strcpy(SrvNam[4], ACROBATR10);
        strcpy(SrvNam[5], ACROBATA10);
        strcpy(SrvNam[6], ACROBAT);
    } else if(nPrefer == 6) {
        if(sServerName)
          strcpy(SrvNam[0], sServerName);
        else
          strcpy(SrvNam[0], ACROBATA15);
        strcpy(SrvNam[1], ACROBATR15);
        strcpy(SrvNam[2], ACROBATA11);
        strcpy(SrvNam[3], ACROBATR11);
        strcpy(SrvNam[4], ACROBATA10);
        strcpy(SrvNam[5], ACROBATR10);
        strcpy(SrvNam[6], ACROBAT);
    }

    if (nn == 0) {
        service = DDEString(SrvNam[0]);
        DDEconversation = DdeConnect(DDEsession, service, topic, 0);

        if (DDEconversation == 0)
        {
	    if (StartServer(FindAcrobatModule()) == 0)
	    {
	        for (n = 0; n < 3; n++)
	        {
		    Sleep (CONNECT_DELAY);
		    DDEconversation = DdeConnect(DDEsession, service, topic, 0);
		    if (DDEconversation)
		        break;
	        }
	        if (DDEconversation == 0)
		    nn = 1;
	    }
        }
    }

    if (nn == 1) {
        for(i = 1; i < SRV_NUM; i++) {
            FreeString(service);
            service = DDEString(SrvNam[i]);
            DDEconversation = DdeConnect(DDEsession, service, topic, 0);
            if(DDEconversation != 0)
                nn = 0;
            else if(StartServer(FindAcrobatModule()) == 0) {
	        for (n = 0; n < 3; n++) {
		    Sleep (CONNECT_DELAY);
		    DDEconversation = DdeConnect(DDEsession, service, topic, 0);
		    if (DDEconversation)
		        break;
	        }
	        if (DDEconversation == 0)
		    nn = 2;
                else
                    nn = 0;
	    }
            if(nn == 0)
                break;
	}
    }

    if (nn == 2)
        error("Cannot contact a server.");

    FreeString(service);
    FreeString(topic);
}

void __cdecl ExecuteCommand(LPCTSTR command, ...)
{
    HDDEDATA ret;
    va_list args;
    int len;
    char *buffer;
    char tp[1024];

    va_start( args, command );
    len = _vsnprintf(tp, 1023, command, args)+1; // _vsnprintf doesn't count
                                                 // terminating '\0'
    buffer = (char *)malloc( len * sizeof(char) );
    vsprintf( buffer, command, args );
    
    ret = DdeClientTransaction((LPBYTE)buffer, strlen(buffer) + 1,
			       DDEconversation, 0, 0, XTYP_EXECUTE,
			       TRANSACTION_TIMEOUT, 0);
    if (ret == 0)
	error("Cannot execute command \"%s\" (error %ld)", command, DdeGetLastError(DDEsession));
}

void StartHotLink(LPCTSTR item_name)
{
    HSZ item = DDEString(item_name);
    DdeClientTransaction(0, 0, DDEconversation, item, CF_TEXT, XTYP_ADVSTART,
			 TRANSACTION_TIMEOUT, 0);
    FreeString(item);
}

LPTSTR RequestData (LPCTSTR item_name)
{
    HSZ item = DDEString(item_name);
    DWORD len;
    char *buf;
    HDDEDATA result;
    result = DdeClientTransaction (NULL, 0, DDEconversation, item, CF_TEXT,
				   XTYP_REQUEST, TRANSACTION_TIMEOUT, 0);
    FreeString(item);
    if (result == 0)
	error("Cannot request item %s\n", item_name);

    len = DdeGetData(result, NULL, 0, 0);
    buf = (char *)emalloc(len + 1);
    DdeGetData(result, (LPBYTE)buf, len + 1, 0);
    return buf;
}

void usage()
{
  fprintf(stderr, "Usage:\n");
  fprintf(stderr, "\tpdfopen  --file <filename> [--page <page>]\n");
  fprintf(stderr, "\tpdfopen  [--page <page>] <filename>\n");
  fprintf(stderr, "\t\t       Opens <filename> (at page <page> if available)\n");
  fprintf(stderr, "\t\t             in Adobe Acrobat or Adobe Reader.\n");
  fprintf(stderr, "\tpdfclose --file <filename>\n");
  fprintf(stderr, "\tpdfclose <filename>\n");
  fprintf(stderr, "\t         Closes <filename> in Adobe Acrobat or Adobe Reader.\n");
  fprintf(stderr, "\tpdfclose --all\n");
  fprintf(stderr, "\t         Closes all documents in Adobe Acrobat or Adobe Reader.\n");
  fprintf(stderr, "Beware: only documents opened by `pdfopen' can be closed\n");
  fprintf(stderr, "        by `pdfclose'.\n");
  fprintf(stderr, "Option:\n");
  fprintf(stderr, "\t         --rx  : Prefer the server Adobe Reader X.\n");
  fprintf(stderr, "\t         --ax  : Prefer the server Adobe Acrobat X.\n");
  fprintf(stderr, "\t         --rxi : Prefer the server Adobe Reader XI.\n");
  fprintf(stderr, "\t         --axi : Prefer the server Adobe Acrobat XI.\n");
  fprintf(stderr, "\t         --rxv : Prefer the server Adobe Reader XV.\n");
  fprintf(stderr, "\t         --axv : Prefer the server Adobe Acrobat XV.\n");
  fprintf(stderr, "\t         --r10 : Same as --rx.\n");
  fprintf(stderr, "\t         --a10 : Same as --ax.\n");
  fprintf(stderr, "\t         --r11 : Same as --rxi.\n");
  fprintf(stderr, "\t         --a11 : Same as --axi.\n");
  fprintf(stderr, "\t         --r15 : Same as --rxv.\n");
  fprintf(stderr, "\t         --a15 : Same as --axv.\n\n");
  fprintf(stderr, "If you see a message 'Cannot contact a server.'\n");
  fprintf(stderr, "you have to specify the DDE server name in a file\n");
  fprintf(stderr, "`pdfddeservername.txt' which is in a directory\n");
  fprintf(stderr, "where pdfdde.exe exists.\n");
  exit(0);
}

char *CheckFileName(char *p)
{
  char sTmp[256];
  char *fp;

  sLongFileName[0] = '\0';

  if (GetFileAttributes(p) == -1) {
    fprintf(stderr, "%s: non existent file %s\n", argv0, p);
    return NULL;
  }
  if (GetFullPathName(p, sizeof(sTmp), sTmp, &fp) == 0) {
    fprintf(stderr, "%s: failed to get full path name for %s (Error %d)\n", argv0, p, GetLastError());
    return NULL;
  }

/*
  if (GetLongPathName(sTmp, sLongFileName, sizeof(sLongFileName)) == 0) {
    fprintf(stderr, "%s: failed to get long path name for %s (Error %d)\n", argv0, sTmp, GetLastError());
    return NULL;
  }
*/

  strcpy(sLongFileName, sTmp);
  return sLongFileName;
}

int pdfopen()
{
  if (sLongFileName[0] == '\0') {
    fprintf(stderr, "%s: file is not found.\n", argv0);
    fprintf(stderr, "         if `--file' option is not used, file name\n");
    fprintf(stderr, "         must be the last argument.\n");
    fprintf(stderr, "         try `--help' option for the usage.\n");
    return EXIT_FAILURE;
  }

  OpenConversation(EVAL_TOPIC);
  
  ExecuteCommand("[DocOpen(\"%s\")]", sLongFileName); 
  ExecuteCommand("[FileOpen(\"%s\")]", sLongFileName); 

  if (nPage > 0) {
    ExecuteCommand("[DocGoTo(\"%s\", %d)]", sLongFileName, nPage); 
  }

  if (sGoto != NULL) {
    ExecuteCommand("[DocGoToNameDest(\"%s\", %s)]", sLongFileName, sGoto); 
  }

  CloseConversation();
#if 0
  /* Problem : it seems that these calls can put AR into a strange state.
     It would have been simpler if Adobe had simply iconified their application. */
  if (stricmp(argv0, "pdfclose") == 0) {
    sprintf(buf, "[AppHide()]");
  }
  else if (stricmp(argv0, "pdfopen") == 0) {
    sprintf(buf, "[AppShow()]");
  }
  bRetVal = DdeClientTransaction((unsigned char *)buf, (DWORD)strlen(buf),
				 (HCONV)hConversation, NULL,
				 (UINT)CF_TEXT, (UINT)XTYP_EXECUTE, (DWORD)1000, &dwResult);
#endif
  
  return EXIT_SUCCESS;
}

int pdfclose()
{
    OpenConversation(EVAL_TOPIC);

    if (bAll) {
	ExecuteCommand("[CloseAllDocs()]");
    }
    else if (sLongFileName[0] != '\0') {
	ExecuteCommand("[DocClose(\"%s\")]", sLongFileName);
    }
    
#if 0
    fprintf(stderr, "cmd : %s\n", buf);
#endif
    
    CloseConversation();
    
    return EXIT_SUCCESS;
}

int pdfserver()
{
  char line[1024];

  OpenConversation(EVAL_TOPIC);
  
  fprintf(stdout, "Type Ctrl-Z to quit.\n");

  while (fgets(line, sizeof(line), stdin)) {
#define WHITE_DELIM " \t\n"
    char *p = strtok(line, WHITE_DELIM);
    if (stricmp(p, "open") == 0) {
      p = strtok(NULL, WHITE_DELIM);
      if (CheckFileName(p) == NULL) goto next;
  
      ExecuteCommand("[DocOpen(\"%s\")]", sLongFileName); 
    }
    else if (stricmp(p, "close") == 0) {
      p = strtok(NULL, WHITE_DELIM);
      if (CheckFileName(p) == NULL) goto next;
      ExecuteCommand("[DocClose(\"%s\")]", sLongFileName);
    }
    else if (stricmp(p, "closeall") == 0) {
      ExecuteCommand("[CloseAllDocs()]");
    }
    else if (stricmp(p, "goto") == 0) {
      p = strtok(NULL, WHITE_DELIM);
      if (p == NULL) goto next;
      if (CheckFileName(p) == NULL) goto next;
      p = strtok(NULL, WHITE_DELIM);
      if (p == NULL) goto next;
      nPage = atoi(p) - 1;
      ExecuteCommand("[DocGoTo(\"%s\", %d)]", sLongFileName, nPage); 
    }
    else if (stricmp(p, "gotoname") == 0) {
      p = strtok(NULL, WHITE_DELIM);
      if (p == NULL) goto next;
      if (CheckFileName(p) == NULL) goto next;
      p = strtok(NULL, WHITE_DELIM);
      if (p == NULL) goto next;
      sGoto = p;
      ExecuteCommand("[DocGoToNameDest(\"%s\", %s)]", sLongFileName, sGoto); 
    }
    else if (stricmp(p, "show") == 0) {
      ExecuteCommand("[AppShow()]");

    }
    else if (stricmp(p, "hide") == 0) {
      ExecuteCommand("[AppHide()]");

    }
    else if (stricmp(p, "exit") == 0) {
      ExecuteCommand("[AppExit()]");
      goto exit;
    }
    else if (stricmp(p, "list") == 0) {
      fprintf(stdout, "open <file>		open the file\n");
      fprintf(stdout, "close <file>		close the file\n");
      fprintf(stdout, "closeall		close all files\n");
      fprintf(stdout, "goto <file> <page>	goto the given <page> in <file>\n");
      fprintf(stdout, "gotoname <file> <dest>	goto the <dest> named destination in <file>\n");
      fprintf(stdout, "show			show acroview\n");
      fprintf(stdout, "hide			hide acroview\n");
      fprintf(stdout, "exit			exit acroview and %s\n", argv0);
    }
  next: ;   
  }

#if 0
  fprintf(stderr, "cmd : %s\n", buf);
#endif
exit:
  CloseConversation();

  return EXIT_SUCCESS;
}

static char *getservername(void)
{
  LSTATUS retreg;
  HKEY    hkey;
  char    lpSubKey[512];
  DWORD   pdwType;
  char    pvData[128];
  DWORD   pcbData = 120;

  FILE *f;
  const char *fname = "pdfddeservername.txt";
  char buf[256];
  size_t  len;
  char buffer[256];
  char *ret = NULL;

/* First try to read the registry */
  hkey = HKEY_CLASSES_ROOT;
  strcpy(lpSubKey, "acrobat\\shell\\open\\ddeexec\\application");

  retreg = RegGetValueA(
  hkey,
  lpSubKey,
  "",
  RRF_RT_REG_SZ,
  &pdwType,
  pvData,
  &pcbData);

  if (retreg == ERROR_SUCCESS) {
    ret = _strdup(pvData);
    return ret;
  }

  if (GetModuleFileNameA(NULL, (LPCH) buffer, 256)) {
    char *p = strrchr(buffer, '\\');
    if (p) {
      p++;
      *p = '\0';
    }
    strcat (buffer, fname);
  } else {
    return NULL;
  }

  f = fopen(buffer, "r");
  if (f == NULL)
    return NULL;

  while(fgets(buf, 256, f)) {
    if (buf[0] != '#' && buf[0] != '\n')
      break;
    else
      continue;
  }

  fclose(f);
  if(strncmp(buf, "un", 2) == 0)
    return NULL;

  len = strlen (buf);
  if (len < 8 || buf[0] == '#')
    return NULL;

  if (buf[len - 1] == '\n')
    buf[len - 1] = '\0';

  ret = _strdup(buf);
  return ret;
}

int main (int argc, char *argv[])
{
  BOOL bRet = FALSE;
  char *p;
  int argv0len = 0;
  int g; /* getopt return code */
  int option_index;
  int i;

  sServerName = getservername();
 
  for(i=0; i < SRV_NUM; i++)
      SrvNam[i] = (char *)malloc(16);

  /* Make argv0 to point to the raw base name */
  argv0 = argv[0];
  if ((p = strrchr(argv0, '/'))
      || (p = strrchr(argv0, '\\'))) {
    argv0 = _strdup(p+1);
  }

  if ((argv0len = strlen(argv0)) > 4 
      && _strnicmp(argv0 + argv0len - 4, ".exe", 4) == 0)
    argv0[argv0len - 4] = '\0';

  sLongFileName[0] = '\0';

  if ((p = strrchr(argv[argc-1], '.')) && !_stricmp(p, ".pdf"))
    CheckFileName(argv[argc-1]);

  for(;;) {
    g = getopt_long_only (argc, argv, "", long_options, &option_index);
    
    if (g == EOF)
      break;

    if (g == '?') {
      usage();			/* Unknown option.  */
      for(i=0; i < SRV_NUM; i++)
          free(SrvNam[i]);
      if(sServerName)
          free(sServerName);
      exit(EXIT_FAILURE);
    }

    if (ARGUMENT_IS ("debug")) {
      iDebug = TRUE;
    }
    else if (ARGUMENT_IS ("help")) {
      usage();
      for(i=0; i < SRV_NUM; i++)
          free(SrvNam[i]);
      if(sServerName)
          free(sServerName);
      exit(EXIT_SUCCESS);
    }
    else if (ARGUMENT_IS ("version")) {
      fprintf(stderr, "%s of %s.\n", argv0, pdfdde_version_string);
      for(i=0; i < SRV_NUM; i++)
          free(SrvNam[i]);
      if(sServerName)
          free(sServerName);
      exit(EXIT_SUCCESS);
    }
    else if (PROGRAM_IS("pdfopen")) {
      if (ARGUMENT_IS("file")) {
	CheckFileName(optarg);
      }
      else if (ARGUMENT_IS("page")) {
	nPage = atoi(optarg) - 1;
      }
      else if (ARGUMENT_IS("goto")) {
	sGoto = optarg;
      }
    }
    else if (PROGRAM_IS("pdfclose")) {
      if (ARGUMENT_IS("file")) {
	CheckFileName(optarg);
      }
      else if (ARGUMENT_IS("all") && !sLongFileName[0]) {
	bAll = TRUE;
      }
    }
  }

  if (PROGRAM_IS("pdfopen")) {
    bRet = pdfopen();
  }
  else if (PROGRAM_IS("pdfclose")) {
    bRet = pdfclose();
  }
  else if (PROGRAM_IS("pdfdde")) {
    bRet = pdfserver();
  }
  else {
    fprintf(stderr, "This program has been incorrectly copied to the name %s.\n", argv[0]);
    bRet = EXIT_FAILURE;
  }
  for(i=0; i < SRV_NUM; i++)
      free(SrvNam[i]);
  if(sServerName)
      free(sServerName);
  return bRet;
}
