#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "server.h"
#include "textBuf.h"
#include "nedit.h"
#include "window.h"
#include "file.h"
#include "selection.h"
#include "macro.h"
#include "menu.h"
#include "preferences.h"
#include "server_common.h"
#include "filter.h"
#include "../util/fileUtils.h"
#include "../util/utils.h"
#include "../util/misc.h"
#include "../util/nedit_malloc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/param.h>
#include <unistd.h>
#include <pwd.h>
#include <Xm/Xm.h>
#include <Xm/XmP.h>
#ifdef HAVE_DEBUG_H
#include "../debug.h"
#endif
static void processServerCommand(
void);
static void cleanUpServerCommunication(
void);
static void processServerCommandString(
char *string);
static void getFileClosedProperty(WindowInfo *window);
static int isLocatedOnDesktop(WindowInfo *window,
long currentDesktop);
static WindowInfo *findWindowOnDesktop(
int tabbed,
long currentDesktop);
static Atom ServerRequestAtom =
0;
static Atom ServerExistsAtom =
0;
void InitServerCommunication(
void)
{
Window rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay));
CreateServerPropertyAtoms(GetPrefServerName(),
&ServerExistsAtom,
&ServerRequestAtom);
XSelectInput(TheDisplay, rootWindow, PropertyChangeMask);
XChangeProperty(TheDisplay, rootWindow, ServerExistsAtom,
XA_STRING,
8,
PropModeReplace, (
unsigned char *)
"True",
4);
atexit(cleanUpServerCommunication);
}
static void deleteProperty(Atom* atom)
{
if (!IsServer) {
*atom = None;
return;
}
if (*atom != None) {
XDeleteProperty(TheDisplay,
RootWindow(TheDisplay, DefaultScreen(TheDisplay)),
*atom);
*atom = None;
}
}
static void cleanUpServerCommunication(
void)
{
WindowInfo *w;
for (w = WindowList; w; w = w->next) {
DeleteFileClosedProperty(w);
}
DeleteServerFileAtoms(GetPrefServerName(),
RootWindow(TheDisplay, DefaultScreen(TheDisplay)));
deleteProperty(&ServerExistsAtom);
XSync(TheDisplay, False);
}
void ServerMainLoop(XtAppContext context)
{
while (
TRUE) {
XEvent event;
XtAppNextEvent(context, &event);
ServerDispatchEvent(&event);
}
}
static void processServerCommand(
void)
{
Atom dummyAtom;
unsigned long nItems, dummyULong;
unsigned char *propValue;
int getFmt;
if (XGetWindowProperty(TheDisplay, RootWindow(TheDisplay,
DefaultScreen(TheDisplay)), ServerRequestAtom,
0,
INT_MAX, True,
XA_STRING, &dummyAtom, &getFmt, &nItems, &dummyULong, &propValue)
!= Success || getFmt !=
8)
return;
processServerCommandString((
char *)propValue);
XFree(propValue);
}
Boolean ServerDispatchEvent(XEvent *event)
{
if (IsServer) {
Window rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay));
if (event->xany.window == rootWindow && event->xany.type == PropertyNotify) {
const XPropertyEvent* e = &event->xproperty;
if (e->type == PropertyNotify && e->window == rootWindow) {
if (e->atom == ServerRequestAtom && e->state == PropertyNewValue)
processServerCommand();
else if (e->atom == ServerExistsAtom && e->state == PropertyDelete)
XChangeProperty(TheDisplay,
rootWindow,
ServerExistsAtom,
XA_STRING,
8, PropModeReplace,
(
unsigned char *)
"True",
4);
}
}
}
return XtDispatchEvent(event);
}
static Atom findFileOpenProperty(
const char* filename,
const char* pathname) {
char path[
MAXPATHLEN];
Atom atom;
if (!IsServer)
return(None);
strcpy(path, pathname);
strcat(path, filename);
atom = CreateServerFileOpenAtom(GetPrefServerName(), path);
return(atom);
}
static void deleteFileOpenProperty(WindowInfo *window)
{
if (window->filenameSet) {
Atom atom = findFileOpenProperty(window->filename, window->path);
deleteProperty(&atom);
}
}
static void deleteFileOpenProperty2(
const char* filename,
const char* pathname)
{
Atom atom = findFileOpenProperty(filename, pathname);
deleteProperty(&atom);
}
static Atom findFileClosedProperty(
const char* filename,
const char* pathname)
{
char path[
MAXPATHLEN];
Atom atom;
if (!IsServer)
return(None);
strcpy(path, pathname);
strcat(path, filename);
atom = CreateServerFileClosedAtom(GetPrefServerName(),
path,
True);
return(atom);
}
static void getFileClosedProperty(WindowInfo *window)
{
if (window->filenameSet) {
window->fileClosedAtom = findFileClosedProperty(window->filename,
window->path);
}
}
void DeleteFileClosedProperty(WindowInfo *window)
{
if (window->filenameSet) {
deleteProperty(&window->fileClosedAtom);
}
}
static void deleteFileClosedProperty2(
const char* filename,
const char* pathname)
{
Atom atom = findFileClosedProperty(filename, pathname);
deleteProperty(&atom);
}
static int isLocatedOnDesktop(WindowInfo *window,
long currentDesktop)
{
long windowDesktop;
if (currentDesktop == -
1)
return True;
windowDesktop = QueryDesktop(TheDisplay, window->shell);
if (windowDesktop == currentDesktop || windowDesktop == 0xFFFFFFFFL)
return True;
return False;
}
static WindowInfo *findWindowOnDesktop(
int tabbed,
long currentDesktop)
{
WindowInfo *window;
if (tabbed ==
0 || (tabbed == -
1 && GetPrefOpenInTab() ==
0)) {
for (window=WindowList; window!=
NULL; window=window->next) {
if (window->filenameSet || window->fileChanged ||
window->macroCmdData !=
NULL) {
continue;
}
if (isLocatedOnDesktop(window, currentDesktop)) {
return window;
}
}
}
else {
for (window=WindowList; window!=
NULL; window=window->next) {
if (!IsTopDocument(window)) {
continue;
}
if (isLocatedOnDesktop(window, currentDesktop)) {
return window;
}
}
}
return NULL;
}
static void processServerCommandString(
char *string)
{
char *fullname, filename[
MAXPATHLEN], pathname[
MAXPATHLEN];
char *doCommand, *geometry, *langMode, *inPtr;
int editFlags, stringLen = strlen(string);
int lineNum, createFlag, readFlag, iconicFlag, lastIconic =
0, tabbed = -
1;
int fileLen, doLen, lmLen, geomLen, charsRead, itemsRead;
WindowInfo *window, *lastFile =
NULL;
long currentDesktop = QueryCurrentDesktop(TheDisplay,
RootWindow(TheDisplay, DefaultScreen(TheDisplay)));
if (string[
0] ==
'\0') {
for (window=WindowList; window!=
NULL; window=window->next)
if (!window->filenameSet && !window->fileChanged &&
isLocatedOnDesktop(window, currentDesktop))
break;
if (window ==
NULL) {
EditNewFile(findWindowOnDesktop(tabbed, currentDesktop),
NULL,
False,
NULL,
NULL);
CheckCloseDim();
}
else {
RaiseDocument(window);
WmClientMsg(TheDisplay, XtWindow(window->shell),
"_NET_ACTIVE_WINDOW",
0,
0,
0,
0,
0);
XMapRaised(TheDisplay, XtWindow(window->shell));
}
return;
}
inPtr = string;
while (
TRUE) {
if (*inPtr ==
'\0')
break;
itemsRead = sscanf(inPtr,
"%d %d %d %d %d %d %d %d %d%n", &lineNum,
&readFlag, &createFlag, &iconicFlag, &tabbed, &fileLen,
&doLen, &lmLen, &geomLen, &charsRead);
if (itemsRead !=
9)
goto readError;
inPtr += charsRead +
1;
if (inPtr - string + fileLen > stringLen)
goto readError;
fullname = inPtr;
inPtr += fileLen;
*inPtr++ =
'\0';
if (inPtr - string + doLen > stringLen)
goto readError;
doCommand = inPtr;
inPtr += doLen;
*inPtr++ =
'\0';
if (inPtr - string + lmLen > stringLen)
goto readError;
langMode = inPtr;
inPtr += lmLen;
*inPtr++ =
'\0';
if (inPtr - string + geomLen > stringLen)
goto readError;
geometry = inPtr;
inPtr += geomLen;
*inPtr++ =
'\0';
if (fileLen <=
0) {
for (window=WindowList; window!=
NULL; window=window->next) {
if(!window->filenameSet && !window->fileChanged &&
(isLocatedOnDesktop(window, currentDesktop))) {
break;
}
}
if (*doCommand ==
'\0') {
if (window ==
NULL) {
EditNewFile(findWindowOnDesktop(tabbed, currentDesktop),
NULL, iconicFlag, lmLen==
0?
NULL:langMode,
NULL);
}
else {
if (iconicFlag)
RaiseDocument(window);
else
RaiseDocumentWindow(window);
}
}
else {
WindowInfo *win = WindowList;
while (win !=
NULL && win->macroCmdData !=
NULL) {
win = win->next;
}
if (!win) {
XBell(TheDisplay,
0);
}
else {
if (iconicFlag)
RaiseDocument(win);
else
RaiseDocumentWindow(win);
DoMacro(win, doCommand,
"-do macro");
}
}
CheckCloseDim();
return;
}
editFlags = (readFlag ?
PREF_READ_ONLY :
0) |
CREATE |
(createFlag ?
SUPPRESS_CREATE_WARN :
0);
if (ParseFilename(fullname, filename, pathname) !=
0) {
fprintf(stderr,
"XNEdit: invalid file name\n");
deleteFileClosedProperty2(filename, pathname);
break;
}
window = FindWindowWithFile(filename, pathname);
if (window ==
NULL) {
size_t pathlen = strlen(pathname);
size_t namelen = strlen(filename);
char *fullpath = NEditMalloc(pathlen + namelen +
1);
memcpy(fullpath, pathname, pathlen);
memcpy(fullpath+pathlen, filename, namelen);
fullpath[pathlen+namelen] =
'\0';
IOFilter *filter = GetFilterForPath(fullpath);
const char *filter_name = filter ? filter->name :
NULL;
NEditFree(fullpath);
window = EditExistingFile(findWindowOnDesktop(tabbed, currentDesktop),
filename, pathname,
NULL, filter_name, editFlags, geometry, iconicFlag,
lmLen ==
0 ?
NULL : langMode,
tabbed == -
1? GetPrefOpenInTab() : tabbed, True);
if (window) {
CleanUpTabBarExposeQueue(window);
if (lastFile && window->shell != lastFile->shell) {
CleanUpTabBarExposeQueue(lastFile);
RaiseDocument(lastFile);
}
}
}
if (window !=
NULL) {
deleteFileOpenProperty(window);
getFileClosedProperty(window);
if (lineNum >
0)
SelectNumberedLine(window, lineNum);
if (*doCommand !=
'\0') {
RaiseDocument(window);
if (!iconicFlag) {
WmClientMsg(TheDisplay, XtWindow(window->shell),
"_NET_ACTIVE_WINDOW",
0,
0,
0,
0,
0);
XMapRaised(TheDisplay, XtWindow(window->shell));
}
if (window->macroCmdData !=
NULL) {
XBell(TheDisplay,
0);
}
else {
DoMacro(window, doCommand,
"-do macro");
if (!IsValidWindow(window))
window =
NULL;
if (lastFile && !IsValidWindow(lastFile))
lastFile =
NULL;
}
}
if (window) {
lastFile = window;
lastIconic = iconicFlag;
}
}
else {
deleteFileOpenProperty2(filename, pathname);
deleteFileClosedProperty2(filename, pathname);
}
}
if (lastFile) {
CleanUpTabBarExposeQueue(lastFile);
if (lastIconic)
RaiseDocument(lastFile);
else
RaiseDocumentWindow(lastFile);
CheckCloseDim();
}
return;
readError:
fprintf(stderr,
"XNEdit: error processing server request\n");
return;
}