/* addresses.c */

#include "ml.h"

Menu address_file_menu[] = {
  { NULL, "add", NUL_TERM,
      address_add, NULL, 0, NULL, NULL, BTN_SELECTION },
  { NULL, "remove", NUL_TERM,
      address_remove, NULL, 0, NULL, NULL, BTN_NOSELECTION },
  { NULL, "modify", NUL_TERM,
      address_modify, NULL, 0, NULL, NULL, BTN_NOSELECTION },
  { NULL, "close_window", NUL_TERM,
      address_close_window, NULL, 0, NULL, NULL, BTN_ON },

};

Menu address_book_menu[] = {
  { NULL, "file_menu", NUL_TERM,
      NULL, address_file_menu, XtNumber(address_file_menu),
      NULL, NULL, BTN_ON },
  { NULL, "search", NUL_TERM,
      address_search, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "reset", NUL_TERM,
      address_reset, NULL, 0, NULL, NULL, BTN_ON },
  { NULL, "HELP", NUL_TERM,
      address_help, NULL, 0, NULL, NULL, BTN_ON },

};


#ifdef __STDC__
Address_Book_Info *new_address_book_info(void)
#else
Address_Book_Info *new_address_book_info()
#endif
{
  Address_Book_Info *address_book_info =
    (Address_Book_Info *) fs_get(sizeof(Address_Book_Info));

  address_book_info->name    = NULL;
  address_book_info->address = NULL;
  address_book_info->comment = NULL;
  address_book_info->groups  = NULL;
  address_book_info->next    = NULL;
  address_book_info->prev    = NULL;

  return(address_book_info);
}

#ifdef __STDC__
void free_address_book_info(Address_Book_Info *address_book_info)
#else
void free_address_book_info(address_book_info)
     Address_Book_Info *address_book_info;
#endif
{
  if(address_book_info != NULL) {
    if(address_book_info->name != NULL)
      fs_give((void **) &address_book_info->name);
    if(address_book_info->address != NULL)
      fs_give((void **) &address_book_info->address);
    if(address_book_info->comment != NULL)
      fs_give((void **) &address_book_info->comment);
    if(address_book_info->groups != NULL)
      fs_give((void **) &address_book_info->groups);
    fs_give((void **) &address_book_info);
  }
  return;
}

#ifdef __STDC__
void create_address_book_window(Tool w)
#else
void create_address_book_window(w)
     Tool w;
#endif
{
  Arg args[ARGLISTSIZE];
  int n = 0;
  XtTranslations translations;
  Address_Book *address_book;
  Tool form, menubar;

  if(session->address_book != NULL) {
    if(session->address_book->is_realized == TRUE)
      de_iconify(session->address_book->shell);
    else {
      XtPopup(session->address_book->shell, XtGrabNone);
      session->address_book->is_realized = TRUE;
    }
    return;
  }


  address_book = (Address_Book *) fs_get(sizeof(Address_Book));
  address_book->is_realized = FALSE;
  session->address_book = address_book;

  address_book->current = NULL;
  address_book->button_state = BTN_ON | BTN_NOSELECTION;
  XtSetArg (args[n], XmNdeleteResponse, XmDO_NOTHING);      n++; 
  address_book->shell = XtCreatePopupShell("address",topLevelShellWidgetClass,
					   session->shell, args, n);
  AddDestroyCallback (address_book->shell);
  n = 0;
  setup_editres(address_book->shell);

  if(addr_icon != (Pixmap) None)
    XtVaSetValues(address_book->shell,
		  XmNiconPixmap,addr_icon,
		  NULL);

  form = XmCreateForm(address_book->shell, "form", args, n );         n = 0;

  XtSetArg(args[n], XmNtopAttachment,   XmATTACH_FORM);               n ++;
  XtSetArg(args[n], XmNleftAttachment,  XmATTACH_FORM);               n ++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);               n ++;
  menubar = XmCreateMenuBar(form, "menubar", args, n);                n = 0;
  XtManageChild(menubar);

  create_buttons(NULL, menubar, address_book_menu, 
		 XtNumber(address_book_menu),
		 address_book->button_state, 
		 (XtPointer) address_book,
		 ROOTMENULEVEL);

  address_book->name =
    create_text_field(form, menubar, 
		      "name", NULL, 0, NULL, NULL);

  address_book->address =
    create_text_field(form, address_book->name, 
		      "addr", NULL, 0, NULL, NULL);

  address_book->groups =
    create_text_field(form, address_book->address, 
		      "grps", NULL, 0, NULL, NULL);

  address_book->comment =
    create_text_field(form, address_book->groups,
		      "cmmt", NULL, 0, NULL, NULL);

  XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC);             n ++;
  XtSetArg(args[n], XmNlistSizePolicy,         XmCONSTANT);           n ++;
  XtSetArg(args[n], XmNselectionPolicy,        XmSINGLE_SELECT);      n ++;
  address_book->list = XmCreateScrolledList(form,"list",args,n);      n = 0;

  XtAddCallback(address_book->list, XmNsingleSelectionCallback, 
		(XtCallbackProc) address_book_select, address_book);
  XtAddCallback(address_book->list, XmNdefaultActionCallback, 
		(XtCallbackProc) address_book_select, address_book);

  translations = XtParseTranslationTable(GLOBAL_addresses_pop_translations);
  XtOverrideTranslations(address_book->list, translations);


  XtSetArg(args[n], XmNtopAttachment,          XmATTACH_WIDGET);       n ++;
  XtSetArg(args[n], XmNtopWidget,              address_book->comment); n ++;
  XtSetArg(args[n], XmNleftAttachment,         XmATTACH_FORM);         n ++;
  XtSetArg(args[n], XmNrightAttachment,        XmATTACH_POSITION);     n ++;
  XtSetArg(args[n], XmNrightPosition,          50);                    n ++;
  XtSetArg(args[n], XmNbottomAttachment,       XmATTACH_FORM);         n ++;

  XtSetValues(XtParent(address_book->list), args, n);                  n = 0;

  XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC);              n ++;
  XtSetArg(args[n], XmNlistSizePolicy,         XmCONSTANT);            n ++;
  XtSetArg(args[n], XmNselectionPolicy,        XmSINGLE_SELECT);       n ++;
  address_book->search_list = 
    XmCreateScrolledList(form,"slist",args,n);                 n = 0;

  XtAddCallback(address_book->search_list, XmNsingleSelectionCallback, 
		(XtCallbackProc) address_book_select, address_book);
  XtAddCallback(address_book->search_list, XmNdefaultActionCallback, 
		(XtCallbackProc) address_book_select, address_book);

  translations = XtParseTranslationTable(GLOBAL_addresses_pop_translations);
  XtOverrideTranslations(address_book->search_list, translations);

  XtSetArg(args[n], XmNtopAttachment,          XmATTACH_WIDGET);       n ++;
  XtSetArg(args[n], XmNtopWidget,              address_book->comment); n ++;
  XtSetArg(args[n], XmNrightAttachment,        XmATTACH_FORM);         n ++;
  XtSetArg(args[n], XmNleftAttachment,         XmATTACH_POSITION);     n ++;
  XtSetArg(args[n], XmNleftPosition,           50);                    n ++;
  XtSetArg(args[n], XmNbottomAttachment,       XmATTACH_FORM);         n ++;

  XtSetValues(XtParent(address_book->search_list), args, n);           n = 0;

  XtAddCallback(address_book->shell, XmNpopdownCallback, 
		(XtCallbackProc) address_book_popdown, address_book);

  XtAddCallback(address_book->shell, XmNdestroyCallback,
		(XtCallbackProc) address_book_destroy, address_book);

  address_sort(address_book);
  stuff_address_book(address_book);

  XtManageChild(address_book->search_list);
  XtManageChild(address_book->list); 
  XtManageChild(form);
  XtManageChild(address_book->shell);
  XtPopup(address_book->shell,XtGrabNone); 
  address_book->is_realized = TRUE;
  return;
}

#ifdef __STDC__
void address_close_window(Tool w,Address_Book *address_book,XtPointer xp)
#else
void address_close_window(w,address_book,xp)
     Tool w;
     Address_Book *address_book;
     XtPointer xp;
#endif
{
  XtPopdown(address_book->shell);
  address_book->is_realized = FALSE;
  return;
}

#ifdef __STDC__
void address_book_popdown(Tool w,Address_Book *address_book,XtPointer xp)
#else
void address_book_popdown(w,address_book,xp)
     Tool w;
     Address_Book *address_book;
     XtPointer xp;
#endif
{
  address_book->is_realized = FALSE;
  return;
}

#ifdef __STDC__
void address_book_destroy(Tool w,Address_Book *address_book,XtPointer xp)
#else
void address_book_destroy(w,address_book,xp)
     Tool w;
     Address_Book *address_book;
     XtPointer xp;
#endif
{
  XtDestroyWidget(address_book->shell);
  fs_give((void **) &session->address_book);
  session->address_book = NULL;
  return;
}

#ifdef __STDC__
void address_book_select(Tool w, Address_Book *address_book,
			 XmListCallbackStruct *cb)
#else
void address_book_select(w,address_book,cb)
     Tool w;
     Address_Book *address_book;
     XmListCallbackStruct *cb;
#endif
{
  unsigned char *str;
  Address_Book_Info *info;
  Tool other;

  if(w == address_book->list)
    other = address_book->search_list;
  else
    other = address_book->list;

  XmListDeselectAllItems(other);

  XmStringGetLtoR(cb->item,XmSTRING_DEFAULT_CHARSET,(char **)&str);

  if((address_book->current != NULL) && 
     (ml_strcoll(str,address_book->current->name) == STRMATCH) &&
     (address_book->current_list == w)) { 
    address_book_context_switch(address_book,address_book->current,NULL);
    address_book->button_state |= BTN_NOSELECTION;
    address_book->button_state &= ~BTN_SELECTION;
  }
  else {
    for(info = session->addresses; info ; info = info->prev ) {
      if((ml_strcoll(info->name,str)) == STRMATCH) {
	address_book_context_switch(address_book,address_book->current, info);
	address_book->button_state |= BTN_SELECTION;
	address_book->button_state &= ~BTN_NOSELECTION;
      }
    }
  }

  fs_give((void **) &str);
  address_book->current_list = w;
  check_buttons(address_book_menu, XtNumber(address_book_menu), 
		NULL, address_book->button_state);
  return;
}


#ifdef __STDC__
void address_book_context_switch(Address_Book *address_book,
				 Address_Book_Info *old,
				 Address_Book_Info *new)
#else
void address_book_context_switch(address_book,old,new)
     Address_Book *address_book;
     Address_Book_Info *old; 
     Address_Book_Info *new;
#endif
{
  
  if(old != NULL) {
    if(old->name != NULL) 
      fs_give((void **) &old->name);
    old->name = GetUnTextField(address_book->name);
    if(old->address != NULL)
      fs_give((void **) &old->address);
    old->address = GetUnTextField(address_book->address);
    if(old->groups != NULL)
      fs_give((void **) &old->groups);
    old->groups = GetUnTextField(address_book->groups);
    if(old->comment != NULL)
      fs_give((void **) &old->comment);
    old->comment = GetUnTextField(address_book->comment);
  }
  if(new != NULL) {
    TextSetString(address_book->name,    
		  (new->name != NULL)    
		  ? new->name    
		  : (unsigned char *) EMPTYSTR);
    TextSetString(address_book->address,
		  (new->address != NULL) 
		  ? new->address 
		  : (unsigned char *) EMPTYSTR);
    TextSetString(address_book->groups,
		  (new->groups != NULL) 
		  ? new->groups 
		  : (unsigned char *) EMPTYSTR);
    TextSetString(address_book->comment,
		  (new->comment != NULL) 
		  ? new->comment 
		  : (unsigned char *) EMPTYSTR);
    
  }
  else {
    TextSetString(address_book->name,   (unsigned char *) EMPTYSTR);
    TextSetString(address_book->address,(unsigned char *) EMPTYSTR);
    TextSetString(address_book->groups, (unsigned char *) EMPTYSTR);
    TextSetString(address_book->comment,(unsigned char *) EMPTYSTR);
  }

  address_book->current = new;
  return;
}

#ifdef __STDC__
void stuff_address_book(Address_Book *address_book)
#else
void stuff_address_book(address_book)
     Address_Book *address_book;
#endif
{
  Address_Book_Info *info;
  XmString xstr;
  
  for(info = session->addresses; info ; info = info->prev) {
    xstr = XmStringCreateSimple((char *) info->name);
    XmListAddItemUnselected(address_book->list,xstr,0);
    XmStringFree(xstr);
  }
  return;
}

#ifdef __STDC__
void address_search(Tool w, Address_Book *address_book, XtPointer xp)
#else
void address_search(w,address_book,xp)
     Tool w;
     Address_Book *address_book;
     XtPointer xp;
#endif
{
  Address_Book_Info *info;
  XmString xstr;
  Boolean found = FALSE;

  /* Search on the current window contents */

  unsigned char *name     = GetUnTextField(address_book->name);
  unsigned char *address  = GetUnTextField(address_book->address);
  unsigned char *groups   = GetUnTextField(address_book->groups);
  unsigned char *comment  = GetUnTextField(address_book->comment);

  /* Nothing to search for. */

  if((*name == NUL_TERM) && (*address == NUL_TERM) 
     && (*groups == NUL_TERM) && (*comment == NUL_TERM))
    return;

  /* Let 'em know we're busy. */

  push_cursor(WATCH_CURSOR);

  address_book->current = NULL;
  XmListDeleteAllItems(address_book->search_list);

  /* 
   * Find a match on any field in our internal list, and
   * put it in the search list widget
   */

  for(info = session->addresses; info; info = info->prev) {
    if((address_searchit(info->name,name))
       || (address_searchit(info->address,address))
       || (address_searchit(info->groups,groups))
       || (address_searchit(info->comment,comment))) {
      found = TRUE;
      xstr = XmStringCreateSimple((char *) info->name);
      XmListAddItemUnselected(address_book->search_list,xstr,0);
      XmStringFree(xstr);
    }
  }

  /* 
   * Popup the first one in the list. This will call our selection
   * callback before it's done, so we don't have to tweak anything.
   */

  if(found) {
    XmListSelectPos(address_book->search_list,1,TRUE);
  }

  pop_cursor();
  return;
}


/*
 * This isn't the best search algorithm, but it doesn't have to be.
 * We're looking for any substring match, case insensitive.
 * Empty strings or null strings don't count.
 */

/* i18n-broken */

#ifdef __STDC__
Boolean address_searchit(unsigned char *str,unsigned char *pat)
#else
Boolean address_searchit(str,pat)
     unsigned char *str;
     unsigned char *pat;
#endif
{
  register unsigned char *ptr;

  if((str == NULL) || (pat == NULL) || (*pat == NUL_TERM))
    return(FALSE);
  for(ptr = str; *ptr; ptr ++ ) 
    if(strncasecmp((char *) ptr,(char *) pat,strlen((char *)pat)) == STRMATCH)
      return(TRUE);
  return(FALSE);
}

#ifdef __STDC__
void address_remove(Tool w, Address_Book *address_book, XtPointer xp)
#else
void address_remove(w,address_book,xp)
     Tool w;
     Address_Book *address_book;
     XtPointer xp;
#endif
{
  Address_Book_Info *info = address_book->current;

  if(! info)
    return;

  if(preferences.confirmDestroy == TRUE) 
    if((ml_confirm(address_book->shell,
		  MLGetLocalized(XtNmsgDestroyAddress,
				 MsgDestroyAddress), 
		   CONFIRM_OK_CANCEL)) == FALSE)
      return;

  if(info->prev)
    info->prev->next = info->next;
  if(info->next)
    info->next->prev = info->prev;
  else
    session->addresses = info->prev;

  if(address_book->current == info)
    address_book->current = NULL;

  free_address_book_info(info);
  
  push_cursor(WATCH_CURSOR);
  save_defaults();
  address_reset(w,address_book, NULL);
  pop_cursor();
  return;
}

#ifdef __STDC__
void address_add(Tool w, Address_Book *address_book, XtPointer xp)
#else
void address_add(w,address_book,xp)
     Tool w;
     Address_Book *address_book;
     XtPointer xp;
#endif
{
  Address_Book_Info *info;
  Address_Book_Info *curr;

  info = new_address_book_info();

  info->name = GetUnTextField(address_book->name);

  if((info->name == NULL) || (*info->name == NUL_TERM)) {
    free_address_book_info(info);
    return;
  }
    
  for(curr = session->addresses; curr; curr = curr->prev) {
    if(ml_strcoll(curr->name,info->name) == STRMATCH) {
      free_address_book_info(info);
      return;
    }
  }

  push_cursor(WATCH_CURSOR);
  info->address = GetUnTextField(address_book->address);
  info->groups  = GetUnTextField(address_book->groups);
  info->comment = GetUnTextField(address_book->comment);
  info->next = NULL;
  info->prev = session->addresses;
  if(info->prev)
    info->prev->next = info;
  session->addresses = info;
  address_sort(address_book);
  save_defaults();
  address_reset(w,address_book, NULL);
  pop_cursor();
  return;
}

#ifdef __STDC__
void address_modify(Tool w, Address_Book *address_book, XtPointer xp)
#else
void address_modify(w,address_book,xp)
     Tool w;
     Address_Book *address_book;
     XtPointer xp;
#endif
{
  Address_Book_Info *info;
  unsigned char *name = GetUnTextField(address_book->name);

  info = address_book->current;

  if((! info) || (*name == NUL_TERM))
    return;

  push_cursor(WATCH_CURSOR);

  if(info->name)
    fs_give((void **) &info->name);
  info->name = name;

  if(info->address)
    fs_give((void **) &info->address);
  info->address = GetUnTextField(address_book->address);

  if(info->groups)
    fs_give((void **) &info->groups);
  info->groups = GetUnTextField(address_book->groups);

  if(info->comment)
    fs_give((void **) &info->comment);
  info->comment = GetUnTextField(address_book->comment);

  address_sort(address_book);
  save_defaults();
  address_reset(w,address_book, NULL);
  pop_cursor();
  return;
}

#ifdef __STDC__
void address_reset(Tool w, Address_Book *address_book, XtPointer xp)
#else
void address_reset(w,address_book,xp)
     Tool w;
     Address_Book *address_book;
     XtPointer xp;
#endif
{
  if(address_book == NULL)
    return;

  XmListDeleteAllItems(address_book->search_list);
  XmListDeselectAllItems(address_book->search_list);
  XmListDeselectAllItems(address_book->list);
  XmListDeleteAllItems(address_book->list);
  address_book->button_state |= BTN_NOSELECTION;
  address_book->button_state &= ~BTN_SELECTION;

  address_book_context_switch(address_book,address_book->current, NULL);
  stuff_address_book(address_book);
  check_buttons(address_book_menu, XtNumber(address_book_menu),
		NULL, address_book->button_state);
  return;
}

#ifdef __STDC__
int address_compare(const void *adr1, const void *adr2)
#else
int address_compare(adr1,adr2)
     const void *adr1;
     const void *adr2;
#endif
{
  Address_Book_Info **a1 = (Address_Book_Info **) adr1;
  Address_Book_Info **a2 = (Address_Book_Info **) adr2;
  return(ml_strcoll((*(a1))->name,(*(a2))->name));
}


#ifdef __STDC__
void address_sort(Address_Book *address_book)
#else
void address_sort(address_book)
     Address_Book *address_book;
#endif
{
  Address_Book_Info **sort;
  Address_Book_Info *info;
  int n = 0;
  int total = 0;

  if(session->addresses == NULL)
    return;

  for(info = session->addresses; info; info = info->prev)
    total ++;

  if(total < 2)
    return;

  sort = (Address_Book_Info **) fs_get(total * sizeof(Address_Book_Info *));

  for(info = session->addresses; info; info = info->prev) {
    sort[n] = info; 
    n ++;
  }

  qsort((char *) sort,total,sizeof(Address_Book_Info **),address_compare);

  for(n = 0; n < total; n ++) {
    info = sort[n];
    if(n == 0) {
      session->addresses = info;
      info->next = NULL;
      info->prev = sort[n + 1];
    }
    else {
      info->next = sort[n - 1];
      if(n == (total - 1))
	info->prev = NULL;
      else
	info->prev = sort[n + 1];
    }
  }
  fs_give((void **) &sort);
  return;
}


#ifdef __STDC__
void address_help(Tool w, Address_Book *address_book, XtPointer xp)
#else
void address_help(w,address_book,xp)
     Tool w;
     Address_Book *address_book;
     XtPointer xp;
#endif
{
  help(address_book->shell, ADDRESSBOOKHELPFILE);
  return;
}


#ifdef __STDC__
ADDRESS *text_to_address(char *text,char *host)
#else
ADDRESS *text_to_address(text,host)
     char *text;
     char *host;
#endif
{
  ADDRESS *address = NULL;

  if(host == NULL)
    host = EMPTYSTR;

  if((text != NULL) && (*text != NUL_TERM))
    rfc822_parse_adrlist(&address,text,host);
  return(address);
}

#ifdef __STDC__
ADDRESS *copy_address(ADDRESS *src_address)
#else
ADDRESS *copy_address(src_address)
     ADDRESS *src_address;
#endif
{
  ADDRESS *new_address = (ADDRESS*) NULL;
  
  new_address = mail_newaddr();
  
  if ((new_address != NULL) && (src_address != NULL)) {
    
    new_address->personal   = 
      ((src_address->personal) ? cpystr(src_address->personal) : NULL);
    new_address->adl        = 
      ((src_address->adl) ? cpystr(src_address->adl) : NULL);
    new_address->mailbox    = 
      ((src_address->mailbox) ? cpystr(src_address->mailbox) : NULL);
    new_address->host       = 
      ((src_address->host) ? cpystr(src_address->host) : NULL );
    new_address->error      = 
      ((src_address->error) ? cpystr(src_address->error) : NULL);
    
    if (src_address->next)
      new_address->next = copy_address( src_address->next );
  }
  
  return(new_address);
}


#ifdef __STDC__
void local_make_addr_str(ADDRESS *adr, char *obuf)
#else
void local_make_addr_str(adr, obuf)
     ADDRESS *adr;
     char *obuf;
#endif
{
  if ((!adr) || (adr->mailbox == NULL)) {
    sprintf(obuf, SPACESTR);
    return;
  }

  if ((adr->personal != NULL) && (adr->host != NULL))
    sprintf(obuf, "\"%s\" <%s@%s>", adr->personal, adr->mailbox, adr->host);
  else {
    if(adr->host != NULL)
      sprintf(obuf, "%s@%s", adr->mailbox, adr->host);
    else
      sprintf(obuf,"%s",adr->mailbox);
  }
  return;
}



#ifdef __STDC__
int save_address_book(FILE *fp)
#else
int save_address_book(fp)
     FILE *fp;
#endif
{
  Address_Book_Info *info;

  if(session->addresses == NULL)
    return(0);

  fprintf(fp,"\n%s\n",BEGIN_ADDRESS_STR);
  for(info = session->addresses; info ; info = info->prev) {
    fprintf(fp,"*%s\n",(info->name != NULL)    
	    ? (char *) info->name    
	    : EMPTYSTR); 
    fprintf(fp,"%s\n",(info->address != NULL) 
	    ? (char *) info->address 
	    : EMPTYSTR); 
    fprintf(fp,"%s\n",(info->groups != NULL) 
	    ? (char *) info->groups 
	    : EMPTYSTR); 
    fprintf(fp,"%s\n",(info->comment != NULL) 
	    ? (char *) info->comment 
	    : EMPTYSTR); 
  }
  fprintf(fp,"%s\n",END_ADDRESS_STR);
  return(0);
}


#ifdef __STDC__
int load_address_book(FILE *fp)
#else
int load_address_book(fp)
     FILE *fp;
#endif
{
  char buffer[FILEBUFFLEN];
  Boolean new_style = FALSE;
  Address_Book_Info *info;
  char *ptr;
  while((fgets(buffer,sizeof(buffer),fp)) != NULL) {
    buffer[strlen(buffer)-1] = '\0';

    if((strcmp(buffer,END_ADDRESS_STR)) == STRMATCH)
      return(0);
    
    info = new_address_book_info();

    ptr = buffer;
    if(*ptr == '*') {
      ptr ++;
      new_style = TRUE;
    }

    info->name = (unsigned char *) cpystr(ptr);
    

    if(fgets(buffer,sizeof(buffer),fp)) {
      buffer[strlen(buffer)-1] = '\0';
      info->address = (unsigned char *) cpystr(buffer);
    }
    else
      info->address = (unsigned char *) cpystr(EMPTYSTR);

    if(new_style == TRUE) {
      if(fgets(buffer,sizeof(buffer),fp)) {
	buffer[strlen(buffer)-1] = '\0';
	info->groups  = (unsigned char *) cpystr(buffer);
      }
      else
	info->groups = (unsigned char *) cpystr(EMPTYSTR);
    }

    if(fgets(buffer,sizeof(buffer),fp)) {
      buffer[strlen(buffer)-1] = '\0';
      info->comment = (unsigned char *) cpystr(buffer);
    }
    else
      info->comment = (unsigned char *) cpystr(EMPTYSTR);

    if(session->addresses == NULL)
      session->addresses = info;
    else {
      info->prev = session->addresses;
      session->addresses->next = info;
      session->addresses = info;
    }
  }
  return(0);
}

#ifdef __STDC__
void addresses_pop(Widget w, XtPointer xp)
#else
void addresses_pop(w,xp)
     Widget w;
     XtPointer xp;
#endif
{
  address_close_window(w,session->address_book,NULL);
  return;
}


syntax highlighted by Code2HTML, v. 0.9.1