/* WIDE AREA INFORMATION SERVER SOFTWARE:
   No guarantees or restrictions.  See the readme file for the full standard
   disclaimer.

   This is part of the X user-interface for the WAIS software.  Do with it
   as you please.

   Version 0.82
   Wed Apr 24 1991

   jonathan@Think.COM

*/

/* this file contains X specific code - it is an integral part of XWAIS */

#define _C_QCOMMANDS

#include "xwais.h"

static Boolean editting_new_question;

static Question helpquestion = NULL;
static Textbuff current_text;

long
GetLineFromPos(text, p)
char *text;
XawTextPosition p;
{
  Textbuff t;
  long i, lines;

  for(lines=0, i=0; (i < p) && (*text != 0); i++, text++)
    if(*text == '\n') lines++;

  return lines;
}

XawTextPosition
GetPosFromLine(text, line)
char *text;
long line;
{
  Textbuff t;
  long i;
  XawTextPosition pos;

  for(pos=0, i=0; (i < line) && (*text != 0); pos++, text++)
    if(*text == '\n') i++;

  return pos;
}

int get_selected_qsource(question)
Question question;
{
  int result;
  Widget list;

  list = question->window->Sources->ListWidget;

  if ((result = get_selected_item(list)) != NO_ITEM_SELECTED) {
    result+=question->window->Sources->offset;
    return result;
  }
  else 
    return question->CurrentSource;
}

int get_selected_qdoc(question)
Question question;
{
  int result;
  Widget list;

  list = question->window->RelevantDocuments->ListWidget;

  if ((result = get_selected_item(list)) != NO_ITEM_SELECTED) {
    result+=question->window->RelevantDocuments->offset;
    return result;
  }
  else 
    return question->CurrentRelDoc;
}

int get_selected_response(question)
Question question;
{
  int result;
  Widget list;

  list = question->window->ResultDocuments->ListWidget;

  if ((result = get_selected_item(list)) != NO_ITEM_SELECTED) {
    result+=question->window->ResultDocuments->offset;
    return result;
  }
  else 
    return question->CurrentResDoc;      
}

/* these are the commands used in the question widget */


/* ARGSUSED */
void
DoSearch(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  Arg args[5];
  Cardinal num_args;
  float top, shown;
  Question q;
  char message[255];

  double_click = FALSE;
  LastClicked = w;

  q = the_Question;

  /* update the info */

  strncpy(q->keywords, GetString(q->window->keywordwid), STRINGSIZE);

  SearchWais(q);

  RebuildListWidget(q->window->ResultDocuments, q->Result_Items);
}

/* ARGSUSED */
void CloseQuestionEdit(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  strncpy(the_Question->keywords,
	  GetString(the_Question->window->keywordwid),
	  STRINGSIZE);

  if(strcmp(the_Question->name, "New Question") == 0)
    SaveQuestion();
  else {
    WriteQuestion(app_resources.questionDirectory,
		  the_Question,
		  TRUE);
    exit(0);
  }
}


int get_selected_question()
{
  int result;

  if ((result = get_selected_item(questionwindow->ListWidget))
      != NO_ITEM_SELECTED)
    result+=questionwindow->offset;
  return result;
}

int get_question_response(questionwindow)
QuestionWindow questionwindow;
{
  int result;

  if ((result = get_selected_item(questionwindow->ResultDocuments->ListWidget))
      != NO_ITEM_SELECTED)
    result+=questionwindow->ResultDocuments->offset;
  return result;
}

/* ARGSUSED */
void
AddResponseToQuestion(w, closure, call_data)
Widget w;
caddr_t closure, call_data;
{
  int numdocs, document_number, i;
  Question q;
  DocList this, last;
  float top, shown;

  double_click = FALSE;
  LastClicked = w;

  q = the_Question;

  document_number = get_question_response(q->window);

  if(document_number == NO_ITEM_SELECTED) {
    PrintStatus("\nNo selected response.  Select one and try again.",
	   q->window->StatusWindow);
    return;
  }

  /* find and add document to question's relevant documents */

  last = findLast(q->RelevantDocuments);

  for(this = q->ResultDocuments, i = 0; i < document_number; i++)
    this = this->nextDoc;

  if(last != NULL) 
    last->nextDoc = makeDocList(this->thisDoc, NULL);
  else q->RelevantDocuments = makeDocList(this->thisDoc, NULL);

  if(q->Relevant_Items != NULL)
    freeItemList(q->Relevant_Items);

  q->Relevant_Items =
    buildDocumentItemList(q->RelevantDocuments, FALSE);

  q->numdocs = charlistlength(q->Relevant_Items);

  RebuildListWidget(q->window->RelevantDocuments, q->Relevant_Items);

  q->modified = TRUE;
}

/* ARGSUSED */

void
AddDocToQuestion(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  int i;
  int SelectedDoc;
  Question q;
  float top, shown;
  DocumentID docid;
  DocList dlist;

  q = the_Question;

  if ((SelectedDoc = get_selected_response(q)) == NO_ITEM_SELECTED) {
    PrintStatus("\nNo selected ResultDocument - select one and try again.",
	   q->window->StatusWindow);
    return;
  }

  docid = (DocumentID)s_malloc(sizeof(_DocumentID));
  docid->doc = (CRetDocument)s_malloc(sizeof(_CRetDocument));

  dlist = makeDocList(docid, NULL);
  
  /* need to get DocID too - that's not as easy. */

  docid->doc->headline = q->Result_Items[SelectedDoc];

  /* append it to the current sourcelist */
  
  if(q->RelevantDocuments != NULL) {
    DocList doc;

    for(doc = q->RelevantDocuments; doc->nextDoc != NULL; doc = doc->nextDoc);
    doc->nextDoc = dlist;
  }
  else
    q->RelevantDocuments = dlist;

  if (q->Relevant_Items != NULL) freeItemList(q->Relevant_Items);

  q->Relevant_Items = buildDocumentItemList(q->RelevantDocuments, FALSE);
  q->numdocs = charlistlength(q->Relevant_Items);

  RebuildListWidget(q->window->RelevantDocuments, q->Relevant_Items);
}

/* ARGSUSED */
void
DeleteQuestionDoc(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  int i;
  float shown;
  int SelectedDoc;
  Question q;
  DocList doc, last;

  q = the_Question;

  if((SelectedDoc = get_selected_qdoc(q)) == NO_ITEM_SELECTED) {
    double_click = FALSE;
    LastClicked = w;
    PrintStatus("\nNo Document selected.  Please select one and try again.",
		q->window->StatusWindow);
    return;
  }

  /* rip out the bugger */

  q->modified = TRUE;

  double_click = FALSE;
  LastClicked = NULL;
  if (SelectedDoc == 0)
    q->RelevantDocuments = q->RelevantDocuments->nextDoc;
  else {
    for (doc = q->RelevantDocuments, i = 0; i < SelectedDoc-1; i++) {
      doc = doc->nextDoc;
    }
    if(doc->nextDoc != NULL)
      doc->nextDoc = doc->nextDoc->nextDoc;
  }
  if(q->Relevant_Items != NULL) freeItemList(q->Relevant_Items);
  q->Relevant_Items = buildDocumentItemList(q->RelevantDocuments, FALSE);

  q->numdocs--;
  q->window->RelevantDocuments->offset = 0;

  RebuildListWidget(q->window->RelevantDocuments, q->Relevant_Items);
}

/* ARGSUSED */
void
AddSourceToQuestion(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  int i;
  Question q;
  float top, shown;
  SourceID sid;
  SourceList slist;

  q = the_Question;

  sid = (SourceID)s_malloc(sizeof(_SourceID));
  slist = makeSourceList(sid, NULL);
  
  sid->filename = s_strdup(XtName(w));

  /* append it to the current sourcelist */
  
  if(q->Sources != NULL) {
    SourceList source;

    /* check to see if it's already in the list */

    for(source = q->Sources; source != NULL; source = source->nextSource) {
      if(strcmp(source->thisSource->filename, sid->filename) == 0) {
	s_free(sid);
	s_free(slist);
	return;
      }
      if(source->nextSource == NULL) break;
    }
    source->nextSource = slist;
  }
  else
    q->Sources = slist;

  q->Source_Items = buildSourceItemList(q->Sources);
  q->numsources = charlistlength(q->Source_Items);

  RebuildListWidget(q->window->Sources, q->Source_Items);

  q->modified = TRUE;
}

/* ARGSUSED */
void
DeleteQuestionSource(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  int i;
  float shown;
  int SelectedSource;
  Question q;
  SourceList source, last;

  q = the_Question;

  if((SelectedSource = get_selected_qsource(q)) == NO_ITEM_SELECTED) {
    double_click = FALSE;
    LastClicked = w;
    PrintStatus("\nNo source selected.  Please select one and try again.",
		q->window->StatusWindow);
    return;
  }

  /* rip out the bugger */

  q->modified = TRUE;

  double_click = FALSE;
  LastClicked = NULL;
  if (SelectedSource == 0)
    q->Sources = q->Sources->nextSource;
  else {
    for (source = q->Sources, i = 0; i < SelectedSource-1; i++) {
      source = source->nextSource;
    }
    if(source->nextSource != NULL)
      source->nextSource = source->nextSource->nextSource;
  }
  q->Source_Items = buildSourceItemList(q->Sources);

  q->numsources--;
  q->window->Sources->offset = 0;

  RebuildListWidget(q->window->Sources, q->Source_Items);
}



/* ARGSUSED */
void
ViewResponse(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  Arg args[5];
  Cardinal num_args;
  static long request_length = 0;
  static int document_number;
  static long lines, size, count;
  WAISDocumentText *text;
  char *viewtext, message[255];
  Source source;
  int i;
  Question q;
  DocumentID doc;
  Textbuff textstruct;
  TextList thisText, a_tList;

  double_click = FALSE;
  LastClicked = w;

  q = the_Question;

  size = 0;

  document_number = get_selected_response(q);

  if(document_number == NO_ITEM_SELECTED) {
    PrintStatus("\nNo selected response.  Select one and try again.",
		q->window->StatusWindow);
    return;
  }

  if((doc = findDoc(q->ResultDocuments, document_number)) == NULL) {
    PrintStatus("\nUnable to find document.  This should not happen.",
		q->window->StatusWindow);
    return;
  }

  source = NULL;

  if(doc->doc != NULL)
    if(doc->doc->sourceID != NULL)
      if(doc->doc->sourceID->filename != NULL)
	source = findsource(doc->doc->sourceID->filename);

  if (source == NULL) {

    PrintStatus("\nCould not find Source for this document!",
		q->window->StatusWindow);
    return;
  }

  thisText = (TextList) s_malloc(sizeof(_TextList));
  thisText->thisText = textstruct = (Textbuff) s_malloc(sizeof(_Textbuff));
  thisText->nextText = NULL;

  if(allText != NULL)
    for(a_tList = allText; a_tList != NULL; a_tList = a_tList->nextText) {
      if(a_tList->nextText == NULL) {
	a_tList->nextText = thisText;
	break;
      }
    }
  else
    allText = thisText;

  if(ViewWaisDocument(q, source, doc, textstruct)) {

    textstruct->docid = doc;
    if (!strcmp(doc->doc->type, "GIF")) {
      ShowGIF(textstruct);
    }
    else if (!strcmp(doc->doc->type, "TIFF")) {
      ShowTIFF(textstruct);
    }
    else if (!strcmp(doc->doc->type, "WSRC")) {
      DoSource(textstruct);
    }
    else if (doc->doc->type[0] == 0 ||
	     !strcmp(doc->doc->type, "TEXT")) {
      textstruct->textwindow = MakeTextPopup(top, textstruct,
					     q->Result_Items[document_number]);
      num_args = 0;
      XtSetArg(args[num_args], XtNtype, XawAsciiString); num_args++;
      XtSetArg(args[num_args], XtNstring, textstruct->text); num_args++;
      XtSetValues(textstruct->textwindow, args, num_args);
      if (doc->doc->best > 0)
	XawTextSetInsertionPoint(textstruct->textwindow,
				 GetPosFromLine(textstruct->text, doc->doc->best));
      XawTextDisplay(textstruct->textwindow);
    }
    else do_other_thing(textstruct, doc->doc->type);
  }
}

Textbuff
findText(w)
Widget w;
{
  TextList a_tList;
  static Widget shell = NULL;

  if (w != NULL) 
    if((shell = XtParent(w)) != NULL)
      shell = XtParent(shell);
  if (shell != NULL) {
    for(a_tList = allText; a_tList != NULL; a_tList = a_tList->nextText)
      if(a_tList->thisText->shell != NULL)
	  if (a_tList->thisText->shell == shell)
	    return a_tList->thisText;
  }
  return NULL;
}


void
EndText(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  Textbuff t;

  t = findText(w);

  if(t != NULL) {
    XtPopdown(t->shell);
    if(t->text != NULL)
      s_free(t->text);
  }
}
static Widget helpwindow = NULL;

void EndHelp(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  XtPopdown(helpwindow);
}

void XwaisHelp(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  Widget textwindow, frame, button;
  Arg arglist[10];
  Cardinal num_args;
  static String items[] = {NULL};

  if (helpwindow == NULL) {
    num_args = 0;
    XtSetArg(arglist[num_args], XtNtitle, "X WAIS Help"); num_args++;
    XtSetArg(arglist[num_args], XtNiconName, "X WAIS Help"); num_args++;
    helpwindow = XtCreatePopupShell("textpopup", applicationShellWidgetClass,
				    XtParent(w), arglist, num_args);
    frame =
      XtCreateManagedWidget("helppopupform", formWidgetClass,
			    helpwindow, NULL, ZERO);
    num_args = 0;
    XtSetArg(arglist[num_args], XtNtype, XawAsciiFile); num_args++;
    XtSetArg(arglist[num_args], XtNstring, app_resources.helpFile); num_args++;
    XtSetArg(arglist[num_args], XtNeditType, XawtextRead); num_args++;
    textwindow =
      XtCreateManagedWidget("textWindow", asciiTextWidgetClass, frame, arglist, num_args);
    button = MakeCommandButton(frame, "tdone", EndHelp,
			       textwindow, NULL);
    SettIcon(helpwindow);
  }
  XtPopup(helpwindow, XtGrabNone);
}

#include <X11/Xaw/TextP.h>


XawTextPosition
findstring(text, string, casesensitive)
char *text, *string;
Boolean casesensitive;
{
  char *t, *t2, *t3;

  if (casesensitive) {
    for (t = text; *t != 0; t++) {
      if (*t == *string) {
	t2 = t;
	t3 = string;
	do {
	  t2++;
	  t3++;
	  if(*t3 == 0) return((XawTextPosition)(t-text));
	}
	while(*t2 == *t3);
      }
    }
    return -1;
  }
  else {
    for (t = text; *t != 0; t++) {
      if (tolower(*t) == tolower(*string)) {
	t2 = t;
	t3 = string;
	do {
	  t2++;
	  t3++;
	  if(*t3 == 0) return((XawTextPosition)(t-text));
	}
	while(tolower(*t2) == tolower(*t3));
      }
    }
    return -1;
  }
}

/* ARGSUSED */
Boolean
showKeyword(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  Question q;
  Textbuff t;
  static char msg[STRINGSIZE], str[STRINGSIZE], minstr[STRINGSIZE], *keys;
  Widget tw;
  XawTextPosition minpos, pos, pos2, offset;
  XawTextBlock text;
  int i, j, k;
  char c1, c2;

  q = the_Question;

  if((t = findText(w)) == NULL) {
    XwaisPrintf("couldn't find text.\n");
    return;
  }

  keys = q->keywords;
  tw = t->textwindow;

  minpos = 999999;
  minstr[0] = 0;

  sprintf(msg, "\nSearching for next keyword...");
  PrintStatus(msg, t->status);

  /* parse the keywords into individual words */
  for(j = 0, i = 0; i <= strlen(keys); i++) {
    str[j] = keys[i];
    if ((keys[i] == 0) || (keys[i] == ' ') || (keys[i] == '\n')) {
      str[j] = 0;
      j = 0;

      text.ptr = str;
      text.length = strlen(str);
      text.firstPos = 0;
      text.format = FMT8BIT;
      
      for(offset = XawTextGetInsertionPoint(tw), 
	  pos = findstring(t->text+offset, str, FALSE);
	  pos > 0;
	  offset=pos+1, 
	  pos = findstring(t->text+offset, str, FALSE)) {
	pos+=offset;
	c1 = t->text[pos-1];
	c2 = t->text[pos+text.length];
	if((isspace(c1) || ispunct(c1)) &&
	   (isspace(c2) || ispunct(c2))) {
	  if (pos < minpos) {
	    minpos = pos;
	    strcpy(minstr, str);
	    break;
	  }
	}
      }
    }
    else
      j++;
  }

  if (minpos == 999999) {
    sprintf( msg, "\nCould not find any more keywords.");
/*    XawTextSetInsertionPoint( tw, 0); */
    XawTextUnsetSelection(tw);
    PrintStatus(msg, t->status);
    return(FALSE);
  }
  else {
    XawTextSetInsertionPoint( tw, minpos + strlen(minstr));
    sprintf(msg, "\nSearching for next keyword...done");
    PrintStatus(msg, t->status);
    XawTextSetSelection( tw, minpos, minpos + strlen(minstr));
    return(TRUE);
  }
}

void
SaveText(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  Arg		args[5];
  Position	x, y;
  Dimension	width, height;
  Cardinal	n;
  Textbuff t;

  if((t = findText(w)) == NULL) {
    XwaisPrintf("couldn't find text.\n");
    return;
  }

  n = 0;
  XtSetArg(args[0], XtNwidth, &width); n++;
  XtSetArg(args[1], XtNheight, &height); n++;
  XtGetValues(t->textwindow, args, n);
  XtTranslateCoords(t->textwindow, (Position) (width / 2), (Position) (height / 2),
		    &x, &y);

  n = 0;
  XtSetArg(args[n], XtNx, MAX(x-150, 0));		n++;
  XtSetArg(args[n], XtNy, y);				n++;

  if(tsavepopup == NULL)
    tsavepopup = MakeTextSavePopup(top);
  
  XtSetValues(tsavepopup, args, n);

  XtPopup(tsavepopup, XtGrabExclusive);

  current_text = t;

  XtAddCallback(tsavebutton, XtNcallback, DoTSave, t);
}

void
SaveQuestion()
{
  Arg		args[5];
  Position	x, y;
  Dimension	width, height;
  Cardinal	n;

  n = 0;
  XtSetArg(args[0], XtNwidth, &width); n++;
  XtSetArg(args[1], XtNheight, &height); n++;
  XtGetValues(top, args, n);
  XtTranslateCoords(top, (Position) (width / 2), (Position) (height / 2),
		    &x, &y);

  n = 0;
  XtSetArg(args[n], XtNx, MAX(x-150, 0));		n++;
  XtSetArg(args[n], XtNy, y);				n++;

  if(savepopup == NULL)
    savepopup = MakeSavePopup(top);
  
  XtSetValues(savepopup, args, n);

  XtPopup(savepopup, XtGrabNone);

  XtAddCallback(savebutton, XtNcallback, DoSave, NULL);
}

void
DoSave(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  FILE *fp;
  char message[STRINGSIZE], filename[STRINGSIZE];

  XtPopdown(savepopup);

  strcpy(the_Question->name, GetString(savenamewid, STRINGSIZE));
  WriteQuestion(app_resources.questionDirectory,
		the_Question,
		TRUE);
  exit(0);
}

void
DontSave(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  exit(0);
}

void
DoTSave(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  FILE *fp;
  Textbuff t;
  char message[STRINGSIZE], filename[STRINGSIZE];

  XtPopdown(tsavepopup);

  t = current_text;

  strcpy(filename, GetString(tsavenamewid, STRINGSIZE));

  if (filename[0] != '/') {
    if(!strcmp(t->type, "WSRC"))
       sprintf(message, "%s%s", app_resources.userSourceDirectory, filename);
    else	
      sprintf(message, "%s%s", app_resources.documentDirectory, filename);
    strcpy(filename, message);
  }

  if((fp = fopen(filename, "w")) == NULL) {
    sprintf(message, "\nUnable to save %s.", filename);
    PrintStatus(message, the_Question->window->StatusWindow);
    return;
  }

  {
    char *text;
    long i;

    text = t->text;
    for (i = 0; i < t->size; i++) fputc(*text++, fp);
  }

  fclose(fp);
}

void
DontTSave(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  XtPopdown(tsavepopup);
}

void
setSourceMenu()
{
  SList s;
  Widget entry;

  if(sourcemenu) 
    XtDestroyWidget(sourcemenu);

  sourcemenu = XtCreatePopupShell("menu", simpleMenuWidgetClass, sourcebutton, 
				  NULL, ZERO);
    
  for (s = Sources; s != NULL; s = s->nextSource) {
    char * item = s->thisSource->name;
	
    entry = XtCreateManagedWidget(item, smeBSBObjectClass, sourcemenu,
				      NULL, ZERO);
    XtAddCallback(entry, XtNcallback, AddSourceToQuestion, NULL);
  }
}

void
addSection(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  int i;
  Question q;
  float top, shown;
  DocList dlist;
  DocumentID doc;
  XawTextPosition p1, p2;
  long l1, l2;
  Textbuff t;

  t = findText(w);
  
  XawTextGetSelectionPos(t->textwindow, &p1, &p2);

  if(p1 > 0 && p2 > 0) {
    /* find the line positions */
    l1 = GetLineFromPos(t->text, p1);
    l2 = GetLineFromPos(t->text, p2);

    q = the_Question;

    doc = copy_docid(t->docid);
    doc->start = l1;
    doc->end = l2;
    dlist = makeDocList(doc, NULL);
    /* append it to the current rellist */
  
    if(q->RelevantDocuments != NULL) {
      DocList doc;

      for(doc = q->RelevantDocuments; doc->nextDoc != NULL; doc = doc->nextDoc);
      doc->nextDoc = dlist;
    }
    else
      q->RelevantDocuments = dlist;

    if(q->Relevant_Items != NULL) freeItemList(q->Relevant_Items);
    q->Relevant_Items = buildDocumentItemList(q->RelevantDocuments, FALSE);
    q->numdocs = charlistlength(q->Relevant_Items);

    RebuildListWidget(q->window->RelevantDocuments, q->Relevant_Items);
  }
}

ShowTIFF(t)
Textbuff t;
{
  ShowGIF(t);
}

ShowGIF(t)
Textbuff t;
{
  char fname[STRINGSIZE], command[STRINGSIZE], *text, *viewer;
  FILE *fp;
  long i;


  sprintf(fname, "%s/wais-documents/%s",
	  getenv("HOME"), get_filename(t->docid->doc->headline));
  
  if((fp = fopen(fname, "w")) == NULL) {
    sprintf(command, "\nError opening file: %s.", fname);
    PrintStatus(command, the_Question->window->StatusWindow);
    return;
  }

  text = t->text;
  for (i = 0; i < t->size; i++) fputc(*text++, fp);
  fclose(fp);

  if((viewer = (char*)getenv ("XWAIS_IMAGE_VIEWER")) == NULL)
    viewer = "xloadimage";

  sprintf(command, "csh -c '%s %s;rm %s' &", viewer, fname, fname);
  system(command);
}
  
void PopupSource(source)
Source source;
{
  Arg arglist[10];
  Cardinal num_args;

  num_args = 0;
  XtSetArg(arglist[num_args], XtNtitle, source->name); num_args++;
  XtSetValues(sourcepopup, arglist, num_args);
  ReplaceText(snamewid, source->name);
  ReplaceText(serverwid,source->server);
  ReplaceText(servicewid, source->service);
  ReplaceText(dbwid, source->database);
  ReplaceText(costwid, source->cost);
  ReplaceText(unitwid, source->units);
  ReplaceText(maintainerwid, source->maintainer);
  ReplaceText(descwid, source->description);
  XtPopup(sourcepopup, XtGrabNone);
}

DoSource(t)
Textbuff t;
{
  char f[STRINGSIZE], message[STRINGSIZE];
  FILE *fp;

  sprintf(f, "/tmp/src%d", getpid());
  if((fp = fopen(f, "w")) == NULL) {
    sprintf(message, "\nError opening file: %s.", f);
    PrintStatus(message, the_Question->window->StatusWindow);
    return;
  }

  fprintf(fp, t->text);

  fclose(fp);
  if((fp = fopen(f, "r")) == NULL) {
    sprintf(message, "\nError opening file: %s.", f);
    PrintStatus(message, the_Question->window->StatusWindow);
    return;
  }

  memset(the_Source, 0, sizeof(_Source));

  ReadSource(the_Source, fp);
  fclose(fp);

  if (the_Source->name != NULL) s_free(the_Source->name);
  the_Source->name = s_strdup(get_filename(t->docid->doc->headline));

  unlink(f);

  PopupSource(the_Source);
}
  
void update_source_connections(s,d)
SList s, d;
{
  SList t1, t2;

  for(t1 = s; t1 != NULL; t1 = t1->nextSource) {
    for (t2 = d; t2 != NULL; t2 = t2->nextSource) {
      if (strcmp(t1->thisSource->server, t2->thisSource->server) == 0 &&
	  strcmp(t1->thisSource->service, t2->thisSource->service) == 0 &&
	  t1->thisSource->connection != NULL) {
	t2->thisSource->connection = t1->thisSource->connection;
	t2->thisSource->buffer_length = t1->thisSource->buffer_length;
	t2->thisSource->initp = t1->thisSource->initp;
	if (strcmp(t1->thisSource->name, "ReMoVe") != 0) {
	  s_free(t1->thisSource->name);
	  t1->thisSource->name = s_strdup("ReMoVe");
	}
      }
    }
    if (strcmp(t1->thisSource->name, "ReMoVe") != 0 &&
	t1->thisSource->connection != NULL) {
      close_connection_to_server(t1->thisSource->connection);
      for (t2 = t1->nextSource; t2 != NULL; t2 = t2->nextSource) {
	if (strcmp(t1->thisSource->server, t2->thisSource->server) == 0 &&
	    strcmp(t1->thisSource->service, t2->thisSource->service) == 0)
	  t2->thisSource->connection = NULL;
      }
    }
  }
}

void
DoSSave(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  FILE *fp;
  char name[STRINGSIZE];
  Source source;
  SList current_sources;

  source = the_Source;

  XtPopdown(sourcepopup);

  strcpy(name, GetString(snamewid));

  if(!((strlen(name) > 4) && 
       strstr(name, ".src") &&
       (!strcmp(".src", strstr(name, ".src")))))
    strcat(name, ".src");

  if(source->name != NULL) s_free(source->name);
  source->name = s_strdup(name);

  if (source->maintainer != NULL) s_free(source->maintainer);
  source->maintainer = s_strdup(GetString(maintainerwid));

  if (source->description != NULL) s_free(source->description);
  source->description = s_strdup(GetString(descwid));

  strncpy(source->server, GetString(serverwid), STRINGSIZE);
  strncpy(source->service, GetString(servicewid), STRINGSIZE);
  strncpy(source->database, GetString(dbwid), STRINGSIZE);
  strncpy(source->cost, GetString(costwid), STRINGSIZE);
  strncpy(source->units, GetString(unitwid), STRINGSIZE);

  WriteSource(app_resources.userSourceDirectory, source, TRUE);

  NumSources = 0;
  current_sources = Sources;
  Sources = NULL;

  ReadSourceDirectory(app_resources.userSourceDirectory, TRUE);
  if(app_resources.commonSourceDirectory[0] != 0)
    ReadSourceDirectory(app_resources.commonSourceDirectory, TRUE);

  update_source_connections(current_sources, Sources);

  FreeSources(current_sources);

  SortSources();
  Source_items = buildSItemList(Sources);

  setSourceMenu();
}

void
DontSSave(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  XtPopdown(sourcepopup);
}

do_other_thing(t, type)
Textbuff t;
char *type;
{
  Arg		args[5];
  Position	x, y;
  Dimension	width, height;
  Cardinal	n;
  char message[STRINGSIZE];

  if (type != NULL && type[0] != 0)
    sprintf(message,
	    "\nDocument is of type: %s, which is unknown. Using Save routine.",
	    type);
  else
    sprintf(message,
	    "\nDocument is of unknown type. Using Save routine.");

  PrintStatus(message, the_Question->window->StatusWindow);

  n = 0;
  XtSetArg(args[0], XtNwidth, &width); n++;
  XtSetArg(args[1], XtNheight, &height); n++;
  XtGetValues(the_Question->window->shell, args, n);
  XtTranslateCoords(the_Question->window->shell, (Position) (width / 2), (Position) (height / 2),
		    &x, &y);

  n = 0;
  XtSetArg(args[n], XtNx, MAX(x-150, 0));		n++;
  XtSetArg(args[n], XtNy, y);				n++;

  if(tsavepopup == NULL)
    tsavepopup = MakeTextSavePopup(top);
  
  XtSetValues(tsavepopup, args, n);

  XtPopup(tsavepopup, XtGrabExclusive);

  XtAddCallback(tsavebutton, XtNcallback, DoTSave, t);
}

void
ListSelect(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
  static int old_document_number = -1;
  int document_number;
  Question q;

  q = the_Question;

  document_number = get_selected_response(q);

  
  if(double_click && LastClicked == w &&
     document_number == old_document_number) {
	  ViewResponse(w, closure, call_data);
	  return;
  }

  old_document_number = document_number;
  double_click = TRUE;
  LastClicked = w;
}

