Newsgroup: it.comp.software.newsreader
Titolo: [HAMSTER][Lungo] Fronteggiare il problema di "R: " con uno script

Salve!
Può  essere  interessato  alla lettura di questo articolo soprattutto
chi usa Hamster abbinato ad  un  newsreader  in  modalità  ONLINE  e,
oltre  a  soffrire  del  problema  "R: ", vede soddisfatta almeno una
delle seguenti condizioni:
 -non ha troppi client da gestire;
 -i suoi polling delle news,  se  automatici,  sono  sufficientemente
  rari (uno ogni 15 minuti può IMO andar già bene);
 -ha una connessione veloce al NS remoto.
Le  funzioni  proposte  saranno  un  po'  pesanti, ancorché semplici:
quindi  consiglierei  qualche  cautela  a   chi   fosse   dotato   di
hardware lento.
Ok, si parte.
Il  problema  di  "R: ",  com'è  comunemente  chiamato,  si manifesta
quando il sbj di un articolo inizia con una sequenza di  "R: "  e  di
"Re: "  diversa  dal  semplice singolo "Re: ": chiamo questa sequenza
"prefisso anomalo". 
"R: pippo" è errato ed è un problema; "R: Re: pippo" è  errato  ed  è
un  problema;  "Re: R: pippo"  è  giusto  (è  la  giusta  risposta  a
"R: pippo"), ma bisogna interessarsene comunque,  qualora  si  voglia
affrontare il problema.
Parto  dal  presupposto  che,  se voglio rispondere ad un articolo il
cui sbj è "R: R: R: pippo", devo farlo con  "Re: R: R: R: pippo".  La
soluzione  "Re: pippo", che io stesso ho più volte adottato, in preda
all'esasperazione, comporta infatti:
a) per chi ordina *solo* in base  al  campo  References,  l'eventuale
   vantaggio di accorciare un sbj inutilmente lungo;
b) per  chi  voglia  ordinare  *anche* per sbj, ed abbia problemi coi
   prefissi non standard, un ulteriore  inopportuno  spezzamento  del
   thread.
Visto  che  sono  proprio  le  situazioni  di  tipo  b)  che vogliamo
limitare,  la  nostra  soluzione  non  può  renderle  più  frequenti:
sarebbe un controsenso.
L'idea si sviluppa nei seguenti punti:
1) appena  scaricati  gli articoli, e prima che vengano dati in pasto
   ai newsreader, Hamster li  carica,  uno  ad  uno,  in  una  lista;
   verifica se il sbj inizi con un prefisso anomalo; *se* sì:
 
 a) lo  cambia  in  un  singolo  "Re: "  e salva il sbj originale nel
    nuovo campo "X-Original-Subject". Avrei pensato di salvarlo  come
    *commento*  nel  campo  Message-ID (cosicché l'informazione fosse
    a portata di mano, inserita nel campo References  di  una  nostra
    eventuale   reply   all'articolo   modificato),   ma  Gravity  mi
    sballerebbe l'aberatura dei thread. :-(
 b) cancella l'articolo originale dal database;
 c) importa nel database l'articolo modificato;
2) prima di spedire un nostro articolo,  Hamster  lo  carica  in  una
   lista  e  ne  controlla  il  campo  Subject: se inizia con "Re: ",
   quindi se è una reply a cui non abbiamo cambiato il subject:
 a) recupera l'ultimo ID del campo References;
 b) ripesca nel suo database l'articolo con quell'ID (sempre  che  ci
    sia ancora), e lo carica in una lista;
 c) controlla  il  campo "X-Original-Subject" di quell'articolo e, se
    esiste e non è vuoto, ne usa il contenuto per sostituire  il  sbj
    dell'articolo  in  uscita,  facendolo  precedere da "Re: " se non
    inizia già con "Re: ";
 d) se l'articolo padre non  è  più  nel  database,  e  b)  fallisce,
    l'articolo   in   uscita   viene   spedito   così  com'è.  Quindi
    ATTENZIONE: se usate un  newsreader  in  modalità  online,  tutto
    bene  (non  potreste  rispondere  ad  un  articolo  che non fosse
    più  nel  database);  se  viceversa  ne  usate  uno  in  modalità
    offline  e  conservate  gli  articoli  in  Hamster  solo  per  un
    brevissimo  periodo,  probabilmente  non  dovreste  usare  queste
    funzioni  (il  sbj  originale  spesso  non  verrebbe ripristinato
    nelle vostre reply).
Ovviamente, perché quanto  sopra  sia  possibile,  bisogna  scaricare
sempre  gli  articoli  con  uno  script,  così  da  poter eseguire 1)
immediatamente dopo lo scarico, *disabilitando* il  server  news  per
tutto  l'intervallo  di  tempo  che va dall'inizio dello scarico alla
fine di 1). Si tratta quindi di un metodo poco  adatto  a  chi  debba
gestire  numerosi  client  e  contemporaneamente  effettui un polling
delle news pressoché continuo (la ratio è: quanti down del srv  posso
permettere, pur sapendo che, quanto più sono numerosi, tanto più sono
brevi?).
La 2) va chiamata prima di inviare gli articoli in uscita.
1) e 2) sono delle sub brevi,  facilmente  gestibili  inserendole  in
un  modulo  e  richiamandole  negli  script  (previo  caricamento del
modulo, s'intende).
Le  propongo  insieme  a  qualche  commento.  Mi  sembrano   alquanto
autoesplicative.
1)
Sub RE_incoming($min,$max,$hdl_gruppo)
var($i,$a1,$a2,$articolo,$pos)
$articolo=listalloc
for($i,$min,$max)
	listsettext($articolo,hamarttext($hdl_gruppo,$i)) 
	$a1=MsgGetHeader($articolo, "Subject:")
	$a2=RE_Extract($a1,"^(R(e)?:\s)+")
	if(($a2<>"")&&($a2<>"Re: "))
		MsgSetHeader($articolo, "Subject:",_
		 replace($a1,$a2,"Re: ",false))
		Hamartdeletemid(msggetheader($articolo,_
		 "Message-ID:"))
		MsgAddheader($articolo, "X-Original-Subject:",$a1)
		Hamartimport(listgettext($articolo),"",true,false)
	endif
endfor
listfree($articolo)
hamflush
endsub
Chiamando  la  RE_incoming,  bisogna  passarle tre valori: ovviamente
$min=hamartnomax($hdl_gruppo)   effettuato   prima   dello   scarico;
$max=hamartnomax($hdl_gruppo) effettuato dopo lo scarico;
$hdl_gruppo è l'handle del gruppo.
Bisogna  chiamare  la  RE_incoming in loop, una volta per ogni gruppo
(ma si può scegliere di evitare certi gruppi: i  gruppi  binari,  per
esempio - sempreché qualcuno usi Hamster per i binari).
2)
Sub RE_outgoing($articolo)
var($original_sbj,$ref,$numero,$gruppo,$riferito,$hdl_gruppo)
	if(RE_match(msggetheader($articolo, "Subject:"), "^Re: "))
		$ref=RE_Extract(msggetheader($articolo,_
		 "References:"),"<[^<>]+>(?=[^<>]*$)")
		if(Hamartlocatemid($ref, $gruppo,$numero)=0)
			$hdl_gruppo=hamgroupopen($gruppo)
			$riferito=listalloc
			listsettext($riferito,_
			 hamarttext($hdl_gruppo,$numero))
			$original_sbj=msggetheader($riferito,_
			 "X-Original-Subject:")
			listfree($riferito)
			hamgroupclose($hdl_gruppo)
			if($original_sbj<>"")
				if(RE_match($original_sbj, "^Re: "))
					Msgsetheader($articolo,_
					 "Subject:",$original_sbj)
				else
					Msgsetheader($articolo,_
					 "Subject:","Re: "_
					  +$original_sbj)
				endif
			endif
		endif
	endif
endsub
La  RE_outgoing  va  chiamata  in loop, una volta per ogni articolo o
messaggio in uscita, passandoglielo, come argomento, sotto  forma  di
lista.
Se voleste provare l'effetto su un vostro gruppo, che sapete  affetto
dal  problema  "R: ",  potreste:  ordinarne  gli  articoli  per data,
controllare il primo e l'ultimo e segnarvi i due numeri di Xref  (che
saranno   min   e  max);  cancellarlo  dal  newsreader  (unsubscribe,
insomma); appiccicare temporaneamente la 1) nel  modulo  hmessage.hsm
e  salvarlo;  nel  prompt   hs2   di   Hamster  appiccicare  la  riga
#!load hmessage.hsm¶RE_incoming(min,max,HamGroupOpen("nome.gruppo"))
sostituendo opportunamente min, max e nome.gruppo; battere <invio>  e
controllare  dopo  quanti  secondi vi compare un avviso giallo che vi
avverte che lo script non ha liberato le  risorse  (avete  aperto  un
gruppo  senza  poi  chiuderlo,  chissenefrega).  In  quel  momento lo
script 1) ha terminato il suo lavoro.
Sottoscrivete di nuovo il gruppo, e verificate.
Uno script che contenga la 1) può esser così fatto: supponendo che la
1)  sia  stata  salvata in azioni.hsm (il quale, a sua volta, carichi
hmessage.hsm), e di aver definito scarica_posta  e  scarica_news,  si
avrà:
#!hs2
#!load azioni.hsm
sincro
hamwaitidle
atclear
atadd(sincro,"00:00","23:46","1111111",15,false)
atexecute
quit
sub sincro
var($ng,$i,$gruppo,$hdl_gruppo,$min,$max)
	if(rasisconnected && hamisidle)
 
		scarica_posta
 
		hammessage(3,0)	#sospende il NS locale
		scarica_news
		hamwaitidle		
 
		$ng=hamgroupcount-1
		for($i,0,$ng)
			$gruppo=hamgroupname($i)
			# controllo solo i ng di it.*, non binari
			if(RE_match($gruppo,"^it\.(?!binari)"))
				$hdl_gruppo=hamgroupopen($gruppo)
				$min=Iniread("","Max_passato",_
				 $gruppo,9999999999)
				$max=hamartnomax($hdl_gruppo)
				Iniwrite("","Max_passato",$gruppo,_
				 $max)
				RE_incoming($min,$max,$hdl_gruppo)
				hamgroupclose($hdl_gruppo)
			endif
		endfor
		hammessage(3,1) #riattiva il NS locale
	endif
endsub
Si può spostare la stessa sub sincro in azioni.hsm, ovviamente.
Con questo script il trattamento  dei  prefissi  anomali  inizierà  a
partire  dal  secondo scarico: col primo si inizializzano i valori in
Hscript.ini. Sostituendo invece
9999999999
con
hamartnomin($hdl_gruppo)
al primo scarico si andrebbe a pulire tutto  il  database  (cosa  che
può  risultare  davvero  lunga,  e  che sconsiglio). Adottando questa
seconda politica,  andrebbe  aggiornato  anche  il  database  del  NR
usato   online  (in  Gravity  sarebbe  sufficiente  lanciare  "verify
local headers").  Naturalmente  gli  effetti  sul  passato  sarebbero
nulli,  se,  fino  ad oggi, aveste filtrato gli articoli con prefissi
anomali (BTW: ricordatevi di tirarli fuori dal killfile!).
Disclaimer: le distrazioni sono possibili, al solito.
[Xpost e f/up]
-- 
Informazioni su it.*: 
www.news.nic.it/news-it/
Archivio news: 
http://groups.google.com/advanced_group_search?hl=it
Un motore di ricerca: 
www.alltheweb.com/advanced
Computazione diffusa: 
www.aspenleaf.com/distributed/

autoesplicative.
Però  non funzionano coi sbj Q-codificati in base ad un set esteso di
caratteri (del tipo
Subject: =?ISO-8859-1?Q?Re:_R:_imposte_su_reddito_di_societ=E0?=).
Prima  di  proporvene  le  ultime  versioni,  modificate per superare
anche questo ostacolo,  attiro  la  vostra  attenzione  su  un  punto
completamente   diverso   (e   che   non  condiziona  minimamente  il
funzionamento delle procedure in oggetto): Agent 1.8 non mostra  mai,
né  salva  su  file,  il  campo  X-Original-Subject,  benché esso sia
ovviamente presente nei .DAT. Non so perché, forse non gli  piace  il
nome. Non so se ciò capiti anche con altri NR.
Ripeto che la cosa non ha alcuna conseguenza pratica.
Ecco le ultime versioni:
1)
Sub RE_incoming($min,$max,$hdl_gruppo)
var($i,$a1,$a2,$a3,$a4,$articolo,$pos)
$articolo=listalloc
for($i,$min,$max)
	listsettext($articolo,hamarttext($hdl_gruppo,$i)) 
	$a1=MsgGetHeader($articolo, "Subject:")
	if(ord($a1)=61)
		$a2=RE_extract($a1,"^=\?[^?]+\?Q\?(R(e)?:_)+")
		$a3=RE_Extract($a2,"(R(e)?:_)+")
		$a4="Re:_"
	else
		$a2=RE_Extract($a1,"^(R(e)?:\s)+")
		$a3=$a2
		$a4="Re: "	
	endif
	if(($a3<>"")&&($a3<>"Re: ")&&($a3<>"Re:_"))
		MsgSetHeader($articolo, "Subject:",_
		 replace($a1,$a2,replace($a2,$a3,$a4,false),false))
		Hamartdeletemid(msggetheader($articolo,_
		 "Message-ID:"))
		MsgAddheader($articolo, "X-Original-Subject:",$a1)
		Hamartimport(listgettext($articolo),"",true,false)
	endif
endfor
listfree($articolo)
hamflush
endsub
2) A  proposito:  su  idea  di  Joe  Fox,  questa  versione  della 2)
inserisce nel corpo dell'articolo un avvertimento, quando si risponde
a qualcuno che usi R: al posto di Re:.
Sub RE_outgoing($articolo)
var($original_sbj,$ref,$numero,$gruppo,$riferito,$hdl_gruppo,$a1,_
 $a2)
	if(RE_match(msggetheader($articolo, "Subject:"),_
	 "^(=\?[^?]+\?Q\?)?Re:"))
		$ref=RE_Extract(msggetheader($articolo,_
		 "References:"), "<[^<>]+>(?=[^<>]*$)")
		if(Hamartlocatemid($ref, $gruppo,$numero)=0)
			$hdl_gruppo=hamgroupopen($gruppo)
			$riferito=listalloc
			listsettext($riferito,_
			 hamarttext($hdl_gruppo,$numero))
			$original_sbj=msggetheader($riferito,_
			 "X-Original-Subject:")
			listfree($riferito)
			hamgroupclose($hdl_gruppo)
			if($original_sbj<>"")
				if(RE_match($original_sbj,_
				 "^(=\?[^?]+\?Q\?)?Re:"))
					Msgsetheader($articolo,_
					 "Subject:", $original_sbj)
				else
					if(ord($original_sbj)=61)
					$a1=RE_Extract($original_sbj,_
					 "^=\?[^?]+\?Q\?(R(e)?:_)+")
					$a2=RE_Extract($a1,"(R(e)?:_)+")
					Msgsetheader($articolo,_
					 "Subject:",_
					  replace($original_sbj,$a1,_
					   replace($a1,$a2,"Re:_"+$a2)))
					else
					Msgsetheader($articolo,_
					 "Subject:", "Re: "_
					   +$original_sbj)
					endif
					#### avvertimento R: ####
			varset($insert,listindexof($articolo,"")+1)
			if(!RE_match(listget($articolo,$insert),_
			 "(?-i)_ATTENZIONE_!!!"))				
				listinsert($articolo,$insert,_
			 "_ATTENZIONE_!!!")
				listinsert($articolo,$insert+1,"Il_
			 tuo programma utilizza un prefisso di_
			  risposta non standard.")
				listinsert($articolo,$insert+2,_
			 "(""R: "" al posto di ""Re: ""). Per_
			  cortesia, risolvi il problema.")
				listinsert($articolo,$insert+3,_
			 "Maggiori informazioni qui:_
 
www.vene.ws/mail/r-out.asp
 - Grazie.")
				listinsert($articolo,$insert+4)
				listinsert($articolo,$insert+5)
			endif
					#### fine avvertimento R: ####
				endif
			endif
		endif
	endif
endsub
Xpost e f/up.


autoesplicative.
Però  non funzionano coi sbj Q-codificati in base ad un set esteso di
caratteri (del tipo
Subject:  =?ISO-8859-1?Q?Re:_R:_imposte_su_reddito_di_societ=E0?=  ).
Prima  di  proporvene  le  ultime  versioni,  modificate per superare
anche questo ostacolo,  attiro  la  vostra  attenzione  su  un  punto
completamente   diverso   (e   che   non  condiziona  minimamente  il
funzionamento delle procedure in oggetto): Agent 1.8 non mostra  mai,
né  salva  su  file,  il  campo  X-Original-Subject,  benché esso sia
ovviamente presente nei .DAT. Non so perché, forse non gli  piace  il
nome. Non so se ciò capiti anche con altri NR.
Ripeto che la cosa non ha alcuna conseguenza pratica.
Ecco le ultime versioni:
1)
Sub RE_incoming($min,$max,$hdl_gruppo)
var($i,$a1,$a2,$a3,$a4,$articolo,$pos)
$articolo=listalloc
for($i,$min,$max)
	listsettext($articolo,hamarttext($hdl_gruppo,$i)) 
	$a1=MsgGetHeader($articolo, "Subject:")
	if(ord($a1)=61)
		$a2=RE_extract($a1,"^=\?[^?]+\?Q\?(R(e)?:_)+")
		$a3=RE_Extract($a2,"(R(e)?:_)+")
		$a4="Re:_"
	else
		$a2=RE_Extract($a1,"^(R(e)?:\s)+")
		$a3=$a2
		$a4="Re: "	
	endif
	if(($a3<>"")&&($a3<>"Re: ")&&($a3<>"Re:_"))
		MsgSetHeader($articolo, "Subject:",_
		 replace($a1,$a2,replace($a2,$a3,$a4,false),false))
		Hamartdeletemid(msggetheader($articolo,_
		 "Message-ID:"))
		MsgAddheader($articolo, "X-Original-Subject:",$a1)
		Hamartimport(listgettext($articolo),"",true,false)
	endif
endfor
listfree($articolo)
hamflush
endsub
2) A  proposito:  su  idea  di  Joe  Fox,  questa  versione  della 2)
inserisce  anche  un  avviso,  quando  si  risponde  a  qualcuno  col
problema della R:.
Sub RE_outgoing($articolo)
var($original_sbj,$ref,$numero,$gruppo,$riferito,$hdl_gruppo,$a1,_
 $a2)
	if(RE_match(msggetheader($articolo, "Subject:"),_
	 "^(=\?[^?]+\?Q\?)?Re:"))
		$ref=RE_Extract(msggetheader($articolo,_
		 "References:"), "<[^<>]+>(?=[^<>]*$)")
		if(Hamartlocatemid($ref, $gruppo,$numero)=0)
			$hdl_gruppo=hamgroupopen($gruppo)
			$riferito=listalloc
			listsettext($riferito,_
			 hamarttext($hdl_gruppo,$numero))
			$original_sbj=msggetheader($riferito,_
			 "X-Original-Subject:")
			listfree($riferito)
			hamgroupclose($hdl_gruppo)
			if($original_sbj<>"")
				if(RE_match($original_sbj,_
				 "^(=\?[^?]+\?Q\?)?Re:"))
					Msgsetheader($articolo,_
					 "Subject:", $original_sbj)
				else
					if(ord($original_sbj)=61)
						$a1=RE_Extract($original_sbj,_
					 	 "^=\?[^?]+\?Q\?(R(e)?:_)+")
						$a2=RE_Extract($a1,"(R(e)?:_)+")
						Msgsetheader($articolo,_
						 "Subject:",_
						  replace($original_sbj,$a1,_
						   replace($a1,$a2,"Re:_"+$a2)))
					else
						Msgsetheader($articolo,_
						 "Subject:", "Re: "_
						   +$original_sbj)
					endif
					#### avvertimento R: ####
			varset($insert,listindexof($articolo,"")+1)
			if(!RE_match(listget($articolo,$insert),_
			 "(?-i)_ATTENZIONE_!!!"))				
				listinsert($articolo,$insert,_
			 "_ATTENZIONE_!!!")
				listinsert($articolo,$insert+1,"Il_
			 tuo programma utilizza un prefisso di_
			  risposta non standard.")
				listinsert($articolo,$insert+2,_
			 "(""R: "" al posto di ""Re: ""). Per_
			  cortesia, risolvi il problema.")
				listinsert($articolo,$insert+3,_
			 "Maggiori informazioni qui:_
 
www.vene.ws/mail/r-out.asp
 - Grazie.")
				listinsert($articolo,$insert+4)
				listinsert($articolo,$insert+5)
			endif
					#### fine avvertimento R: ####
				endif
			endif
		endif
	endif
endsub
Xpost e f/up.
