/* -*- mode: C; mode: fold; -*- */
/*
 This file is part of SLRN.

 Copyright (c) 1994, 1999 John E. Davis <davis@space.mit.edu>

 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the Free
 Software Foundation; either version 2 of the License, or (at your option)
 any later version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along
 with this program; if not, write to the Free Software Foundation, Inc., 675
 Mass Ave, Cambridge, MA 02139, USA. 
*/
#include "config.h"
#include "slrnfeat.h"

/*{{{ system include files */

#include <stdio.h>
#include <string.h>
#include <time.h>


#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif

#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif

#include <ctype.h>
#include <slang.h>
#include "jdmacros.h"

#include "slrn.h"
#include "group.h"
#include "server.h"
#include "art.h"
#include "misc.h"
#include "post.h"
/* #include "clientlib.h" */
#include "startup.h"
#include "hash.h" 
#include "score.h"
#include "menu.h"
#include "util.h"
#include "xover.h"
#include "chmap.h"
#include "print.h"

/*}}}*/

int Slrn_Art_Hide_Quote_Level = 0;
int Slrn_Wrap_Mode = 3;
int Slrn_Wrap_Method = 0;

static char *Super_Cite_Regexp = "^[^A-Za-z0-9]*\"\\([-_a-zA-Z/]+\\)\" == .+";

static void hide_article_lines (Slrn_Article_Type *a, unsigned int mask) /*{{{*/
{
   Slrn_Article_Line_Type *l;

   if (a == NULL)
     return;
   
   a->needs_sync = 1;
   l = a->lines;

   while (l != NULL)
     {
	if (l->flags & mask)
	  l->flags |= HIDDEN_LINE;

	l = l->next;
     }
}

/*}}}*/

static void unhide_article_lines (Slrn_Article_Type *a, unsigned int mask) /*{{{*/
{
   Slrn_Article_Line_Type *l;

   if (a == NULL)
     return;

   a->needs_sync = 1;
   l = a->lines;

   while (l != NULL)
     {
	if (l->flags & mask)
	  l->flags &= ~HIDDEN_LINE;

	l = l->next;
     }
}

/*}}}*/

/* The function that set the needs_sync flag article line number start with _ 
 */

int _slrn_art_unhide_quotes (Slrn_Article_Type *a) /*{{{*/
{
   if (a == NULL)
     return -1;

   unhide_article_lines (a, QUOTE_LINE);
   a->quotes_hidden = 0;
   return 0;
}

/*}}}*/



int _slrn_art_hide_quotes (Slrn_Article_Type *a, int level) /*{{{*/
{
   Slrn_Article_Line_Type *l, *last;
   
   if (a == NULL)
     return -1;

   _slrn_art_unhide_quotes (a);
   
   a->needs_sync = 1;

   if (level == -1)
     level = Slrn_Art_Hide_Quote_Level;
   else 
     Slrn_Art_Hide_Quote_Level = level;

   l = a->lines;
   last = NULL;

   while (l != NULL)
     {
	if (l->flags & QUOTE_LINE)
	  {
	     if (level > 0)
	       {
		  if (QUOTE_LEVEL(l->flags) >= (unsigned int) level)
		    l->flags |= HIDDEN_LINE;
	       }
	     else if (last != NULL)
	       l->flags |= HIDDEN_LINE;

	     last = l;
	  }
	else last = NULL;
	l = l->next;
     }
   a->quotes_hidden = 1;
   return 0;
}

/*}}}*/


#if SLRN_HAS_SPOILERS
void slrn_art_mark_spoilers (Slrn_Article_Type *a) /*{{{*/
{
   Slrn_Article_Line_Type *l;
   int spoiler;
   
   if (Slrn_Spoiler_Char == 0)
     return;
   
   if (a == NULL)
     return;

   l = a->lines;
   spoiler = 0;
   /* skip header */
   while ((l != NULL) && (l->flags & HEADER_LINE))
     l = l->next;
   
   while (l != NULL)
     {
	if ((l->buf[0] == 12) && (l->buf[1] == 0))
	  {
	     spoiler = 1;
	  }
	else if (spoiler)
	  {
	     l->flags |= SPOILER_LINE;
	  }
	l = l->next;
     }
}

/*}}}*/
#endif

static int try_supercite (Slrn_Article_Line_Type *l) /*{{{*/
{
   Slrn_Article_Line_Type *last, *lsave;
   static unsigned char compiled_pattern_buf[256];
   static SLRegexp_Type re;
   unsigned char *b;
   int count;
   char name[32];
   unsigned int len;
   int ret;

   re.pat = (unsigned char *) Super_Cite_Regexp;
   re.buf = compiled_pattern_buf;
   re.case_sensitive = 1;
   re.buf_len = sizeof (compiled_pattern_buf);
   
   /* skip header --- I should look for Xnewsreader: gnus */
   while ((l != NULL) && (*l->buf != 0)) l = l->next;
   
   if ((*compiled_pattern_buf == 0) && SLang_regexp_compile (&re))
     return -1;
   
   /* look at the first 15 lines on first attempt.
    * After that, scan the whole buffer looking for more citations */
   count = 15;
   lsave = l;
   ret = -1;
   while (1)
     {
	while (count && (l != NULL))
	  {
	     if ((l->flags & QUOTE_LINE) == 0)
	       {
		  if (NULL != slrn_regexp_match (&re, l->buf))
		    {
		       l->flags |= QUOTE_LINE;
		       break;
		    }
	       }
	     l = l->next;
	     count--;
	  }
	
	if ((l == NULL) || (count == 0)) return ret;
	
	/* Now find out what is used for citing. */
	b = (unsigned char *) l->buf + re.beg_matches[1];
	len = re.end_matches[1];
	if (len > sizeof (name) - 2) return ret;
	
	ret = 0;
	strncpy (name, (char *) b, len); name[len] = 0;
	/* strcat (name, ">");
	 len++; */
	
	while (l != NULL)
	  {
	     unsigned char ch;
	     
	     b = (unsigned char *) l->buf;
	     last = l;
	     l = l->next;
	     if (last->flags & QUOTE_LINE) continue;
	     
	     b = (unsigned char *) slrn_skip_whitespace ((char *) b);

	     if (!strncmp ((char *) b, name, len)
		 && (((ch = b[len] | 0x20) < 'a')
		     || (ch > 'z')))
	       {
		  last->flags |= QUOTE_LINE;
		  
		  while (l != NULL)
		    {
		       b = (unsigned char *) slrn_skip_whitespace (l->buf);
		       if (strncmp ((char *) b, name, len)
			   || (((ch = b[len] | 0x20) >= 'a')
			       && (ch <= 'z')))
			 break;
		       l->flags |= QUOTE_LINE;
		       l = l->next;
		    }
	       }
	  }
	count = -1;
	l = lsave;
     }
}

/*}}}*/

static unsigned char *is_quote_line (unsigned char *b, unsigned int len) /*{{{*/
{
   SLRegexp_Type **r;

   r = Slrn_Ignore_Quote_Regexp;

   while (*r != NULL)
     {
	SLRegexp_Type *re;

	re = *r++;
	if ((re->min_length > len) 
	    || (b != SLang_regexp_match (b, len, re)))
	  continue;
	
	return b + re->end_matches[0];
     }
   return NULL;
}

/*}}}*/


void slrn_art_mark_quotes (Slrn_Article_Type *a) /*{{{*/
{
   Slrn_Article_Line_Type *l;
   unsigned char *b;
   
   if (a == NULL)
     return;

   if (0 == try_supercite (a->lines))
     {
	/* return; */
     }
   
   if (Slrn_Ignore_Quote_Regexp[0] == NULL) return;
   
   /* skip header */
   l = a->lines;
   while ((l != NULL) && (l->flags == HEADER_LINE))
     l = l->next;

   while (l != NULL)
     {
	int level;
	b = (unsigned char *) l->buf;

	if (NULL == (b = is_quote_line (b, strlen ((char *) b))))
	  {
	     l = l->next;
	     continue;
	  }
	l->flags |= QUOTE_LINE;
	level = 1;
	while ((level < MAX_QUOTE_LEVELS)
	       && (NULL != (b = is_quote_line (b, strlen ((char *)b)))))
	  level++;

	l->flags |= ((level-1) << QUOTE_LEVEL_SHIFT);
	l = l->next;
     }
   a->is_modified = 1;
}

/*}}}*/

void slrn_art_mark_signature (Slrn_Article_Type *a) /*{{{*/
{
   Slrn_Article_Line_Type *l;
   int nmax = 10;
   
   if (a == NULL)
     return;
   
   l = a->lines;
   if (l == NULL) return;
   /* go to end of article */
   while (l->next != NULL) l = l->next;
   
   /* skip back untill "-- " seen.  Assume that it is not more than
    * 10 lines long.
    */
   
   while ((l != NULL) && nmax--
	  && ((*l->buf != '-')
	      || strcmp (l->buf, "-- ")))
     l = l->prev;
   
   if (nmax == -1) return;
   
   while (l != NULL)
     {
        l->flags |= SIGNATURE_LINE;
        l->flags &= ~(
		      QUOTE_LINE  /* if in a signature, not a quote */
#if SLRN_HAS_SPOILERS
		      | SPOILER_LINE     /* not a spoiler */
#endif
		      );
	l = l->next;
     }
}

/*}}}*/

/* The input line is assumed to be the first wrapped portion of a line.  For
 * example, if a series of lines denoted as A/B is wrapped: A0/A1/A2/B0/B1,
 * then to unwrap A, A1 is passed and B0 is returned.
 */
static Slrn_Article_Line_Type *unwrap_line (Slrn_Article_Type *a, /*{{{*/
					    Slrn_Article_Line_Type *l) /*{{{*/
{
   char *b;
   Slrn_Article_Line_Type *next, *ll;

   a->needs_sync = 1;
   a->is_modified = 1;

   ll = l->prev;
   b = ll->buf;
   do 
     {
	b += strlen (b);
	strcpy (b, l->buf + 1);   /* skip the space at beginning of
				   * the wrapped line. */
	next = l->next;
	slrn_free ((char *)l->buf);
	slrn_free ((char *)l);
	if (l == a->cline) a->cline = ll;
	l = next;
     }
   while ((l != NULL) && (l->flags & WRAPPED_LINE));
	     
   ll->next = l;
   if (l != NULL) l->prev = ll;
   return l;
}

/*}}}*/

/*}}}*/

int _slrn_art_unwrap_article (Slrn_Article_Type *a) /*{{{*/
{
   Slrn_Article_Line_Type *l;
   
   if (a == NULL)
     return -1;

   a->needs_sync = 1;
   a->is_modified = 1;
   l = a->lines;

   while (l != NULL)
     {
	if (l->flags & WRAPPED_LINE)
	  l = unwrap_line (a, l);      /* cannot fail */
	else l = l->next;
     }
   a->is_wrapped = 0;
   return 0;
}

/*}}}*/

int _slrn_art_wrap_article (Slrn_Article_Type *a) /*{{{*/
{
   unsigned int len;
   unsigned char *buf, ch;
   Slrn_Article_Line_Type *l;
   unsigned int wrap_mode = Slrn_Wrap_Mode;

   if (a == NULL)
     return -1;

   a->is_modified = 1;
   a->needs_sync = 1;

   if (-1 == _slrn_art_unwrap_article (a))
     return -1;

   l = a->lines;

   while (l != NULL)
     {
	unsigned char header_char_delimiter = 0;

	if (l->flags & HEADER_LINE) 
	  {
	     if ((wrap_mode & 1) == 0)
	       {
		  l = l->next;
		  continue;
	       }

	     if (0 == slrn_case_strncmp ((unsigned char *)"Path: ",
					 (unsigned char *)l->buf, 6))
	       header_char_delimiter = '!';
	     else if (0 == slrn_case_strncmp ((unsigned char *) "Newsgroups: ",
					      (unsigned char *)l->buf, 12))
	       header_char_delimiter = ',';
	  }
	else if (l->flags & QUOTE_LINE)
	  {
	     if ((wrap_mode & 2) == 0)
	       {
		  l = l->next;
		  continue;
	       }
	  }

	len = 0;
	buf = (unsigned char *) l->buf;
	ch = *buf;
	while (ch != 0)
	  {
	     if ((ch == '\t') && (SLsmg_Tab_Width > 0))
	       {
		  len += SLsmg_Tab_Width;
		  len -= len % SLsmg_Tab_Width;
	       }
	     else if (((ch >= ' ') && (ch < 127))
		      || (ch >= (unsigned char) SLsmg_Display_Eight_Bit))
	       len++;
	     else
	       {
		  len += 2;
		  if (ch & 0x80) len++;
	       }

	     if (len > (unsigned int) SLtt_Screen_Cols)
	       {
		  Slrn_Article_Line_Type *new_l;
		  unsigned char *buf0, *lbuf;

		  /* Try to break the line on a word boundary.  
		   * For now, I will only break on space characters.
		   */
		  buf0 = buf;
		  lbuf = (unsigned char *) l->buf;

		  lbuf += 1;	       /* avoid space at beg of line */

                  if (Slrn_Wrap_Method == 0 || Slrn_Wrap_Method == 2) {

		  while (buf0 > lbuf)
		    {
		       if ((*buf0 == ' ') || (*buf0 == '\t')
			   || (header_char_delimiter 
			       && (*buf0 == header_char_delimiter)))
			 {
			    buf = buf0;
			    break;
			 }
		       buf0--;
		    }

		  if (buf0 == lbuf)
		    {
		       if (Slrn_Wrap_Method == 0) {

		       /* Could not find a place to break the line.  Ok, so
			* we will not break this.  Perhaps it is a URL.  
			* If not, it is a long word and who cares about it.
			*/
		       while (((ch = *buf) != 0)
			      && (ch != ' ') && (ch != '\t'))
			 buf++;

		       if (ch == 0)
			 continue;

		       }
		       else {
		         lbuf = (unsigned char *) l->buf;
			 lbuf += 1; /* avoid space at beg of line */
		       }

		    }

		  }
		       
		  /* Start wrapped lines with a space.  To do this, I will
		   * _temporally_ modify the previous character for the purpose
		   * of creating the new space.
		   */
		  buf--;
		  ch = *buf;
		  *buf = ' ';
		  
		  new_l = (Slrn_Article_Line_Type *) slrn_malloc (sizeof (Slrn_Article_Line_Type), 1, 1);
		  if (new_l == NULL)
		    return -1;
		  
		  if (NULL == (new_l->buf = slrn_strmalloc ((char *)buf, 1)))
		    {
		       slrn_free ((char *) new_l);
		       return -1;
		    }

		  *buf++ = ch;
		  *buf = 0;
		  
		  new_l->next = l->next;
		  new_l->prev = l;
		  l->next = new_l;
		  if (new_l->next != NULL) new_l->next->prev = new_l;

		  new_l->flags = l->flags | WRAPPED_LINE;
		  l = new_l;
		  buf = (unsigned char *) new_l->buf;
		  len = 0;
		  a->is_wrapped = 1;
	       }
	     else buf++;
	     
	     ch = *buf;
	  }
	l = l->next;
     }
   return 0;
}

/*}}}*/


static int is_blank_line (unsigned char *b) /*{{{*/
{
   b = (unsigned char *) slrn_skip_whitespace ((char *) b);
   return (*b == 0);
}

/*}}}*/

void _slrn_art_skip_quoted_text (Slrn_Article_Type *a) /*{{{*/
{
   Slrn_Article_Line_Type *l;

   if (a == NULL)
     return;

   l = a->cline;
   a->needs_sync = 1;

   /* look for a quoted line */
   while (l != NULL)
     {
	if ((l->flags & HIDDEN_LINE) == 0)
	  {
	     a->cline = l;
	     if (l->flags & QUOTE_LINE) break;
	  }
	l = l->next;
     }
   
   /* Now we are either at the end of the buffer or on a quote line. Skip
    * past other quote lines.
    */
   
   if (l == NULL)
     return;
   
   l = l->next;
   
   while (l != NULL)
     {
	if (l->flags & HIDDEN_LINE)
	  {
	     l = l->next;
	     continue;
	  }
	a->cline = l;
	if ((l->flags & QUOTE_LINE) == 0)
	  {
	     /* Check to see if it is blank */
	     if (is_blank_line ((unsigned char *) l->buf) == 0) break;
	  }
	l = l->next;
     }
}

/*}}}*/

int _slrn_art_skip_digest_forward (Slrn_Article_Type *a) /*{{{*/
{
   Slrn_Article_Line_Type *l;
   int num_passes;

   if (a == NULL)
     return -1;

   /* We are looking for:
    * <blank line>  (actually, most digests do not have this-- even the FAQ that suggests it!!)
    * ------------------------------
    * <blank line>
    * Subject: something
    *
    * In fact, most digests do not conform to this.  So, I will look for:
    * <blank line>
    * Subject: something
    *
    * Actually, most faqs, etc... do not support this.  So, look for any line
    * beginning with a number on second pass.  Sigh.
    */
   num_passes = 0;
   while (num_passes < 2)
     {
	l = a->cline->next;

	while (l != NULL)
	  {
	     char ch;
	     char *buf;
	     
	     if ((l->flags & HIDDEN_LINE) || (l->flags & HEADER_LINE))
	       {
		  l = l->next;
		  continue;
	       }
	     
	     buf = l->buf;
	     if (num_passes == 0)
	       {
		  if ((strncmp ("Subject:", buf, 8))
		      || (((ch = buf[8]) != ' ') && (ch != '\t')))
		    {
		       l = l->next;
		       continue;
		    }
	       }
	     else
	       {
		  ch = *buf;
		  if ((ch > '9') || (ch < '0'))
		    {
		       l = l->next;
		       continue;
		    }
	       }
	     
	     a->cline = l;
	     a->needs_sync = 1;
	     return 0;
	  }
	num_passes++;
     }
   return -1;
}

/*}}}*/

char *slrn_art_extract_header (Slrn_Article_Type *a, char *hdr, unsigned int len) /*{{{*/
{
   Slrn_Article_Line_Type *l;

   if (a == NULL)
     return NULL;
   
   l = a->lines;

   while ((l != NULL)
	  && (*l->buf != 0))
     {
	if (0 == slrn_case_strncmp ((unsigned char *) hdr,
				    (unsigned char *) l->buf, len))
	  {
	     char *result;

	     if ((l->next != NULL) && (l->next->flags & WRAPPED_LINE))
	       {
		  (void) unwrap_line (a, l->next);
		  slrn_art_sync_article (a);
	       }

	     /* Return the data after the colon */
	     result = slrn_strchr (l->buf, ':');
	     if (result == NULL) 
	       result = l->buf + len;
	     else result += 1;

	     return slrn_skip_whitespace (result);
	  }
	l = l->next;
     }
   return NULL;
}

/*}}}*/

typedef struct _Visible_Header_Type /*{{{*/
{
   char *header;
   unsigned int len;
   struct _Visible_Header_Type *next;
}

/*}}}*/
Visible_Header_Type;

static Visible_Header_Type *Visible_Headers;

#if SLRN_HAS_SLANG
char *Slrn_Visible_Headers_String;     /* for interpreter */
#endif

static void free_visible_header_list (void) /*{{{*/
{
   while (Visible_Headers != NULL)
     {
	Visible_Header_Type *next;
	next = Visible_Headers->next;
	SLang_free_slstring (Visible_Headers->header);   /* NULL ok */
	SLfree ((char *) Visible_Headers);
	Visible_Headers = next;
     }
#if SLRN_HAS_SLANG
   SLang_free_slstring (Slrn_Visible_Headers_String);
#endif
}

/*}}}*/


int slrn_set_visible_headers (char *headers) /*{{{*/
{
   char buf[256];
   unsigned int nth;

   free_visible_header_list ();
   
#if SLRN_HAS_SLANG
   Slrn_Visible_Headers_String = SLang_create_slstring (headers);
   if (Slrn_Visible_Headers_String == NULL)
     return -1;
#endif

   nth = 0;
   while (-1 != SLextract_list_element (headers, nth, ',', buf, sizeof(buf)))
     {
	Visible_Header_Type *next;
	
	next = (Visible_Header_Type *) SLmalloc (sizeof (Visible_Header_Type));
	if (next == NULL)
	  return -1;
	memset ((char *) next, 0, sizeof(Visible_Header_Type));
	if (NULL == (next->header = SLang_create_slstring (buf)))
	  {
	     SLfree ((char *) next);
	     return -1;
	  }
	next->len = strlen (buf);
	next->next = Visible_Headers;
	Visible_Headers = next;
	
	nth++;
     }
   return 0;
}

/*}}}*/

void _slrn_art_hide_headers (Slrn_Article_Type *a) /*{{{*/
{
   Slrn_Article_Line_Type *l;
   char ch;
   
   if (a == NULL)
     return;

   _slrn_art_unhide_headers (a);

   a->needs_sync = 1;
   
   l = a->lines;

   while ((l != NULL) && (l->flags & HEADER_LINE))
     {
	int hide_header;
	Visible_Header_Type *v;
	
	ch = l->buf[0];
	ch |= 0x20;

	hide_header = 1;

	v = Visible_Headers;
	while (v != NULL)
	  {
	     char chv = (0x20 | v->header[0]);
	     
	     if ((chv == ch)
		 && (0 == slrn_case_strncmp ((unsigned char *)l->buf, 
					     (unsigned char *)v->header, 
					     v->len)))
	       {
		  hide_header = 0;
		  break;
	       }
	     
	     v = v->next;
	  }

	do
	  {
	     if (hide_header)
	       l->flags |= HIDDEN_LINE;
	     
	     l = l->next;
	  }
	while ((l != NULL) && ((*l->buf == ' ') || (*l->buf == '\t')));
     }
   a->headers_hidden = 1;
}

/*}}}*/

void _slrn_art_unhide_headers (Slrn_Article_Type *a) /*{{{*/
{
   if (a == NULL)
     return;

   unhide_article_lines (a, HEADER_LINE);
   a->headers_hidden = 0;
}

/*}}}*/

int _slrn_art_unfold_header_lines (Slrn_Article_Type *a) /*{{{*/
{
   Slrn_Article_Line_Type *l;
   char ch;
   
   if (a == NULL)
     return -1;
   
   l = a->lines->next;
   a->is_modified = 1;
   a->needs_sync = 1;

   while ((l != NULL) && (l->flags & HEADER_LINE))
     {
	ch = l->buf[0];
	if ((ch == ' ') || (ch == '\t'))
	  {
	     unsigned int len0, len1;
	     Slrn_Article_Line_Type *prev;
	     char *new_buf;
	     
	     l->buf[0] = ' ';
	     
	     prev = l->prev;
	     
	     len0 = strlen (prev->buf);
	     len1 = len0 + strlen (l->buf) + 1;
	     
	     new_buf = slrn_realloc (prev->buf, len1, 1);
	     if (new_buf == NULL)
	       return -1;

	     prev->buf = new_buf;
	     
	     strcpy (new_buf + len0, l->buf);
	     prev->next = l->next;
	     if (l->next != NULL) l->next->prev = prev;
	     slrn_free ((char *)l->buf);
	     slrn_free ((char *) l);
	     l = prev;
	  }
	
	l = l->next;
     }
   return 0;
}

/*}}}*/

void slrn_mark_header_lines (Slrn_Article_Type *a) /*{{{*/
{
   Slrn_Article_Line_Type *l;
   
   if (a == NULL)
     return;
   l = a->lines;

   while ((l != NULL) && (l->buf[0] != 0))
     {
	l->flags = HEADER_LINE;
	l = l->next;
     }
}

/*}}}*/

void _slrn_art_hide_signature (Slrn_Article_Type *a) /*{{{*/
{
   if (a == NULL)
     return;

   hide_article_lines (a, SIGNATURE_LINE);
   a->signature_hidden = 1;
}

/*}}}*/

void _slrn_art_unhide_signature (Slrn_Article_Type *a) /*{{{*/
{
   if (a == NULL)
     return;

   unhide_article_lines (a, SIGNATURE_LINE);
   a->signature_hidden = 0;
}

/*}}}*/

void slrn_art_mark_pgp_signature (Slrn_Article_Type *a) /*{{{*/
{	
   Slrn_Article_Line_Type *l;

   if (a == NULL)
     return;
   
   l = a->lines;
   while (l != NULL)
     {
	Slrn_Article_Line_Type *l0;
	int count;

	if ((l->buf[0] != '-')
	    || strcmp (l->buf, "-----BEGIN PGP SIGNATURE-----"))
	  {
	     l = l->next;
	     continue;
	  }
	l0 = l;
	l = l->next;
	
	count = 20;
	while ((l != NULL) && count)
	  {
	     if ((l->buf[0] != '-')
		 || strcmp (l->buf, "-----END PGP SIGNATURE-----"))
	       {
		  count--;
		  l = l->next;
		  continue;
	       }
	     
	     l0->flags |= PGP_SIGNATURE_LINE;
	     do
	       {
		  l0 = l0->next;
		  l0->flags |= PGP_SIGNATURE_LINE;
	       }
	     while (l0 != l);
	     return;
	  }
	l = l0->next;
     }
}

/*}}}*/

void _slrn_art_hide_pgp_signature (Slrn_Article_Type *a)
{
   if (a == NULL)
     return;

   hide_article_lines (a, PGP_SIGNATURE_LINE);
   a->pgp_signature_hidden = 1;
}

/*}}}*/

void _slrn_art_unhide_pgp_signature (Slrn_Article_Type *a) /*{{{*/
{
   if (a == NULL)
     return;

   unhide_article_lines (a, PGP_SIGNATURE_LINE);
   a->pgp_signature_hidden = 0;
}

/*}}}*/

#if SLRN_HAS_VERBATUM_MARKS
void slrn_art_mark_verbatum (Slrn_Article_Type *a)
{
   Slrn_Article_Line_Type *l;
   unsigned char chon, choff;
   unsigned int mask;
   char *von, *voff;

   if (a == NULL)
     return;
   
   von = "#v+";
   voff = "#v-";

   chon = von[0];
   choff = voff[0];

   l = a->lines;
   mask = 0;

   while (l != NULL)
     {
	if (mask == 0)
	  {
	     if ((l->buf[0] == chon)
		 && (0 == strcmp ((char *) l->buf, von)))
	       {
		  l = l->next;
		  mask = VERBATUM_LINE;
		  continue;
	       }
	  }
	else if ((l->buf[0] == choff)
		 && (0 == strcmp ((char *) l->buf, voff)))
	  {	     
	     mask = 0;
	     l = l->next;
	     continue;
	  }

	if (mask)
	  {
	     l->flags &= ~(QUOTE_LINE|SIGNATURE_LINE|PGP_SIGNATURE_LINE);
	     l->flags |= VERBATUM_LINE;
	  }
	
	l = l->next;
     }
}

void _slrn_art_unhide_verbatum (Slrn_Article_Type *a) /*{{{*/
{
   if (a == NULL)
     return;

   unhide_article_lines (a, VERBATUM_LINE);
   a->verbatum_hidden = 0;
}

/*}}}*/

void _slrn_art_hide_verbatum (Slrn_Article_Type *a) /*{{{*/
{
   if (a == NULL)
     return;

   hide_article_lines (a, VERBATUM_LINE);
   a->verbatum_hidden = 1;
}

/*}}}*/
#endif

	     
	     
	       
	  
   
