xpn-1.2.6/0000755000175000017500000000000011141275756010464 5ustar antantxpn-1.2.6/TODO0000644000175000017500000000053211141275756011154 0ustar antant******************************************************************************* * X Python Newsreader * * TODO * ******************************************************************************* Just too much things :-) xpn-1.2.6/lang/0000755000175000017500000000000011141275756011405 5ustar antantxpn-1.2.6/lang/de/0000755000175000017500000000000011141275756011775 5ustar antantxpn-1.2.6/lang/de/LC_MESSAGES/0000755000175000017500000000000011141275756013562 5ustar antantxpn-1.2.6/lang/de/LC_MESSAGES/xpn.mo0000644000175000017500000011434011141275756014727 0ustar antant!-" -,- K-EY-- -7-*-#.*C.n.0.#. .(/+/G/]/a/g/p/ w// / //#//G/?0 ^0 j0u0}0 0 00000001#1=1 P1[1l1q11111111 22 2,2>2N2c2u222 222 333 3*3D3"_3333'3 34 4,4G4L4S4e4t4444#4@4#5:5N5W5j5/555 55566!*6 L6Y6 k6u666 6 666 6#7 '727:7 ?7J7]7v777 7777"8(898@8E8Y8m88 88/8.8"949 E9S9i9~99999999: :/&:.V:::: :::3::;,;.D;"s;$;; ;; ;; <<!<(< 7<D<X<_<g< v<!<< <<<<<<<== = %= 2=S=b=u=z= ====(=== > > >(>7> I> U>c>{>>>>>> ??-?L?c?|? ?? ? ?"? ??@-@G@ L@7Z@@@ @ @@ @@#@#A ,A7AGA XA cA nA|A AAA AAKAKcPcacpcc ccc!cc cd 5dAdRdWdhd~ddddddd ee+e=eTeie*e)e(eff'fGfMf Tf ^fhff'f!ff g$!gFg dgrg%gggggggh'h"/h>Rhhh hh h4i7iKi]i nixii i iiii) j3jSj pj~jjj j)j jjjkk)kEk Wkxkkkkk(k lll#l9lOlhl ~ll4l1l&m+m>mXmqmmmmmmm nn(n9n9Jn3n nnn nnn5o7oMo8Uo8o)o'op +p9p KpXp_ppppppppp p p'pqq (q3q LqWqlq }qq qq q&qqq rrr+rBrZr0arrr rr rrr r s!s#>sbss"ss!ss) t+3t_t!t%ttttu-u CuNufu|u u uJuvv $v 0vSe ń Єބ)C ]jͅ "(0Yw-؆ &/Vgw   ɇӇ+ @"N+q7,Ո+0._t N͉&0C/tiĊ.J\ds't9 ʎ! 9,"f "Ώ/ <U^ mz ː #,7RdA:+4`'@DhÓٓ2;D\n &˔(1X"{L]lp3.td| [/Q6; 6S= 'LhP!3skYK$VIvyjKe4r-cA2R)EO?z:N aPM"^Qp)u U|e  R f(Zj_IT=1ga+n{bFGG\s^, OC ]Sr *x(X W0T#}0$wm}tzBHi/H<F@g 'J97% +L@_qE`~i9V*D-o:M!uZ82\xYk{C4.J8[5~ >7l&vD5"&`bm >n,qdX1BWU;cN<hwyf% #A?o Do you want to send the Article? Insert here a tagline Wrap column%s = Subject %g = Newsgroups %f = From %n = Nick %e = Email %d = Date%s response : %s%s selected* Article contains more than 95% of quoted text * Article doesn't contain new text * Article seems to be empty * From field appears to be invalid * From field is empty * Newsgroups field appears to be invalid * Newsgroups field is empty * Subject field is empty * To field appears to be invalid * To field is empty > [...Muted Quote...]ANDAboutAbout...ActionAdd ManuallyAdd RuleAdd a ServerAdd a TaglineAdd an IdentityAdvance to the Next Article on MarkAlways Use External EditorAn instance of XPN is already running. Do you want to open XPN anyway?Apply Scoring and Action RulesApproved : Archive : ArticleArticle DeletedArticle FoundArticle PaneArticle loadedArticlesArticles NumberArticles View OptionsAscending OrderAssign Identities to GroupsAttribution lineAutomatic Header DownloadAvailable CharsetsBackgroundBackground ColorBodyBuilding ArticlesBuilding Newsgroups listCancel Article Sent: Cancel Article...Case InsensitiveCase SensitiveChange ShortcutChange Signature PathCharset : CharsetsCharsets ListChoose the ServerClear ShortcutsClose Filter ToolbarClose this windowClose window and save settingsClose window. Discard changesClose window. Save ChangesCollapse AllCollapse All ThreadsCollapse Selected SubThreadColorColorsComposeConditionConfigure Display ProfileConfigure Group PropertiesConfigure Miscellaneous PropertiesConfigure Server ProfilesConfigure User ProfileConnection closedConnection estabilished with server: %sConnection estabilished with: %sContains StringCorrect RulesCustom Headers (X-Headers)DateDate: Default ShortcutsDelete ArticleDelete Article/MailDifferent From (numbers only)Discard ArticleDisplayDisplay Headers in the Article PaneDo you want to CANCEL this article? Subject: %s Message-ID: %sDoesn't Contain StringDoesn't Match RegExDownloadDownload CompletedDownload Headers automaticallyDownload this number of articles (headers only)Downloading Bodies for %sDraft ArticlesDraft MailsDraftsDuplicates ErrorsDuplicates WarningsE-Mail addressE-Mail address (for Mail replies)Edit ArticleEdit Article/MailEdit MailEdit Scoring and Action RulesEdit Selected IdentityEdit Selected ServerEdit WindowEmail SentEnglishEqual To (numbers only)Error DialogError while opening external editorErrors LogErrors:ExitExpand AllExpand All ThreadsExpand Group on EnteringExpand Headers RowExpand Selected SubThreadExport Newsrc...External AppsExternal EditorExternal Editor CommandFallback Charset (Reading)Fast (but imprecise) old AlgorithmFetching HeadersFieldsFileFile does not existFilter Articles ...Filter Articles by: Filter Articles...Find ArticleFind Article...First you have to configure at least one ServerFirst you have to create at least one IdentityFirst you have to read the articleFixed Pitch FontFlags & ScoreFocus to Article PaneFocus to Groups PaneFocus to Threads PaneFocus to groups PaneFolderFollow-Up To NewsgroupFollow-Up To Newsgroup...Followup-To : FontsFonts and ColorsForeground ColorFound %s tagsFound duplicated shortcuts on different windowsFound duplicated shortcuts on the same windowsFrenchFromFrom : From ColumnFrom: Fully Qualified Domain NameG: Groups Pane H: Headers Pane A: Article PaneGenerate Message-IDGermanGet Marked Article Bodies in Selected GroupsGet Marked Article Bodies in Subscribed GroupsGet New Headers in Selected GroupsGet New Headers in Subscribed GroupsGet Newsgroups ListGlobal SearchGlobal Search ...Greater ThanGroupGroup removedGroup subscribedGroupsGroups List...Groups ScopeGroups View OptionsHeaderHeadersHeaders ColorsHeaders ListHeaders Shown on the Article PaneHelpHide HeadersIdentityIdentity SettingsIgnoreIgnore SubThreadImport Newsrc...In RangeInsert Spoiler CharItalianKeepKeep ArticleKeep Articles in Selected GroupsKeep SubThreadKeyboard ShortcutsKillLanguageLast ErrorLaunch External EditorLaunch External _EditorLayoutLimit the number of articles to downloadListLower Author ScoreLower LimitLower ScoreLower ThanMail-Copies-ToMail-Copies-To : Main WindowManage GroupsMark All Groups as ReadMark All Groups as UnreadMark Article as ReadMark Article as UnReadMark Article for RetrievingMark Group ...Mark Group for RetrievingMark ReadMark Selected Groups as ReadMark Selected Groups as UnreadMark SubThread as ReadMark SubThread as UnReadMark SubThread for RetrievingMark UnreadMark for DownloadMatch RuleMatches RegExMax number of articles to downloadMessage-IDMessage-ID Search DialogMessage-ID to searchMinutes Between DownloadsMiscMiscellaneousMissing Config File. Do you want to Configure XPN now?ModeModify Keyboard Shortcuts...More HeadersNNTP ServerNNTP Server AddressNNTP ServersName or NickNameName or NickName (for Mail replies)NavigateNavigationNew Action RuleNew Scoring RuleNewsGroupsNewsgroupsNewsgroups : Newsgroups list loadedNewsgroups/ToNewsrc successful exportedNewsrc successful importedNo ErrorsNo New HeadersNo connection with server : %s. Configure NNTP Server Address or try later.No connection with server : %s. Configure SMTP Server Address or try later.Not Greater ThanNot Lower ThanNumberNumber of days. '0' means never purge read articlesNumber of days. '0' means never purge unread articlesOROne Click Enter ArticleOne Click Enter GroupOne-Key ReadingOne-Key Scroll UpOpen Outbox ManagerOptional HeadersOrdered CharsetsOrdered List (Writing)OrganizationOrganization : Original Poster set "Followup_to" on %s, Do you want to send your article on the original newsgroup (%s) ?Original Poster set "Followup_to: poster", Do you want to reply by mail ?Out Of RangeOutBoxOutGoing ArticlesOutGoing MailsOutboxOutbox ManagerOutbox WindowPasswordPerform Live SearchPersonal InformationsPlease Wait. Building ThreadsPlease set the Identity NamePlease set the Server NamePlease wait, I'm downloading the listPort NumberPost New ArticlePost New Article...PreferencesPreferences...Press OK to confirm itProblems while deleting the article: %sProblems while opening : Problems while opening Mail DraftsProblems while opening Mail OutBoxProblems while opening News DraftsProblems while opening News OutBoxProblems while opening Sent ArticlesProblems while opening Sent MailsProblems while opening article :Problems while opening folder :Problems while opening mail :Purge OptionsPurge read articles after (days)Purge unread articles after (days)Purging Group: %sQuote Level 1Quote Level 2Quote Level 3RE TesterROT13 Selected TextRaise Author ScoreRaise ScoreReScan RulesRead Next ArticleRead Next Unread ArticleRead Parent ArticleRead Previous ArticleReferencesRefreshing Group %sRegular ExpressionRemove Selected IdentityRemove Selected ServerReply By Mail...Reply by MailReply-ToReply-To : RetrieveRetrieve Bodies for all new articlesRule used to combine search resultsRulesSMTP ServerSMTP Server Address | Port NumberSave Article as DraftScope/Score ModScoreScore File EditorScoring RulesScoring and Action Rules...Scroll Text (% of page)SearchSearch GroupSearch in current groupSearch in subscribed groupsSearch in the BodySearch in the Body...Search on GoogleSearching...Select Background ColorSelect Headers Background ColorSelect Headers Foreground ColorSelect Newsrc Export PathSelect Newsrc FileSelect Quote Level 1 ColorSelect Quote Level 2 ColorSelect Quote Level 3 ColorSelect Sign ColorSelect Signature FileSelect Text ColorSelect URL ColorSend ArticleSend Article LaterSend Article _LaterSend Queued ArticlesSend Queued MailsSend Queued _MailsSender : Sending Article: Sending Mail: SentSent %d ArticlesSent %d MailsSent ArticlesSent MailsServerServer Error: Server LogsServer Logs ViewerServer Logs...Server SettingsServer error: %sServer requires authenticationServersSet Author ScoreSet Default ListSet ScoreSetColorShortcutShortcut DialogShow All Read ThreadsShow Articles with Score<0Show Articles with Score=0Show Articles with Score>0Show ErrorsShow Full ListShow Hidden FilesShow Ignored ArticlesShow Kept ArticlesShow Quoted TextShow Read ArticlesShow SignaturesShow Spoilered TextShow ThreadsShow Threads Without Watched ArticlesShow UnKept ArticlesShow UnRead ArticlesShow UnWatched/UnIgnored ArticlesShow Watched ArticlesShow/Hide HeadersShown HeadersSignSignatureSignature file not foundSlow (but precise) new AlgorithmSorting ColumnSorting OptionsStandard HeadersStart from the BeginningStart searchingSubjectSubject : Subject ColumnSubject: Subscribe ManuallySubscribe selected groupsSubscribed GroupsSubscribed _GroupsSupersede Article...Supersedes : Syntax Error: Bad Line:: Syntax Error: Bad Match Rule on line:: Syntax Error: Bad Score Modifier on line:: Syntax Error: Missing scope for line :: Syntax Error: Unknown Action on line:: Syntax Error: Unknown Header Name on line:: TagLine AddedTagLine length: Test Regular ExpressionTest TextTextText or Regular ExpressionThat's not a problem, the shortcut will work only on the active window The Group Name seems to be wrongThere are new articles in watched threads: This article is not available on the serverThis could take several minutesThis is a crosspost! Do you want to send the article only on the original newsgroup (%s) ?This is root articleThreading MethodThreadsThreads PaneThreads expander positionTo : To correctly import a newsrc file you have to use the same server you used when you saved the file. By default XPN uses a name like 'server_name.newsrc' so it is possible to know wich server was used When you try to import a newsrc file XPN searches for the server name in the file name. Server To Use:Type the editor launcher, %s represents the filename. Examples: xterm -e vim %s gvim -f %s notepad.exe %s "C:\Program Files\Notepad++\Notepad++.exe" %s -nosession NOTE: This feature works only with *Nix and Windows systemsType your ShortcutType your custom command, %s represents the url. Examples: mozilla %s & xterm -e links %sURLUnKeepUnMark for DownloadUnReadUnSetWatchIgnoreUnSubscribe selected groupsUnable to send the message. Control Server Logs.Unexpected error in the excepthook.Upper LimitUse Custom Web Browser LauncherUse Regular ExpressionUse SSL (Secure Socket Layer)Use System FontsUse different From field in mail repliesUse random taglinesUserUser ProfileUsernameViewView Next GroupView Raw ArticleVisualizationWarnings:WatchWatch SubThreadWeb BrowserWeb Browser LauncherWindowXPN PreferencesXPN TagLines ManagerXPN will show these headers on the top of the Article PaneXPN will try to encode your articles with these charsets in this orderXPN will try to use the charsets in this orderYou can Cancel/Supersede only your articlesYou can try on Google:You can write here a FQDN (Fully Qualified Domain Name) that will be used to compose the Message-ID. Otherwise if you leave this field blank XPN will use your Host Name.You have to download newsgroups listYou must restart XPN in order to get the translation activeZoom Article PaneZoom Groups PaneZoom Headers PaneZoom Threads PaneZoom groups Pane[...Muted Sign...]_Article_Articles_Delete Article/Mail_Discard Article_Edit Article/Mail_Exit_File_Insert Spoiler Char_Navigate_Outbox_ROT13 Selected Text_Search_Send Article_Send Queued Articles_Viewpython %prog [-d] [-cCUSTOM_DIR] With command line options you can decide where XPN will save config files and articles. If you don't use any option, the current working directory will be used. If you use the '--home_dir' option, XPN will create a .xpn directory inside your home directory, and will store informations inside that directory. If you use the '--custom_dir' option, XPN will create a .xpn directory inside that custom_directory. NOTE: If you set the '--home_dir' option, XPN will ignore the '--custom_dir' option (if you used it). Examples: python xpn.py python xpn.py -d python xpn.py --custom_dir /home/user/customrow:%d, col:%dspecify an existing directory where store config files and articlestags.txt not founduse home directory to store config files and articlesProject-Id-Version: XPN 1.2.5 Report-Msgid-Bugs-To: POT-Creation-Date: 2009-01-29 09:20+0100 PO-Revision-Date: 2009-01-30 20:05+0100 Last-Translator: Nemesis Language-Team: German MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Möchtest du den Artikel senden? Tagline hier einfügen Zeilenumbruch%s = Subjekt %g = Newsgruppen %f = From %n = Nick %e = E-Mailadresse %d = Datum%s Reaktion: %s%s ausgewählt* Artikel enthält mehr als 95% zitiertenText * Artikel enthält keinen neuen Text * Artikel scheint leer zu sein * From scheint ungültig zu sein * From ist leer * Newsgroups scheint ungültig zu sein * Newsgroups ist leer * Subjekt ist leer * To scheint ungültig zu sein * To ist leer > [Zitate ausgeblendet]UNDÜberÜber...AktionManuell hinzufügenRegel hinzufügenServer hinzufügenTagline hinzufügenIdentität hinzufügenZum nächsten markierten Artikel springenImmer externen Editor verwendenEine XPN-Instanz scheint bereits zu laufen. Möchtest du XPN trotzdem starten?Anwende Regeln für Scoring und AktionenApproved : Archive : ArtikelArtikel gelöschtArtikel gefundenArtikelansichtArtikel geladenArtikelArtikelanzahlArtikel AnsichtsoptionenAufsteigende SortierungWeise Identitäten den Gruppen zuEinleitungszeileHeader automatisch herunterladenVerfügbare ZeichensätzeHintergrundHintergrundfarbeBodyErstelle ArtikelErstelle GruppenlisteCancel Artikel gesendet: Cancel Artikel...Case InsensitiveGroß-/KleinschreibungTastenkürzel ändernSignaturpfad ändernZeichensatz : ZeichensätzeZeichensatzlisteWähle den ServerTastaturkürzel leerenSchliesse SuchfilterDieses Fenster schliessenFenster schliessen. Änderungen speichern.Fenster schliessen. Änderungen verwerfenSchliesse Fenster. Speichere ÄnderungenAlle zuklappenAlle Threads zuklappenMarkierten Teilthread zuklappenFarbeFarbenVerfassenBedingungAnzeigeprofil konfigurierenGruppenoptionen.konfigurierenKonfiguriere verschiedene EinstellungenServereinstellungen konfigurierenBenutzerprofile konfigurierenVerbindung geschlossenVerbindung hergestellt zu Server: %sVerbindung hergestellt zu: %sEnthält TextKorrekte RegelnBenutzerspezifische Header (X-Header)DatumDatum: Tastaturkürzel zurücksetzenLösche ArtikelLösche Artikel/E-MailIst ungleich (Nur Zahlen)Artikel verwerfenAnzeigeZeige Header in der ArtikelansichtMöchtest du den Artikel canceln? Subjekt: %s Message-ID: %sEnthält nicht TextEntspricht nicht RegExHerunterladenDownload abgeschlossenLade Header automatisch herunterHerunterladen dieser Anzahl von Artikel (nur Header)Lade Bodies für %sArtikel EntwürfeE-Mail EntwürfeEntwürfeDuplikaten FehlerWarnung vor DuplikatenE-MailadresseE-Mailadresse (für Mailantwort)Verfasse ArtikelVerfasse Artikel/E-MailVerfasse E-MailEditiere Regeln für Scoring und AktionenMarkierte Identität bearbeitenMarkierten Server bearbeitenEditorfensterE-Mail gesendetEnglischIst gleich (Nur Zahlen)Fehler DialogFehler beim Öffnen des externen Editors.FehlerlogFehler:BeendenAlle aufklappenAlle Threads aufklappenÖffne Gruppe beim betretenHeader einblendenMarkierten Teilthread aufklappenExport Newsrc...Externe ProgrammeExterner EditorAufruf externer EditorFallback Zeichensatz (Anzeige)Schnell (aber ungenau) alter AlgorithmusLade HeaderFelderDateiDatei existiert nichtDurchsuche Artikel...Durchsuche Artikel nach:Durchsuche Artikel...Suche ArtikelSuche Artikel...Zuerst muß du mindestens einen Server konfigurierenZuerst muß du mindestens eine Identität anlegenDer Artikel muss zuerst gelesen werdenFestbreitenschriftKennzeichnungen & ScoringFocus auf ArtikelansichtFocus auf GruppenansichtFocus auf ThreadsansichtFocus auf GruppenansichtOrdnerFollow-Up in die NewsgruppeFollow-Up in Newsgruppe...Followup-To : SchriftenSchriften und FarbenVordergrundfarbe%s Tags gefundenDoppelte Tastenkürzel in verschiedenen Fenstern gefundenDoppelte Tastenkürzel in gleichem Fenster gefundenFranzösischFromFrom : From SpalteFrom: Fully Qualified Domain NameG: Gruppenliste H: Headerliste A: ArtikelfensterMessage-ID generierenDeutschLade _Bodies markierter Artikel in ausgewählten GruppenLade Bodies markierter Artikel in in abonnierten GruppenLade neue Header in ausgewählten GruppenLade neue Header in abonnierten GruppenLade GruppenlisteGlobale SucheGlobale Suche ...Grösser alsGruppeGruppe gelöschtGruppe abonniertGruppenGruppenliste...GruppenbereichGruppen AnsichtsoptionenHeaderHeaderHeaderfarbenHeaderlisteAngezeigte Header in der ArtikelansichtHilfeHeader ausblendenIdentitätIdentität-EinstellungenIgnorierenIgnoriere TeilthreadImport Newsrc...Im BereichSpoiler Zeichen einfügenItalienischHaltenHalte ArtikelHalte Artikel in ausgewählten GruppenHalte TeilthreadTastaturkürzelLöschenSpracheLetzter FehlerStarte externen EditorStarte externen _EditorLayoutBeschränke Anzahl von Artikel zum herunterladenListeScore des Autors verringernUntergrenzeVerringere ScoreKleiner alsMail-Copies-ToMail-Copies-To : HauptfensterVerwalte GruppenMarkiere alle Gruppen als gelesenMarkiere alle Gruppen als ungelesenMarkiere Artikel als gelesenMarkiere Artikel als ungelesenMarkiere Artikel zum HerunterladenMarkiere Gruppe ...Markiere Gruppe zum HerunterladenGelesen markierenMarkiere ausgewählte Gruppen als gelesenMarkiere ausgewählte Gruppen als ungelesenMarkiere Teilthread als gelesenMarkiere Teilthread als UngelesenMarkiere Teilthread zum HerunterladenUngelesen markierenZum Download markierenzutreffende RegelEntspricht RegExMaximale Anzahl von Artikel zum herunterladenMessage-IDMessage-ID Suche DialogSuche nach Message-IDMinuten zwischen HerunterladenVerschiedenesVerschiedenesKeine Konfigurationsdatei gefunden. Möchtest du XPN jetzt konfigurieren?ModusTastaturkürzel anpassen...Mehr HeaderNNTP-ServerNNTP-Server-AdresseNNTP-ServerNameName (für Mailantwort)NavigationNavigationNeue AktionNeue Scoring RegelNewsgruppenNewsgruppenNewsgruppen : Gruppenliste geladenNewsgruppen/AnNewsrc erfolgreich exportiertNewsrc erfolgreich importiertKeine FehlerKeine neuen HeaderKeine Verbindung zum Server: %s. Konfiguriere NNTP-Server oder versuche es später erneut.Keine Verbindung zu Server: %s. Konfiguriere SMTP-Server oder versuche es später erneut.Nicht grösser alsNicht kleiner alsAnzahlAnzahl der Tage. '0' bedeutet, das gelesene Artikel niemals entfernt werdenAnzahl der Tage. '0' bedeutet, das ungelesene Artikel niemals entfernt werdenODERArtikel mit einem Klick anzeigenGruppe mit einem Klick betretenEintastenlesenNach oben scrollenÖffne PostausgangsmanagerZusätzliche HeaderGeordnete ZeichensätzeGeordnete Liste (Editor)OrganisationOrganisation : Der Autor wünscht ein "Followup_to" nach %s. Soll dein Artikel in die originale Newsgroup (%s) gesendet werden?Der Autor hat ein "Followup_to: poster" gesetzt. Möchtest du per E-Mail antworten?Außerhalb des BereichsAusgangAusgehende ArtikelAusgehende E-MailsPostausgangPostausgangsmanagerPostausgangsfensterPasswortSuche während der EingabePersönliche InformationenBitte warten. Erstelle ThreadsGib den Identität-Name einGib den Server-Name einBitte warten, während die Liste heruntergeladen wirdPort NummerNeuen Artikel erstellenVersende neuen Artikel...EinstellungenEinstellungen...Bestätige mit OKFehler beim Löschen des Artikels: %sFehler beim Öffnen : Fehler beim Öffnen der E-Mail EntwürfeFehler beim Öffnen des Postausgangs (Mail)Fehler beim Öffnen der News EntwürfeFehler beim Öffnen des Postausgangs (News)Fehler beim Öffnen der gesendeten ArtikelFehler beim Öffnen der gesendeten E-MailsFehler beim Öffnen des Artikels auf:Fehler beim Öffnen des Ordners:Fehler beim Öffnen der E-Mail :KomprimierungseinstellungenGelesene Artikel aufräumen nach (Tagen)Ungelesene Artikel aufräumen nach (Tagen)Komprimiere Gruppe: %sZitatebene 1Zitatebene 2Zitatebene 3RegEx-TesterRot13 auf ausgewählten Text anwendenScore des Autors erhöhenErhöhe ScoreRegeln EinlesenNächster ArtikelNächsten ungelesenen ArtikelGehe zum InitialpostingVorheriger ArtikelReferencesGruppe: %s auffrischenRegulärer AusdruckMarkierte Identität löschenMarkierten Server löschenAntwort per E-Mail...MailantwortReply-ToReply-To : LadenLade Bodies für alle neuen ArtikelRegel zum Kombinieren der Suchergebnisse verwendenRegelnSMTP-ServerSMTP-Servername | PortArtikel als Entwurf speichernBereich/Score ModifikatorScoreScorefile EditorScoring RegelnRegeln für Scoring und Aktionen...Text scrollen (% der Seite)SucheGruppe suchenArtikel in der aktiven Gruppe suchenLokal in allen Gruppen suchenIm Body suchenSuche im Body...Bei Google Groups suchenSuche...Wähle HintergrundfarbeWähle Header-HintergrundfarbeWähle Header-VordergrundfarbeWähle Newsrc Export-PfadWähle Newsrc-DateiWähle Farbe für Zitatebene 1Wähle Farbe für Zitatebene 2Wähle Farbe für Zitatebene 3Wähle SignaturfarbeSignaturdatei auswählenWähle TextfarbeWähle Farbe für VerknüpfungenArtikel sendenArtikel später sendenSende Artikel _späterSende Artikel im PostausgangSende E-Mails im PostausgangSende E-Mails in WarteschlangeSender : Sende Artikel: Sende E-Mail: GesendetSende %d ArtikelSende %d E-MailsGesendete ArtikelGesendete E-MailsServerServer Fehler: Server LogsServerlog BetrachterServer Logs...Server EinstellungenServer Fehler: %sServer erfordert AnmeldungServersScore des Autors setzenDefiniere Standard ListeSetze ScoreEinfärbenTastenkürzelTastenkürzel DialogZeige alle gelesene ThreadsZeige Artikel mit Score<0Zeige Artikel mit Score=0Zeige Artikel mit Score>0Zeige FehlerZeige komplette ListeVersteckte Dateien anzeigenZeige ignorierte ArtikelZeige gehaltene ArtikelZeige zitierten TextZeige gelesene ArtikelZeige SignaturenZeige gespoilerten TextZeige ThreadsZeige Threads ohne beobachteten ArtikelnZeige nicht gehaltene ArtikelZeige ungelesene ArtikelZeige unbeobachtete, nicht ignorierte ArtikelZeige beobachtete ArtikelHeader ein/ausblendenAngezeigte HeaderSignaturSignaturSignaturdatei nicht gefundenLangsam (aber genau) neuer AlgorithmusSortierkriteriumSortieroptionenStandard HeaderAm Anfang beginnenStarte SucheSubjektSubjekt : Subjekt SpalteSubjekt: Abonniere manuellAbonniere ausgewählte GruppenAbonnierte GruppenAbonnierte _GruppenSupersede Artikel...Supersedes : Syntax Error: Fehlerhafte Zeile:: Syntax Error: Fehlerhafte Regel in Zeile:: Syntax Error: Fehlerhafter Scoremodifikator in Zeile:: Syntax Error: Fehlender Bereich in Zeile :: Syntax Error: Unbekannte Aktion in Zeile:: Syntax Error: Unbekannter Headername in Zeile:: Tagline hinzugefügtTagline Länge: Teste reguläre AusdrückeTest TextTextText oder regulärer AusdruckDas ist kein Problem, Tastenkürzel wird nur auf das aktive Fenster angewendetDer Groppenname scheint falsch zu seinNeue Artikel in beobachteten Threads vorhanden: Der Artikel ist auf dem Server nicht verfügbarDies kann einige Minuten dauernDieser Artikel ist ein Crosspost! Soll der Artikel nur in die originale Newsgroup (%s) gesendet werden?Dies ist der InitialartikelThreading MethodeThreadsThreadsansichtPosition des ThreadsexpandersAn : Damit die Datei 'newsrc' korrekt importiert werden kann, solltest du den gleichen Server eingeben, den du beim Speichern der Datei verwendet hast. Standartmäßig verwendet XPN den Namen wie: 'server_name.newsrc', so ist es möglich festzustellen, welcher Server benutzt wurde. Wenn du versuchst 'newsrc' zu importieren, wird XPN nach dem Servernamen in der Datei suchen. Verwende Server:Gib den Befehl zum Starten des Editors ein. '%s' definiert den Dateinamen. Beispiele: xterm -e vim %s gvim -f %s notepad.exe %s "C\Programme\Notepad++\Notepad++.exe" %s -nosession ACHTUNG: Diese Option funktioniert nur unter *nix und Windows.Gib deinen Tastenkürzel einGib den gewünschten Befehl ein, '%s' gibt die URL an. Beispiele: mozilla-firefox %s & opera %s & xterm -e links %sVerknüpfungenNicht haltenNicht zum Download markierenNeuEntferne Beobachten/IgnorierenBestelle ausgewählten Gruppen abNachricht senden nicht möglich. Kontrolliere Serverlogs.Unerwarteter Fehler im excepthook.ObergrenzeBenutzerspezifischer BefehlVerwende reguläre AusdrückeVerwende SSL (Secure Socket Layer)System-Schriften verwendenAbweichender Absender für Antworten per E-MailZufallsTagline verwendenBenutzerBenutzerprofilBenutzernameAnsichtZeige nächste GruppeZeige RohansichtDarstellungWarnungen:BeobachtenBeobachte TeilthreadInternet BrowserAufruf Internet BrowserFensterXPN EinstellungenXPN Tagline-ManagerXPN zeigt diese Header in der ArtikelansichtXPN verwendet die Zeichensätze in dieser Reihenfolge zur Kodierung deiner ArtikelXPN versucht die Zeichensätze in dieser Reihenfolge zu verwendenDu kannst Cancel/Supersede nur auf eigene Artikel anwendenDu kannst dein Glück bei Google versuchen:Du kannst hier einen FQDN (Fully Qualified Domain Name) angeben, der zum Erstellen der Message-ID verwendet wird. Wenn du das Feld leer lässt, verwendet XPN deinen Rechnernamen zur Generierung einer eindeutigen Message-ID.Du musst die Gruppenliste herunterladenXPN muss neu gestartet werden um die gewählte Sprache zu aktivierenArtikelansicht zoomenGruppenansicht zoomenHeaderansicht zoomenThreadsansicht zoomenGruppenansicht zoomen[Signatur ausgeblendet]_Artikel_Artikel_Lösche Artikel/E-Mail_Verwerfe Artikel_Verfasse Artikel/E-Mail_Beenden_Datei_Spoiler Zeichen einfügen_Navigation_Postausgang_ROT13 auf ausgewählten Text anwenden_Suche_Sende Artikel_Sende Artikel in Warteschlange_Ansichtpython %prog [-d] [-cCUSTOM_DIR] Mit den Kommandozeilenparametern lässt sich der Speicherort der Konfigurationsdateien und der Nachrichtendatenbank frei wählen. Wird kein Parameter angegeben, verwendet XPN das aktuelle Arbeitsverzeichnis. Mit dem Parameter '--home_dir', wird ein .xpn-Verzeichnis im Home-Verzeichnis angelegt,in dem alle Informationen und Daten gespeichert werden Über den Parameter '--custom_dir', wird das .xpn-Verzeichnis unterhalb des angegebenenbenutzerspezifischen Verzeichnisses erstellt. ACHTUNG: Wird der Parameter '--home_dir' verwendet, wird '--custom_dir' ignoriert (soferndiese gleichzeitig angegeben werden). Beispiele: python xpn.py python xpn.py -d python xpn.py --custom_dir /home/user/customZeile:%d, Spalte:%dGib ein existierendes Verzeichnis zum Speichern der Konfigurationsdateien und Artikel antags.txt nicht gefundenBenutze Home-Verzeichnis zum Speichern der Konfigurationsdateien und Artikelxpn-1.2.6/lang/fr/0000755000175000017500000000000011141275756012014 5ustar antantxpn-1.2.6/lang/fr/LC_MESSAGES/0000755000175000017500000000000011141275756013601 5ustar antantxpn-1.2.6/lang/fr/LC_MESSAGES/xpn.mo0000644000175000017500000011767011141275756014757 0ustar antant!-" -,- K-EY-- -7-*-#.*C.n.0.#. .(/+/G/]/a/g/p/ w// / //#//G/?0 ^0 j0u0}0 0 00000001#1=1 P1[1l1q11111111 22 2,2>2N2c2u222 222 333 3*3D3"_3333'3 34 4,4G4L4S4e4t4444#4@4#5:5N5W5j5/555 55566!*6 L6Y6 k6u666 6 666 6#7 '727:7 ?7J7]7v777 7777"8(898@8E8Y8m88 88/8.8"949 E9S9i9~99999999: :/&:.V:::: :::3::;,;.D;"s;$;; ;; ;; <<!<(< 7<D<X<_<g< v<!<< <<<<<<<== = %= 2=S=b=u=z= ====(=== > > >(>7> I> U>c>{>>>>>> ??-?L?c?|? ?? ? ?"? ??@-@G@ L@7Z@@@ @ @@ @@#@#A ,A7AGA XA cA nA|A AAA AAKAKg$_g$g!g%gg&h*hFhZh$phhhhhhhi i(&i>Oii-i ii*i8*j"cjjj jjjj5k6kIkek,zk%kkklll1l+Clol ll l$lll1l,mBmXmhm(m(mmmmnn0nJnbntn7n6nno1oFoao)|oooooppp/pDp=]p6p ppp pp#p8qTqoqExq>q<q7:rrrrrrrrrrr s#si '<!D(f@4Е (#;"_?$ߖ #59O cq"ח9QN@46;ޙId) ",H^z  ݛ !ўYBX_]lp3.td| [/Q6; 6S= 'LhP!3skYK$VIvyjKe4r-cA2R)EO?z:N aPM"^Qp)u U|e  R f(Zj_IT=1ga+n{bFGG\s^, OC ]Sr *x(X W0T#}0$wm}tzBHi/H<F@g 'J97% +L@_qE`~i9V*D-o:M!uZ82\xYk{C4.J8[5~ >7l&vD5"&`bm >n,qdX1BWU;cN<hwyf% #A?o Do you want to send the Article? Insert here a tagline Wrap column%s = Subject %g = Newsgroups %f = From %n = Nick %e = Email %d = Date%s response : %s%s selected* Article contains more than 95% of quoted text * Article doesn't contain new text * Article seems to be empty * From field appears to be invalid * From field is empty * Newsgroups field appears to be invalid * Newsgroups field is empty * Subject field is empty * To field appears to be invalid * To field is empty > [...Muted Quote...]ANDAboutAbout...ActionAdd ManuallyAdd RuleAdd a ServerAdd a TaglineAdd an IdentityAdvance to the Next Article on MarkAlways Use External EditorAn instance of XPN is already running. Do you want to open XPN anyway?Apply Scoring and Action RulesApproved : Archive : ArticleArticle DeletedArticle FoundArticle PaneArticle loadedArticlesArticles NumberArticles View OptionsAscending OrderAssign Identities to GroupsAttribution lineAutomatic Header DownloadAvailable CharsetsBackgroundBackground ColorBodyBuilding ArticlesBuilding Newsgroups listCancel Article Sent: Cancel Article...Case InsensitiveCase SensitiveChange ShortcutChange Signature PathCharset : CharsetsCharsets ListChoose the ServerClear ShortcutsClose Filter ToolbarClose this windowClose window and save settingsClose window. Discard changesClose window. Save ChangesCollapse AllCollapse All ThreadsCollapse Selected SubThreadColorColorsComposeConditionConfigure Display ProfileConfigure Group PropertiesConfigure Miscellaneous PropertiesConfigure Server ProfilesConfigure User ProfileConnection closedConnection estabilished with server: %sConnection estabilished with: %sContains StringCorrect RulesCustom Headers (X-Headers)DateDate: Default ShortcutsDelete ArticleDelete Article/MailDifferent From (numbers only)Discard ArticleDisplayDisplay Headers in the Article PaneDo you want to CANCEL this article? Subject: %s Message-ID: %sDoesn't Contain StringDoesn't Match RegExDownloadDownload CompletedDownload Headers automaticallyDownload this number of articles (headers only)Downloading Bodies for %sDraft ArticlesDraft MailsDraftsDuplicates ErrorsDuplicates WarningsE-Mail addressE-Mail address (for Mail replies)Edit ArticleEdit Article/MailEdit MailEdit Scoring and Action RulesEdit Selected IdentityEdit Selected ServerEdit WindowEmail SentEnglishEqual To (numbers only)Error DialogError while opening external editorErrors LogErrors:ExitExpand AllExpand All ThreadsExpand Group on EnteringExpand Headers RowExpand Selected SubThreadExport Newsrc...External AppsExternal EditorExternal Editor CommandFallback Charset (Reading)Fast (but imprecise) old AlgorithmFetching HeadersFieldsFileFile does not existFilter Articles ...Filter Articles by: Filter Articles...Find ArticleFind Article...First you have to configure at least one ServerFirst you have to create at least one IdentityFirst you have to read the articleFixed Pitch FontFlags & ScoreFocus to Article PaneFocus to Groups PaneFocus to Threads PaneFocus to groups PaneFolderFollow-Up To NewsgroupFollow-Up To Newsgroup...Followup-To : FontsFonts and ColorsForeground ColorFound %s tagsFound duplicated shortcuts on different windowsFound duplicated shortcuts on the same windowsFrenchFromFrom : From ColumnFrom: Fully Qualified Domain NameG: Groups Pane H: Headers Pane A: Article PaneGenerate Message-IDGermanGet Marked Article Bodies in Selected GroupsGet Marked Article Bodies in Subscribed GroupsGet New Headers in Selected GroupsGet New Headers in Subscribed GroupsGet Newsgroups ListGlobal SearchGlobal Search ...Greater ThanGroupGroup removedGroup subscribedGroupsGroups List...Groups ScopeGroups View OptionsHeaderHeadersHeaders ColorsHeaders ListHeaders Shown on the Article PaneHelpHide HeadersIdentityIdentity SettingsIgnoreIgnore SubThreadImport Newsrc...In RangeInsert Spoiler CharItalianKeepKeep ArticleKeep Articles in Selected GroupsKeep SubThreadKeyboard ShortcutsKillLanguageLast ErrorLaunch External EditorLaunch External _EditorLayoutLimit the number of articles to downloadListLower Author ScoreLower LimitLower ScoreLower ThanMail-Copies-ToMail-Copies-To : Main WindowManage GroupsMark All Groups as ReadMark All Groups as UnreadMark Article as ReadMark Article as UnReadMark Article for RetrievingMark Group ...Mark Group for RetrievingMark ReadMark Selected Groups as ReadMark Selected Groups as UnreadMark SubThread as ReadMark SubThread as UnReadMark SubThread for RetrievingMark UnreadMark for DownloadMatch RuleMatches RegExMax number of articles to downloadMessage-IDMessage-ID Search DialogMessage-ID to searchMinutes Between DownloadsMiscMiscellaneousMissing Config File. Do you want to Configure XPN now?ModeModify Keyboard Shortcuts...More HeadersNNTP ServerNNTP Server AddressNNTP ServersName or NickNameName or NickName (for Mail replies)NavigateNavigationNew Action RuleNew Scoring RuleNewsGroupsNewsgroupsNewsgroups : Newsgroups list loadedNewsgroups/ToNewsrc successful exportedNewsrc successful importedNo ErrorsNo New HeadersNo connection with server : %s. Configure NNTP Server Address or try later.No connection with server : %s. Configure SMTP Server Address or try later.Not Greater ThanNot Lower ThanNumberNumber of days. '0' means never purge read articlesNumber of days. '0' means never purge unread articlesOROne Click Enter ArticleOne Click Enter GroupOne-Key ReadingOne-Key Scroll UpOpen Outbox ManagerOptional HeadersOrdered CharsetsOrdered List (Writing)OrganizationOrganization : Original Poster set "Followup_to" on %s, Do you want to send your article on the original newsgroup (%s) ?Original Poster set "Followup_to: poster", Do you want to reply by mail ?Out Of RangeOutBoxOutGoing ArticlesOutGoing MailsOutboxOutbox ManagerOutbox WindowPasswordPerform Live SearchPersonal InformationsPlease Wait. Building ThreadsPlease set the Identity NamePlease set the Server NamePlease wait, I'm downloading the listPort NumberPost New ArticlePost New Article...PreferencesPreferences...Press OK to confirm itProblems while deleting the article: %sProblems while opening : Problems while opening Mail DraftsProblems while opening Mail OutBoxProblems while opening News DraftsProblems while opening News OutBoxProblems while opening Sent ArticlesProblems while opening Sent MailsProblems while opening article :Problems while opening folder :Problems while opening mail :Purge OptionsPurge read articles after (days)Purge unread articles after (days)Purging Group: %sQuote Level 1Quote Level 2Quote Level 3RE TesterROT13 Selected TextRaise Author ScoreRaise ScoreReScan RulesRead Next ArticleRead Next Unread ArticleRead Parent ArticleRead Previous ArticleReferencesRefreshing Group %sRegular ExpressionRemove Selected IdentityRemove Selected ServerReply By Mail...Reply by MailReply-ToReply-To : RetrieveRetrieve Bodies for all new articlesRule used to combine search resultsRulesSMTP ServerSMTP Server Address | Port NumberSave Article as DraftScope/Score ModScoreScore File EditorScoring RulesScoring and Action Rules...Scroll Text (% of page)SearchSearch GroupSearch in current groupSearch in subscribed groupsSearch in the BodySearch in the Body...Search on GoogleSearching...Select Background ColorSelect Headers Background ColorSelect Headers Foreground ColorSelect Newsrc Export PathSelect Newsrc FileSelect Quote Level 1 ColorSelect Quote Level 2 ColorSelect Quote Level 3 ColorSelect Sign ColorSelect Signature FileSelect Text ColorSelect URL ColorSend ArticleSend Article LaterSend Article _LaterSend Queued ArticlesSend Queued MailsSend Queued _MailsSender : Sending Article: Sending Mail: SentSent %d ArticlesSent %d MailsSent ArticlesSent MailsServerServer Error: Server LogsServer Logs ViewerServer Logs...Server SettingsServer error: %sServer requires authenticationServersSet Author ScoreSet Default ListSet ScoreSetColorShortcutShortcut DialogShow All Read ThreadsShow Articles with Score<0Show Articles with Score=0Show Articles with Score>0Show ErrorsShow Full ListShow Hidden FilesShow Ignored ArticlesShow Kept ArticlesShow Quoted TextShow Read ArticlesShow SignaturesShow Spoilered TextShow ThreadsShow Threads Without Watched ArticlesShow UnKept ArticlesShow UnRead ArticlesShow UnWatched/UnIgnored ArticlesShow Watched ArticlesShow/Hide HeadersShown HeadersSignSignatureSignature file not foundSlow (but precise) new AlgorithmSorting ColumnSorting OptionsStandard HeadersStart from the BeginningStart searchingSubjectSubject : Subject ColumnSubject: Subscribe ManuallySubscribe selected groupsSubscribed GroupsSubscribed _GroupsSupersede Article...Supersedes : Syntax Error: Bad Line:: Syntax Error: Bad Match Rule on line:: Syntax Error: Bad Score Modifier on line:: Syntax Error: Missing scope for line :: Syntax Error: Unknown Action on line:: Syntax Error: Unknown Header Name on line:: TagLine AddedTagLine length: Test Regular ExpressionTest TextTextText or Regular ExpressionThat's not a problem, the shortcut will work only on the active window The Group Name seems to be wrongThere are new articles in watched threads: This article is not available on the serverThis could take several minutesThis is a crosspost! Do you want to send the article only on the original newsgroup (%s) ?This is root articleThreading MethodThreadsThreads PaneThreads expander positionTo : To correctly import a newsrc file you have to use the same server you used when you saved the file. By default XPN uses a name like 'server_name.newsrc' so it is possible to know wich server was used When you try to import a newsrc file XPN searches for the server name in the file name. Server To Use:Type the editor launcher, %s represents the filename. Examples: xterm -e vim %s gvim -f %s notepad.exe %s "C:\Program Files\Notepad++\Notepad++.exe" %s -nosession NOTE: This feature works only with *Nix and Windows systemsType your ShortcutType your custom command, %s represents the url. Examples: mozilla %s & xterm -e links %sURLUnKeepUnMark for DownloadUnReadUnSetWatchIgnoreUnSubscribe selected groupsUnable to send the message. Control Server Logs.Unexpected error in the excepthook.Upper LimitUse Custom Web Browser LauncherUse Regular ExpressionUse SSL (Secure Socket Layer)Use System FontsUse different From field in mail repliesUse random taglinesUserUser ProfileUsernameViewView Next GroupView Raw ArticleVisualizationWarnings:WatchWatch SubThreadWeb BrowserWeb Browser LauncherWindowXPN PreferencesXPN TagLines ManagerXPN will show these headers on the top of the Article PaneXPN will try to encode your articles with these charsets in this orderXPN will try to use the charsets in this orderYou can Cancel/Supersede only your articlesYou can try on Google:You can write here a FQDN (Fully Qualified Domain Name) that will be used to compose the Message-ID. Otherwise if you leave this field blank XPN will use your Host Name.You have to download newsgroups listYou must restart XPN in order to get the translation activeZoom Article PaneZoom Groups PaneZoom Headers PaneZoom Threads PaneZoom groups Pane[...Muted Sign...]_Article_Articles_Delete Article/Mail_Discard Article_Edit Article/Mail_Exit_File_Insert Spoiler Char_Navigate_Outbox_ROT13 Selected Text_Search_Send Article_Send Queued Articles_Viewpython %prog [-d] [-cCUSTOM_DIR] With command line options you can decide where XPN will save config files and articles. If you don't use any option, the current working directory will be used. If you use the '--home_dir' option, XPN will create a .xpn directory inside your home directory, and will store informations inside that directory. If you use the '--custom_dir' option, XPN will create a .xpn directory inside that custom_directory. NOTE: If you set the '--home_dir' option, XPN will ignore the '--custom_dir' option (if you used it). Examples: python xpn.py python xpn.py -d python xpn.py --custom_dir /home/user/customrow:%d, col:%dspecify an existing directory where store config files and articlestags.txt not founduse home directory to store config files and articlesProject-Id-Version: xpn - fr Report-Msgid-Bugs-To: POT-Creation-Date: 2009-01-29 09:20+0100 PO-Revision-Date: 2009-02-01 10:16+0100 Last-Translator: Nemesis Language-Team: French MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Voulez-vous envoyer l'article? Insert ici une ligne d'étiquette. Couper à la colonne%s = Sujet %g = Forum %f = De %n = Surnom %e = Adresse de courriel %d = Date%s Réponse de : %s%s sélectionné* L'Article contient plus de 95% de texte cité * L'Article ne contient pas de nouveau texte * L'Article est vide *·Le champ De·: est invalide * Le champ De est vide * Le champ Newsgroups est invalide * Le champ Forums est vide *·Le champ Subject·est vide *·Le champ A·est invalide * Le champ A est vide > [...Citation cachée...]ETA proposA propos...ActionAjouter manuellementAjouter une règleAjouter un serveurAjouter une étiquetteAjouter une identitéAvancer au prochain article marquéToujours utiliser l'éditeur externeUne instance de XPN est déjà en cours d'excécution. Voulez-vous lancer XPN quand même ?Appliquer les règles de notation et d'actionApprouvé : Archive : ArticleArticle effacéArticle trouvéCadre de l'articleArticle chargéArticlesNombre d'articlesOptions de visualisation des articlesTri croissantAssigner les identités aux forumsLigne d'attributionTéléchargement automatique des entêtesJeux de caractères disponiblesFondCouleur de fondCorpsConstruction des articlesContruction de la liste des forumsArticle d'annulation envoyé: Annuler l'ArticleInsensible à la casseSensible à la casseModifier le raccourcisModifier le chemin de la signatureJeux de caractères : Jeux de caractèresJeux de caractèresChoisissez le serveurEffacer les racourcis clavierFermer la barre d'outils filtreFermer cette fenêtreFermer la fenêtre et enregistrer les paramètresFermer la fenêtre et abandonner les paramètresFermer la fenêtre. Enregistrer les changements.Replier toutReplier tous les fils de discussionReplier le sous-fil de discussion sélectionnéCouleurCouleursComposerConditionConfigurer le profil d'affichageConfigurer les propriétés du forumConfigurer les propriétés diversesConfigurer le profil des serveursConfigurer le profil de l'utilisateurConnexion ferméeConnexion établie avec le serveur: %sConnexion établie avec: %sContient la chaîneRègles de correctionEn-têtes personnalisés (X-Headers)DateDate: Racourcis clavier par défautEffacer l'articleEffacer l'article/courrielEst différent de (Nombre)Abandonner l'articleAffichageAffiche l'en-tête dans le cadre ArticleVoulez-vous annuler cet article? Sujet: %s ID de Message: %sNe contient pas la chaîneNe correspond pas à l'expression régulièreTéléchargerTéléchargement terminéTélécharger les entêtes automatiquementTélécharger ce nombre d'articles (en-têtes seulement)Téléchargement des corps pour %sBrouillons d'articlesBrouillons de courriersBrouillonsErreur: duppliquéAvertissement: duppliquéAdresse de courrielAdresse de courriel (pour les réponses par courriel)Modifier l'articleModifier l'article/courrielModifier le courrielMofidier les règles de notation et d'actionEdition de l'identité sélectionnéeEditer le serveur sélectionnéFenêtre d'éditionCourriel envoyéAnglaisEst égale à (Nombre)Fenêtre d'ErreurErreur à l'ouverture de l'éditeur externeJournal d'erreursErreurs :QuitterDéplier toutDéplier tous les fils de discussionDéplier les fils en entrantAfficher les en-têtes_Déplier le sous-fil de discussion sélectionnéExporter en Newsrc...Applications externesEditeur externeCommande de l'éditeur externeJeu de caractères par défaut (Lecture)Ancien algorithme, rapide mais imprécisRécupération des en-têtesChampsFichierLe fichier n'existe pasFiltre articles...Filtrer les articles par:Filtrer les articles...Trouver l'articleRechercher un article...Premièrement vous devez configurer au moins un ServeurPremièrement vous devez créer au moins une IdentitéVous devez lire l'article avantFonte à chasse fixeDrapeaux et NotationFocus sur le cadre articleFocus sur le cadre groupesFocus sur le cadre des fils de discussionFocus sur le cadre groupesDossierFaire suivre sur le forumFaire suivre sur le forum...Faire suivre sur : FontesPolices et CouleursCouleur d'avant plan%s étiquettes trouvéesRaccourcis clavier duppliqués vers des fenêtres différenteRaccourcis clavier duppliqués vers une même fenêtreFrançaisDeDe : From colonneDe: Nom de Domaine Pleinement QualifiéG: Cadre Forums H: Cadre En-têtes A: Cadre ArticleGénérer un ID de messageAllemandRécupérer les corps des messages marqués des forums sélectionnésRécupérer le corps des articles marqués des forums abonnésRécupérer les nouveaux en-têtes des forums sélectionnésRécupérer les nouveaux _en-têtes des forums abonnésRécupérer la liste des forumsRecherche globaleRecherche globale ...Plus grand queForumForum suppriméAbonnement au forumForumsListe des ForumsForums ScopeOptions de visualisation des forumsEn-têteEn-têtesCouleurs des en-têtesListe des en-têtesEn-têtes affichées dans le cadre de l'articleAideCacher les en-têtesIdentitéParamètres de l'identitéIgnorerIgnorer la suite du fil de discussionImporter un Newsrc...Dans la fourchetteInsérer un caractère cachéItalienGarderGarder l'articleGarder les articles des forums sélectionnésGarder le sous filRacourcis clavierTuerLangageDernière erreurLancer l'éditeur externeLancer l'éditeur _externeDispositionLimitation du nombre d'articles à téléchargerListeDiminuer la notation de l'auteurLimite basseDiminuer la notationPlus petit queCopie-Courrier-ÀCopie-Courrier-À : Fenêtre principaleGérer les forumsMarquer tout comme luMarquer tous les groupes comme non lusMarquer l'article comme luMarquer l'article comme non-luMarquer l'article pour la récupérationMarquer le forum...Marquer le forum pour la récupérationMarquer comme luMarquer les forums sélectionnés comme lusMarquer les forums sélectionnés comme non lusMarquer le fil comme luMarquer le sous-fil comme non-luMarquer le fil de discussion pour la récupérationMarquer comme non-luMarquer pour le téléchargementRègle de concordanceCorrespond à l'expression régulièreNombre max d'articles à téléchargerID de MessageRecherche de Message-IDMessage-ID à rechercherMinutes entre chargementsDiversDiversLe fichier de configuration est manquant. Voulez-vous configurer XPN maintenant ?ModeModifier les racourcis clavier...Plus d'en-têtesServeur NNTPAdresse du serveur NNTPServeurs NNTPNom ou SurnomNom ou Surnom (pour les réponses par courriel)NaviguerNavigationNouvelle règle d'actionNouvelle règle de notationForumsForumsForums : La liste des forums est chargée.Forums/AL'export du Newsrc a réussiL'import du fichier Newsrc a réussiPas d'erreurPas de nouveaux en-têtesPas de connexion au serveur : %s. Configurez l'adresse du serveur NNTP ou réessayez plus tard.Pas de connexion au serveur : %s. Configurez le serveur SMTP ou réessayez plus tard.Pas plus grand quePas plus petit queNombreNombre de jours. '0' signifie ne jamais purger les articles lusNombre de jours. '0' signifie ne jamais purger les articles non-lusOUUn clic ouvre l'articleUn clic ouvre le forumDéfilement basDéfilement hautOuvrir le gestionnaire de boites d'envoiEn-têtes optionnelsJeux de caractères sélectionnésListe personnalisée (Ecriture)OrganisationOrganisation : L'auteur de l'article a défini "Faire suivre sur " %s, Voulez-vous envoyer l'article sur le forum d'origine (%s) ?L'expéditeur originel a défini "Faire suivre à : poster", Voulez-vous répondre par courriel ?En dehors de la plageBoite d'envoiArticles sortantsCourriers sortantsBoite d'envoiGestionnaire des boites d'envoiBoite d'envoiMot de passeFaire une recherche dynamiqueInformations personnellesPatientez. Construction des fils de discussionIndiquez le nom de d'identité.Entrez le nom du serveurVeuillez patienter. Téléchargement de la liste.Numéro de portEnvoyer un nouvel articleEnvoyer un nouvel article...PréférencesPréférences...Appuyez sur OK pour confirmerProblèmes à l'effacement de l'article : %sProblèmes à l'ouverture :Problèmes à l'ouverture des brouillons de courrielsProblèmes à l'ouverture de la boite d'envoi des courrielsProblèmes à l'ouverture des brouillons d'articlesProblèmes à l'ouverture de la boite d'envoi Problèmes à l'ouverture des articles envoyésProblèmes à l'ouverture des courriels envoyésProblèmes à l'ouverture de l'article :Problèmes à l'ouverture du dossier :Problèmes à l'ouverture du courriel :Options de purgePurger les articles lus après (jours)Purger les articles non-lus après (jours)Purge du forum: %sCitation de niveau 1Citation de niveau 2Citation de niveau 3RE TesteurTexte sélectionné en ROT13Augmenter la notation de l'auteurAugmenter la notationRelire les règlesLire l'article suivantLire le prochain article non-luLire le prochain article parentLire l'article précédentRéférencesRafraîchissement du forum: %sExpression régulièreSupprimer l'identité sélectionnéeSupprimer le serveur sélectionnéRépondre par courriel...Répondre par courrielRépondre-àRépondre-à : RécupérerRécupérer les corps pour tous les nouveaux articlesRègle utilisée pour combiner les résultats de la rechercheRèglesServeur SMTPAdresse du serveur | N° de portSauver l'article comme brouillonModule de portée/notationNotationEditeur de fichier de notationRègles de notationRègles de notation et d'action...Défilement du texte (% de la page)RechercheRecherche parmi les forumsRecherche dans le forum courantRecherche dans les forums abonnésRechercher dans le corpsRecherche dans le corps...Recherche sur GoogleRecherche...Sélectionnez la couleur du fondSélectionnez la couleur du fond des en-têtesSélectionnez la couleur du fond des en-têtesSélectionnez le chemin d'export des NewsrcSélectionnez le fichier NewsrcSélectionnez la couleur des citations de niveau 1Sélectionnez la couleur des citations de niveau 2Sélectionnez la couleur des citations de niveau 3Sélectionnez la couleur de la signatureSélectionnez le fichier de signatureSélectionnez la couleur du texteSélectionnez la couleur des URLEnvoyer l'articleEnvoyer l'article plus tardEnvoyer l'article plus tardEnvoyer les articles en attenteEnvoyer les courriels en attente_Envoyer les courriels en attenteExpéditeur : Envoie l'article: Envoie le courriel : Envoyé%d articles envoyés%d courriels envoyésArticles envoyésCourriels envoyésServeurErreur serveur: Journaux serveurVisualisateur de journaux serveurJournaux serveur...Paramètres du serveurErreur serveur: %sLe serveur requiert une authentificationServeursDéfinir la notation de l'auteurDéfinir la liste par défautDéfinir une notationChoisir la couleurRacourcisFenêtre raccourcis clavierMontrer les fils lusMontrer les articles de notation<0Montrer les articles de notation=0Montrer les articles de notation>0Montrer les erreursMontrer la liste complèteMontrer les fichiers cachésMontrer les articles ignorésMontrer les articles conservésMontrer le texte citéMontrer les articles lusMontrer les signaturesMontrer le texte cachéMontrer les filsMontrer les fils sans articles vusMontrer les articles non conservésMontrer les articles non-lusMontrer les articles non vus/non ignorésMontrer les articles vusMontrer/Cacher les entêtesMontrer les en-têtesSignatureSignatureFicher de signature non trouvéNouvel algorithme, lent mais précisColonne de triOptions de triEn-têtes standardesCommencer depuis le débutCommence la rechercheSujetSujet : Sujet colonneSujet: S'abonner manuellementS'abonner aux forums sélectionnésForums abonnésForums abonnésRemplacer l'article...Remplace : Erreur de syntaxe: Mauvaise ligne:: Erreur de syntaxe: Mauvaise règle de concordance à la ligne:: Erreur de syntaxe: Mauvais modifieur de notation à la ligne:: Erreur de syntaxe: Portée manquante pour la ligne :: Erreur de syntaxe: Action inconnue à la ligne:: Erreur de syntaxe: Nom d'entête inconnu à la ligne:: Etiquette ajoutéeLongueur de l'étiquette: Tester l'expression régulièreTexte de testTexteTexte ou expression régulièreCe n'est pas un problème, le racourcis fonctionnera seulement sur la fenêtre activeLe nom du forum a l'air mauvaisIl y des nouveaux articles dans les fils suivis: Cet article n'est pas disponible sur le serveurCeci peut prendre plusieurs minutesCeci est un envoi croisé ! Voulez-vous envoyer l'article uniquement sur le forum d'origine (%s) ?Ceci est l'article racineMéthode d'enfiladeFils de discussionCadre des fils de discussionPosition de déroulement du filTo : Pour importer un fichier 'newsrc', vous devez utiliser le même serveur que celui utilisé lors de la sauvegarde du fichier. Par défaut XPN utilise un nom comme 'nom_du_serveur.newsrc' pour le nom du fichier newsrc. Quand vous voulez importer un fichier newsrc, regardez quel est le nom du serveur contenu dans le nom du fichier. Serveur à utiliser:Entrez la commande pour lancer l'éditeur, %s représente le nom du fichier. Exemples: xterm -e vim %s gvim -f %s notepad.exe %s NB: Cette fonctionnalité est disponible uniquement sur les systèmes *Nix et WindowsTapez votre racourcisEntrez votre commande personnalisée, %s représente l'adresse. Exemples: mozilla %s & xterm -e links %sURLNe pas garderNe pas marquer pour le téléchargementNon-lusNe pas voir les articles ignorésSe désabonner des forums sélectionnésImpossible d'envoyer le message. Vérifiez les journaux serveur.Erreur inattendue dans le gestionnaire d'exceptions.Limite hauteUtiliser un navigateur web personnaliséUtiliser une expression régulièreUtiliser SSL (Secure Socket Layer)Utiliser les fontes systèmeUtiliser un champ De différent dans les réponses par courrielUtiliser des étiquettes aléatoiresUtilisateurProfil utilisateurNom d'utilisateurVueVoir le forum suivantVoir l'article brutVisualisationAvertissements:RegarderVoir la suite du fil de discussionNavigateur webCommande du navigateur webFenêtrePréférences de XPNGestionnaire d'étiquettes XPNXPN affichera ces en-têtes en haut du cadre de l'articleXPN va essayer d'encoder vos articles avec ces jeux de caractères dans cet ordreXPN va essayer d'utiliser les jeux de caractères dans cet ordreVous pouvez Annuler/Remplacer seulement vos articlesVous pouvez essayer sur Google:Vous pouvez spécifier un FQDN (nom de domaine pleinement qualifié) qui sera utilisé pour créer les ID de message. Si ce champ est vide, XPN utilise le nom d'hôte.Vous devez télécharger la liste des forums de discussion.XPN doit être relancé pour que cette modification soit prise en compte.Zoomer sur le cadre articleZoomer sur le cadre groupesZoomer sur le cadre en-têtesZomer sur le cadre des fils de discussionZoomer sur le cadre groupes[...Signature Muette...]_Article_Articles_Effacer l'article/courrier_Abandonner l'articleModifier l'article/courriel_Quitter_Fichier_Insérer du texte caché_Naviguer_Boite d'envoiTexte sélectionné en _ROT13_Recherche_Envoyer l'article_Envoyer les articles en attente_Vuepython %prog [-d] [-cCUSTOM_DIR] Grâce aux options de la ligne de commande, vous pouvez décider où XPN enregistre ses fichiers de configuration et les articles. Sans option, le répertoire courant est utilisé. Si l'option '--home_dir' est utilisée, XPN crée un dossier '.xpn' dans le dossier utilisateur, et stocke les informations dans ce dossier. Avec l'option '--custom_dir', XPN crée un dossier'.xpn' dans le dossier passé en option pour y stocker ses fichiers. NOTE: Si l'option '--home_dir' est utilisée en même temps que l'option '--custom_dir', XPN ignore l'option '--custom_dir'. Exemples: python xpn.py python xpn.py -d python xpn.py --custom_dir /home/user/customligne: %d, colonne: %dspécifier un dossier existant pour stocker les fichiers de configuration et les articlesFichier tags.txt non trouvéutiliser le dossier personnel pour stocker les fichiers de configuration et les articlesxpn-1.2.6/lang/it/0000755000175000017500000000000011141275756012021 5ustar antantxpn-1.2.6/lang/it/LC_MESSAGES/0000755000175000017500000000000011141275756013606 5ustar antantxpn-1.2.6/lang/it/LC_MESSAGES/xpn.mo0000644000175000017500000011535211141275756014757 0ustar antant!-" -,- K-EY-- -7-*-#.*C.n.0.#. .(/+/G/]/a/g/p/ w// / //#//G/?0 ^0 j0u0}0 0 00000001#1=1 P1[1l1q11111111 22 2,2>2N2c2u222 222 333 3*3D3"_3333'3 34 4,4G4L4S4e4t4444#4@4#5:5N5W5j5/555 55566!*6 L6Y6 k6u666 6 666 6#7 '727:7 ?7J7]7v777 7777"8(898@8E8Y8m88 88/8.8"949 E9S9i9~99999999: :/&:.V:::: :::3::;,;.D;"s;$;; ;; ;; <<!<(< 7<D<X<_<g< v<!<< <<<<<<<== = %= 2=S=b=u=z= ====(=== > > >(>7> I> U>c>{>>>>>> ??-?L?c?|? ?? ? ?"? ??@-@G@ L@7Z@@@ @ @@ @@#@#A ,A7AGA XA cA nA|A AAA AAKAKo-,p.Zpppp ppppppqq-q4q;qOq*bqqq qqqqq qr$r-r6r,Jrwrrr r rrrr)r$s *sKs\s qs{sssss#st t @t at%ntt%t)tt#u$9u^usuuu'u u"uv.vDv Iv;Wvv&vv v v vvw "w .w:wQwiwpw www wwwwwt xtxx yyQyUkyy#y"y zz'zBzSzdz zzmzZ {h{x{{{{{{{{|%'|M|l|"|||| | ||&}=}4U}2}4}2}'%~+M~y~ ~~~#~#2L`t1&7^u π "4 =I*Q4| 'ā &0I%]& ׂ(=*Q |%à ܃ ?Rev!ׄ $.H_gz Å!҅#4X _ ņ(ц:Zl͇ " *&8_~*Èۈ.+Z s ȉ މ !5+J v!@C@+3l3ԋ)/PL'0Ō-*$UO؍#4SL[b$Ր ,<F:7ϑ#A2W ’Ғ  4@\et>^͓5,7b"c.%"ە$"#"Fi ֖ܖ 2#V\lW/M]lp3.td| [/Q6; 6S= 'LhP!3skYK$VIvyjKe4r-cA2R)EO?z:N aPM"^Qp)u U|e  R f(Zj_IT=1ga+n{bFGG\s^, OC ]Sr *x(X W0T#}0$wm}tzBHi/H<F@g 'J97% +L@_qE`~i9V*D-o:M!uZ82\xYk{C4.J8[5~ >7l&vD5"&`bm >n,qdX1BWU;cN<hwyf% #A?o Do you want to send the Article? Insert here a tagline Wrap column%s = Subject %g = Newsgroups %f = From %n = Nick %e = Email %d = Date%s response : %s%s selected* Article contains more than 95% of quoted text * Article doesn't contain new text * Article seems to be empty * From field appears to be invalid * From field is empty * Newsgroups field appears to be invalid * Newsgroups field is empty * Subject field is empty * To field appears to be invalid * To field is empty > [...Muted Quote...]ANDAboutAbout...ActionAdd ManuallyAdd RuleAdd a ServerAdd a TaglineAdd an IdentityAdvance to the Next Article on MarkAlways Use External EditorAn instance of XPN is already running. Do you want to open XPN anyway?Apply Scoring and Action RulesApproved : Archive : ArticleArticle DeletedArticle FoundArticle PaneArticle loadedArticlesArticles NumberArticles View OptionsAscending OrderAssign Identities to GroupsAttribution lineAutomatic Header DownloadAvailable CharsetsBackgroundBackground ColorBodyBuilding ArticlesBuilding Newsgroups listCancel Article Sent: Cancel Article...Case InsensitiveCase SensitiveChange ShortcutChange Signature PathCharset : CharsetsCharsets ListChoose the ServerClear ShortcutsClose Filter ToolbarClose this windowClose window and save settingsClose window. Discard changesClose window. Save ChangesCollapse AllCollapse All ThreadsCollapse Selected SubThreadColorColorsComposeConditionConfigure Display ProfileConfigure Group PropertiesConfigure Miscellaneous PropertiesConfigure Server ProfilesConfigure User ProfileConnection closedConnection estabilished with server: %sConnection estabilished with: %sContains StringCorrect RulesCustom Headers (X-Headers)DateDate: Default ShortcutsDelete ArticleDelete Article/MailDifferent From (numbers only)Discard ArticleDisplayDisplay Headers in the Article PaneDo you want to CANCEL this article? Subject: %s Message-ID: %sDoesn't Contain StringDoesn't Match RegExDownloadDownload CompletedDownload Headers automaticallyDownload this number of articles (headers only)Downloading Bodies for %sDraft ArticlesDraft MailsDraftsDuplicates ErrorsDuplicates WarningsE-Mail addressE-Mail address (for Mail replies)Edit ArticleEdit Article/MailEdit MailEdit Scoring and Action RulesEdit Selected IdentityEdit Selected ServerEdit WindowEmail SentEnglishEqual To (numbers only)Error DialogError while opening external editorErrors LogErrors:ExitExpand AllExpand All ThreadsExpand Group on EnteringExpand Headers RowExpand Selected SubThreadExport Newsrc...External AppsExternal EditorExternal Editor CommandFallback Charset (Reading)Fast (but imprecise) old AlgorithmFetching HeadersFieldsFileFile does not existFilter Articles ...Filter Articles by: Filter Articles...Find ArticleFind Article...First you have to configure at least one ServerFirst you have to create at least one IdentityFirst you have to read the articleFixed Pitch FontFlags & ScoreFocus to Article PaneFocus to Groups PaneFocus to Threads PaneFocus to groups PaneFolderFollow-Up To NewsgroupFollow-Up To Newsgroup...Followup-To : FontsFonts and ColorsForeground ColorFound %s tagsFound duplicated shortcuts on different windowsFound duplicated shortcuts on the same windowsFrenchFromFrom : From ColumnFrom: Fully Qualified Domain NameG: Groups Pane H: Headers Pane A: Article PaneGenerate Message-IDGermanGet Marked Article Bodies in Selected GroupsGet Marked Article Bodies in Subscribed GroupsGet New Headers in Selected GroupsGet New Headers in Subscribed GroupsGet Newsgroups ListGlobal SearchGlobal Search ...Greater ThanGroupGroup removedGroup subscribedGroupsGroups List...Groups ScopeGroups View OptionsHeaderHeadersHeaders ColorsHeaders ListHeaders Shown on the Article PaneHelpHide HeadersIdentityIdentity SettingsIgnoreIgnore SubThreadImport Newsrc...In RangeInsert Spoiler CharItalianKeepKeep ArticleKeep Articles in Selected GroupsKeep SubThreadKeyboard ShortcutsKillLanguageLast ErrorLaunch External EditorLaunch External _EditorLayoutLimit the number of articles to downloadListLower Author ScoreLower LimitLower ScoreLower ThanMail-Copies-ToMail-Copies-To : Main WindowManage GroupsMark All Groups as ReadMark All Groups as UnreadMark Article as ReadMark Article as UnReadMark Article for RetrievingMark Group ...Mark Group for RetrievingMark ReadMark Selected Groups as ReadMark Selected Groups as UnreadMark SubThread as ReadMark SubThread as UnReadMark SubThread for RetrievingMark UnreadMark for DownloadMatch RuleMatches RegExMax number of articles to downloadMessage-IDMessage-ID Search DialogMessage-ID to searchMinutes Between DownloadsMiscMiscellaneousMissing Config File. Do you want to Configure XPN now?ModeModify Keyboard Shortcuts...More HeadersNNTP ServerNNTP Server AddressNNTP ServersName or NickNameName or NickName (for Mail replies)NavigateNavigationNew Action RuleNew Scoring RuleNewsGroupsNewsgroupsNewsgroups : Newsgroups list loadedNewsgroups/ToNewsrc successful exportedNewsrc successful importedNo ErrorsNo New HeadersNo connection with server : %s. Configure NNTP Server Address or try later.No connection with server : %s. Configure SMTP Server Address or try later.Not Greater ThanNot Lower ThanNumberNumber of days. '0' means never purge read articlesNumber of days. '0' means never purge unread articlesOROne Click Enter ArticleOne Click Enter GroupOne-Key ReadingOne-Key Scroll UpOpen Outbox ManagerOptional HeadersOrdered CharsetsOrdered List (Writing)OrganizationOrganization : Original Poster set "Followup_to" on %s, Do you want to send your article on the original newsgroup (%s) ?Original Poster set "Followup_to: poster", Do you want to reply by mail ?Out Of RangeOutBoxOutGoing ArticlesOutGoing MailsOutboxOutbox ManagerOutbox WindowPasswordPerform Live SearchPersonal InformationsPlease Wait. Building ThreadsPlease set the Identity NamePlease set the Server NamePlease wait, I'm downloading the listPort NumberPost New ArticlePost New Article...PreferencesPreferences...Press OK to confirm itProblems while deleting the article: %sProblems while opening : Problems while opening Mail DraftsProblems while opening Mail OutBoxProblems while opening News DraftsProblems while opening News OutBoxProblems while opening Sent ArticlesProblems while opening Sent MailsProblems while opening article :Problems while opening folder :Problems while opening mail :Purge OptionsPurge read articles after (days)Purge unread articles after (days)Purging Group: %sQuote Level 1Quote Level 2Quote Level 3RE TesterROT13 Selected TextRaise Author ScoreRaise ScoreReScan RulesRead Next ArticleRead Next Unread ArticleRead Parent ArticleRead Previous ArticleReferencesRefreshing Group %sRegular ExpressionRemove Selected IdentityRemove Selected ServerReply By Mail...Reply by MailReply-ToReply-To : RetrieveRetrieve Bodies for all new articlesRule used to combine search resultsRulesSMTP ServerSMTP Server Address | Port NumberSave Article as DraftScope/Score ModScoreScore File EditorScoring RulesScoring and Action Rules...Scroll Text (% of page)SearchSearch GroupSearch in current groupSearch in subscribed groupsSearch in the BodySearch in the Body...Search on GoogleSearching...Select Background ColorSelect Headers Background ColorSelect Headers Foreground ColorSelect Newsrc Export PathSelect Newsrc FileSelect Quote Level 1 ColorSelect Quote Level 2 ColorSelect Quote Level 3 ColorSelect Sign ColorSelect Signature FileSelect Text ColorSelect URL ColorSend ArticleSend Article LaterSend Article _LaterSend Queued ArticlesSend Queued MailsSend Queued _MailsSender : Sending Article: Sending Mail: SentSent %d ArticlesSent %d MailsSent ArticlesSent MailsServerServer Error: Server LogsServer Logs ViewerServer Logs...Server SettingsServer error: %sServer requires authenticationServersSet Author ScoreSet Default ListSet ScoreSetColorShortcutShortcut DialogShow All Read ThreadsShow Articles with Score<0Show Articles with Score=0Show Articles with Score>0Show ErrorsShow Full ListShow Hidden FilesShow Ignored ArticlesShow Kept ArticlesShow Quoted TextShow Read ArticlesShow SignaturesShow Spoilered TextShow ThreadsShow Threads Without Watched ArticlesShow UnKept ArticlesShow UnRead ArticlesShow UnWatched/UnIgnored ArticlesShow Watched ArticlesShow/Hide HeadersShown HeadersSignSignatureSignature file not foundSlow (but precise) new AlgorithmSorting ColumnSorting OptionsStandard HeadersStart from the BeginningStart searchingSubjectSubject : Subject ColumnSubject: Subscribe ManuallySubscribe selected groupsSubscribed GroupsSubscribed _GroupsSupersede Article...Supersedes : Syntax Error: Bad Line:: Syntax Error: Bad Match Rule on line:: Syntax Error: Bad Score Modifier on line:: Syntax Error: Missing scope for line :: Syntax Error: Unknown Action on line:: Syntax Error: Unknown Header Name on line:: TagLine AddedTagLine length: Test Regular ExpressionTest TextTextText or Regular ExpressionThat's not a problem, the shortcut will work only on the active window The Group Name seems to be wrongThere are new articles in watched threads: This article is not available on the serverThis could take several minutesThis is a crosspost! Do you want to send the article only on the original newsgroup (%s) ?This is root articleThreading MethodThreadsThreads PaneThreads expander positionTo : To correctly import a newsrc file you have to use the same server you used when you saved the file. By default XPN uses a name like 'server_name.newsrc' so it is possible to know wich server was used When you try to import a newsrc file XPN searches for the server name in the file name. Server To Use:Type the editor launcher, %s represents the filename. Examples: xterm -e vim %s gvim -f %s notepad.exe %s "C:\Program Files\Notepad++\Notepad++.exe" %s -nosession NOTE: This feature works only with *Nix and Windows systemsType your ShortcutType your custom command, %s represents the url. Examples: mozilla %s & xterm -e links %sURLUnKeepUnMark for DownloadUnReadUnSetWatchIgnoreUnSubscribe selected groupsUnable to send the message. Control Server Logs.Unexpected error in the excepthook.Upper LimitUse Custom Web Browser LauncherUse Regular ExpressionUse SSL (Secure Socket Layer)Use System FontsUse different From field in mail repliesUse random taglinesUserUser ProfileUsernameViewView Next GroupView Raw ArticleVisualizationWarnings:WatchWatch SubThreadWeb BrowserWeb Browser LauncherWindowXPN PreferencesXPN TagLines ManagerXPN will show these headers on the top of the Article PaneXPN will try to encode your articles with these charsets in this orderXPN will try to use the charsets in this orderYou can Cancel/Supersede only your articlesYou can try on Google:You can write here a FQDN (Fully Qualified Domain Name) that will be used to compose the Message-ID. Otherwise if you leave this field blank XPN will use your Host Name.You have to download newsgroups listYou must restart XPN in order to get the translation activeZoom Article PaneZoom Groups PaneZoom Headers PaneZoom Threads PaneZoom groups Pane[...Muted Sign...]_Article_Articles_Delete Article/Mail_Discard Article_Edit Article/Mail_Exit_File_Insert Spoiler Char_Navigate_Outbox_ROT13 Selected Text_Search_Send Article_Send Queued Articles_Viewpython %prog [-d] [-cCUSTOM_DIR] With command line options you can decide where XPN will save config files and articles. If you don't use any option, the current working directory will be used. If you use the '--home_dir' option, XPN will create a .xpn directory inside your home directory, and will store informations inside that directory. If you use the '--custom_dir' option, XPN will create a .xpn directory inside that custom_directory. NOTE: If you set the '--home_dir' option, XPN will ignore the '--custom_dir' option (if you used it). Examples: python xpn.py python xpn.py -d python xpn.py --custom_dir /home/user/customrow:%d, col:%dspecify an existing directory where store config files and articlestags.txt not founduse home directory to store config files and articlesProject-Id-Version: XPN 0.4.5 Report-Msgid-Bugs-To: POT-Creation-Date: 2009-01-29 09:20+0100 PO-Revision-Date: 2009-01-29 09:24+0100 Last-Translator: Nemesis Language-Team: Italian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vuoi inviare l'Articolo? Inserisci qui una tagline Lunghezza della riga%s = Subject %g = Newsgroups %f = From %n = Nick %e = Email %d = DateRisposta di %s : %s%s selezionato* L'Articolo contiene più del 95% di testo quotato * L'Articolo non contiene del testo nuovo * L'Articolo sembra vuoto * Il campo From sembra invalido * Il campo From è vuoto * Il campo Newsgroups è vuoto * Il campo Newsgroups è vuoto * Il campo Subject è vuoto * Il campo To sembra invalido * Il campo To è vuoto > [...Citazione nascosta...]ANDInformazioni su XPNInformazioni su XPN...AzioneAggiungi ManualmenteAggiungi RegolaAggiungi un ServerAggiungi una TaglineAggiungi un'IdentitàAvanza al Prossimo Articolo dopo un MarkUsa sempre l'Editor EsternoC'è gia un'istanza di XPN in funzione Vuoi lanciare XPN comunque?Applica le Regole dei Punteggi e delle AzioniApproved : Archive : ArticoloArticolo CancellatoArticolo trovatoPannello dell'ArticoloArticolo caricatoArticoliNumero di ArticoliVisualizzazione ArticoliOrdine CrescenteAssocia le Identità ai GruppiRiga IntroduttivaDownload Automatico degli HeaderCharset DisponibiliSfondoColore dello SfondoCorpoSto ricostruendo gli ArticoliSto ricostruendo la lista dei gruppiHo inviato il Cancel: Cancella Articolo sul Server (CANCEL) ...Non distingure MAIUSCOLE/minuscoleDistingui MAIUSCOLE/minuscoleCambia la ScorciatoiaCambia il percorso della FirmaCharset : CharsetLista dei CharsetScegli il ServerResetta ScorciatoieChiudi la Barra dei FiltriChiudi la finestraChiudi la finestra e salva le impostazioiChiudi la finestra. Elimina i cambiamentiChiudi la finestra. Salva i cambiamentiComprimi TuttoComprimi tutt i ThreadComprimi il SottoThread SelezionatoColoreColoriComposizioneCondizioneProfilo GraficoProprietà dei GruppiProprietà VarieProfili dei ServerProfilo dell'UtenteConnessione chiusaConnessione stabilita col server: %sConnessione stabilita col server: %sContiene la StringaRegole CorretteHeader Aggiuntivi (X-Header)DateDate: Scorciatoie di DefaultCancella ArticoloCancella Articolo/MailDiverso da (solo per i numeri)Elimina ArticoloDisplayMostra gli Header nel Pannello dell'ArticoloVuoi inviare un CANCEL per questo articolo? Subject: %s Message-ID: %sNon Contiene la StringaNon Soddisfa l'Espressione RegolareScaricaDownload CompletatoScarica gli header automaticamenteScarica questo numero di articoli (solo gli header)Sto scaricando i Corpi per %sBozze ArticoliBozze MailBozzeErrori dei duplicatiWarning dei duplicatiIndirizzo E-MailIndirizzo E-Mail (per le mail)ArticoloModifica Articolo/MailE-MailModifica Regole dei Punteggi e delle AzioniModifica l'Identità SelezionataModifica il Server SelezionatoFinestra di EditEmail InviataIngleseUguale a (solo per i numeri)ErroreImpossibile aprire l'editor esternoLog degli ErroriErrori:EsciEspandi TuttoEspandi tutti i ThreadEspandi il Gruppo all'AperturaEspandi la Riga degli HeaderEspandi il SottoThread SelezionatoEsporta NewsrcApplicazioni EsterneEditor EsternoComando d'avvio dell'Editor EsternoCharset Predefinito (in lettura)Vecchio Algoritmo di Threading (veloce ma lento)Sto scaricando gli HeaderCampiFileIl file non esisteFiltra Articoli...Filtra gli Articoli per:Filtra Articoli...Trova ArticoloTrova Articolo...Prima devi configurare almeno un ServerPrima devi creare almeno una IdentitàPrima devi leggere l'articoloFont a Spaziatura FissaOpzioni e PunteggiFocus sul Pannello dell'ArticoloFocus sul Pannello dei GruppiFocus sul Pannello dei ThreadFocus sul Pannello dei GruppiCartellaRispondi sul NewsgroupRispondi sul Newsgroup...Followup-To : FontFont e ColoriColore del TestoHo trovato %s taglineSono state trovate delle Scorciatoie duplicate in finestre differentiSono state trovate delle Scorciatoie duplicate sulla stessa finestraFranceseFromFrom : Colonna dei FromFrom: Fully Qualified Domain NameG: Gruppi H: Header A: ArticoliGenera il Message-IDTedescoScarica i Corpi degli Articoli Marcati nei Gruppi SelezionatiScarica i Corpi degli Articoli Marcati nei Gruppi SottoscrittiScarica i Nuovi Header nei Gruppi SelezionatiScarica i Nuovi Header nei Gruppi SottoscrittiScarica la listaRicerca GlobaleRicerca Globale ...Maggiore diGruppoGruppo RimossoGruppo SottoscrittoGruppiLista dei Gruppi...GruppiVisualizzazione GruppiHeaderHeaderColore degli HeaderLista degli HeaderHeader mostrati nel Pannello dell'ArticoloAiutoNascondi gli HeaderIdentitàImpostazioni dell'IdentitàIgnoraIgnora il SottoThreadImporta Newsrc...Compreso inInserisci Spoiler Char (^L)ItalianoConservaConserva l'ArticoloConserva gli Articoli nei Gruppi SelezionatiConserva il SottoThreadScorciatoie da TasteriaEliminaLinuguaggioUltimo ErroreApri l'Editor EsternoApri Editor EsternoLayoutLimita il numero di articoli da scaricareListaAbbassa il Punteggio dell'AutoreLimite InferioreAbbassa il PunteggioMinore diMail-Copies-ToMail-Copies-To : Finestra principaleGestisci GruppiMarca Tutti i Gruppi come LettiMarca come Non Letti Tutti i GruppiMarca l'Articolo come LettoMarca l'Articolo come Non LettoMarca l'articolo per il DownloadMarca GruppoMarca l'Intero Gruppo per il DownloadMarca come LettoMarca i Gruppi Selezionati come LettiMarca come Non Letti i Gruppi SelezionatiMarca il SottoThread come LettoMarca il SottoThread come Non LettoMarca il SottoThread per il DownloadMarca come Non LettoMarca per il DownloadRegola di CorrispondenzaSoddisfa l'Espressione RegolareMassimo numero di articoli da scaricareMessage-IDFinestra di ricerca dei Message-IDMessage-ID da cercareMinuti tra i downloadMiscMiscellaneousManca il file di configurazione. Vuoi configurare XPN ora?ModoModifica le Scorciatoie da Tasteria...Tutti gli HeaderServer NNTPServer NNTPServer NNTPNome o NickNameNome o NickName (per le mail)NavigazioneNavigazioneNuova Regola di AzioneNuova Regola di ScoringGruppiGruppiNewsgroups : Lista caricataNewsgroups/ToNewsrc exportato con successoNewsrc importato con successoNon ci sono ErroriNon ci sono nuovi HeaderImpossibile stabilire la connessione col server : %s. Configura L'indirizzo del server NNTP oppure prova in seguito.Impossibile stabilire la connessione col server : %s. Configura L'indirizzo del server SMTP oppure prova in seguito.Non Maggiore diNon Minore diNumeroNumero di giorni '0' significa che gli articoli letti non verranno mai cancellatiNumero di giorni '0' significa che gli articoli non letti non verranno mai cancellatiORSingolo click per aprire l'ArticoloSingolo click per aprire il GruppoLeggi con un TastoTorna suGestisci Messagi in UscitaHeader OpzionaliCharset OrdinatiLista Ordinata (in scrittura)OrganizationOrganization : Sull'articolo è stato impostato un "Followup_to" su %s, Vuoi inviare l'articolo sul gruppo originale (%s) ?Sull'articolo è stato impostato un "Followup_to: poster", Vuoi rispondere con una mail ?Non Compreso inMessaggi in UscitaArticoli In UscitaMail In UscitaMessaggi in UscitaMessaggi in UscitaFinestra dei Messaggi in UscitaPasswordRicerca InterattivaInformazioni PersonaliAttendere. Sto ricostruendo i Thread.Imposta il Nome dell'IdentitàImposta il Nome del ServerAttendere, sto scaricando la listaPortaComponi un Nuovo ArticoloInvia un Nuovo Articolo...PreferenzePreferenze...Premi OK per confermareImpossibile cancellare l'articolo : %sProblemi nell'accesso :Impossibile aprire la Casella delle Bozze delle MailImpossibile aprire la Casella delle Mail in UscitaImpossibile aprire la Casella delle Bozze delle NewsImpossibile aprire la Casella delle News in UscitaImpossibile aprire gli Articoli InviatiProblemi nell'aperture delle Mail Inviate :Impossibile aprire l'articolo :Impossibile aprire la cartella :Impossibile aprire la mail :Pulizia dei GruppiElimina gli articoli letti (giorni)Elimina articoli non letti (giorni)Sto pulendo il gruppo: %sCitazione Livello 1Citazione Livello 2Citazione Livello 3Prova le Espressioni RegolariCodifica/Decodifica in ROT13 il Testo SelezionatoAlza il Punteggio dell'AutoreAlza il PunteggioAnalizza le RegoleLeggi l'Articolo SuccessivoLeggi il Successivo Articolo Non LettoLeggi l'Articolo PadreLeggi l'Articolo PrecedenteReferencesSto aggiornando il gruppo: %sEspressione RegolareRimuovi l'Identità SelezionataRimuovi il Server SelezionatoRispondi via Mail...Rispondi via MailReply-ToReply-To : ScaricaScarica i Corpi per tutti i nuovi articoliRegola usata per combinare i risultati della ricercaRegoleServer SMTPIndirizzo Server SMTP | Numero di portaSalva l'Articolo nelle BozzeGruppi/Modficatore PunteggioPunteggioEditor File dei PunteggiRegole dei PunteggiRegole dei Punteggi e delle Azioni...Avanzamento del testo (% della pagina)CercaCerca GruppoCerca nel gruppo correnteCerca nei gruppi sottoscrittiCerca nel CorpoCerca nel Corpo...Cerca su GoogleRicerca in corso ...Colore dello SfondoSeleziona il Colore di Sfondo degli HeaderSelezione il Colore degli HeaderSeleziona dove salvare il file NewsrcSeleziona il file NewsrcColore delle Citazioni Livello 1Colore delle Citazioni Livello 2Colore delle Citazioni Livello 3Colore della FirmaSeleziona la FirmaColore del TestoColore delle URLInvia ArticoloInvia Articolo SuccessivamenteInvia l'Articolo _SuccessivamenteInvia gli Articoli in UscitaInvia le Mail in UscitaInvia le Mail in UscitaSender : Sto inviando l'Articolo: Sto inviando la Mail: InviatiIviati %d ArticoliInviate %d MailArticoli InviatiMail InviateServerErrore del Server: Log del ServerVisualizzatore dei Log del ServerLog del Server...Impostazioni del ServerErrore del server: %sIl server richiede l'autenticazioneServerImposta il Punteggio dell'AutoreLista di DefaultImposta il PunteggioModifica il coloreScorciatoiaScorciatoieMostra i Thread con Articoli Tutti LettiMostra Articoli con Punteggio<0Mostra Articoli con Punteggio=0Mostra Articoli con Punteggio>0Mostra gli ErroriMostra lista completaMostra i file nascostiMostra Articoli IgnoratiMostra Articoli ConservatiMostra il Testo CitatoMostra Articoli LettiMostra FirmeMostra il Testo coperto da SpoilerMostra ThreadMostra i Thread Senza Articoli SeguitiMostra Articoli Non ConservatiMostra Articoli Non LettiMostra Articoli Non Seguiti e Non IgnoratiMostra Articoli SeguitiMostra/Nascondi HeaderHeader MostratiFirmaFirmaFile della firma non trovatoNuovo Algoritmo di Threading (preciso e lento)Colonna dell'OrdinamentoOrdinamentoHeader StandardComincia dall'inizioAvvia la RicercaSubjectSubject : Colonna dei Subject: Subject: Sottoscrivi ManualmenteSottoscrivi i gruppi selezionatiGruppi Sottoscritti_Gruppi SottoscrittiSostituisci Articolo sul Server (SUPERSEDE)Supersedes : Error di Sintassi: Riga errata:: Errore di Sintassi: Regola di Corrispondenza errata alla riga:: Error di Sintassi: Modificatore di Punteggio errato nella linea :: Errore di Sintassi: Manca l'indicazione dei gruppi alla riga :: Errore di Sintassi: Azione sconosciuta alla riga:: Errore di Sintassi: Header sconosciuto alla riga:: TagLine AggiuntaLunghezza della TagLine: Prova Espressione RegolariTesto di provaTestoTesto o Espressione RegolareQuesto non è un problema, la Scorciatoia funzionerà solo sulla finestra attivaIl nome del Gruppo sembra essere erratoCi sono nuovi articoli nelle discussione seguiteQuesto articolo non è disponibile sul serverPotrebbero essere necessari diversi minutiQuesto è un crosspost! Vuoi inviare l'articolo solo sul newsgroup originale (%s) ?Questo è l'articolo radiceAlgoritmo di ThreadingThreadsPannello dei ThreadPosizione dell'espansore dei ThreadTo : Per importare un file newsrc correttamente devi usare lo stesso server usatoper salvare il file Di default XPN usa un nome tipo 'nome_server.newsrc' così è possibile risalireal server usato Quando provi ad importare un file newsrc XPN cerca il nome del server nel nome del file. Server da Usare:Inserisci il comando d'avvio dell'editor, %s rappresenta il file Esempi: xterm -e vim %s gvim -f %s notepad.exe %s "C:\Program Files\Notepad++\Notepad++.exe" %s -nosession NOTA: Questa funzionalità è disponibile solo sui sistemi *Nix e Windows.Digita la ScorciatoiaInserisci il comando d'avvio, %s rappresenta la url Esempi: mozilla %s & xterm -e links %sURLRimuovi 'Conserva'Rimuovi la marcatura per il DownloadNon lettiRimuovi Segui/IgnoraRimuovi Sottoscrizione ai gruppi selezionatiImpossibile inviare il messaggio. Controlla i Log del ServerSi è verificato un errore nella gestione delle eccezioni.Limite SuperioreUsa un Browser diverso da quello predefinito di sistemaUsa le Espressioni RegolariUsa SSL (Secure Socket Layer)Usa i font di sistemaUsa un diverso campo From per le risposte via mailUsa le tagline randomUtenteProfilo UtenteNome UtenteVisualizzazioneVai al Prossimo GruppoVedi tutti gli HeaderVisualizzazioneWarnings:SeguiSegui il SottoThreadWeb BrowserComando d'avvio del BrowserFinestraXPN PreferenzeXPN Gestore delle TaglineXPN mostrerà questi header in cima al Pannello degli ArticoliXPN proverà a codificare i tuoi articoli con questi charset nell'ordine in cui sono riportatiXPN proverà ad utilizzare i charset in questo ordinePuoi usare il Cancel/Supersede solo per i tuoi articoliPuoi provare con Google: Qui puoi inserire un FQDN (Fully Qualified Domain Name) che sarà usato per comporre i tuoi Message-ID Altrimenti se lasci in bianco questo campo XPN userà il tuo Host Name.Devi scaricare la lista dei gruppiPer attivare la traduzione devi riavviare XPN.Ingrandisci il Pannello dell'ArticoloIngrandisci il Pannello dei GruppiIngrandisci il Pannello degli HeaderIngrandisci il Pannello dei ThreadIngrandisci il Pannello dei Gruppi[...Firma Nascosta...]_Articolo_Articoli_Cancella Articolo/Mail_Elimina Articolo_Modifica Articolo/Mail_Esci_File_Inserisci lo Spoiler Char (^L)_NavigazioneMessaggi in _UscitaCodifica/Decodifica in _ROT13 il Testo SelezionatoCerca_Invia ArticoloInvia gli Articoli in Uscita_Visualizzazionepython %prog [-d] [-cCUSTOM_DIR] Con le opzioni a linea di comando puoi decidere dove XPN salverà i file di configurazione e gli articoli. Se non usi alcuna opzione sarà utilizzata la directory corrente. Se usi l'opzione '--home_dir', XPN creerà una directory .xpn all'internodella tua home directory, e tutte le informazioni saranno memorizzazionein essa. Se usi l'opzione '--custom_dir', XPN creerà una directory .xpn all'interno della directory da te indicata.. NOTA: Se setti l'opzione '--home_dir', XPN ignorerà l'eventuale opzione '--custom-dir'. Esempi: python xpn.py python xpn.py -d python xpn.py --custom_dir /home/user/customriga:%d, col:%dindica una directory esistente dove memorizzare i file di configurazione e gli articolitags.txt non trovatousa la home directory per memorizzare i file di configurazione e gli articolixpn-1.2.6/lang/xpn.pot0000644000175000017500000012727311141275756012752 0ustar antant# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-01-29 09:20+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: xpn.py:305 xpn.py:352 xpn.py:417 msgid "First you have to read the article" msgstr "" #: xpn.py:315 #, python-format msgid "" "Do you want to CANCEL this article?\n" "\n" "Subject: %s \n" "Message-ID: %s" msgstr "" #: xpn.py:322 msgid "Cancel Article Sent: " msgstr "" #: xpn.py:326 msgid "You can Cancel/Supersede only your articles" msgstr "" #: xpn.py:377 #, python-format msgid "" "This is a crosspost! \n" " Do you want to send the article only on the original newsgroup (%s) ?" msgstr "" #: xpn.py:382 #, python-format msgid "" "Original Poster set \"Followup_to\" on %s,\n" "\n" "Do you want to send your article on the original newsgroup (%s) ?" msgstr "" #: xpn.py:386 msgid "" "Original Poster set \"Followup_to: poster\",\n" "\n" "Do you want to reply by mail ?" msgstr "" #: xpn.py:660 msgid "Please Wait. Building Threads" msgstr "" #: xpn.py:862 #, python-format msgid "%s selected" msgstr "" #: xpn.py:1191 msgid "> [...Muted Quote...]" msgstr "" #: xpn.py:1204 msgid "[...Muted Sign...]" msgstr "" #: xpn.py:1449 msgid "This is root article" msgstr "" #: xpn.py:1464 msgid "Article Found" msgstr "" #: xpn.py:1500 msgid "Article loaded" msgstr "" #: xpn.py:1502 xpn.py:1504 msgid "This article is not available on the server" msgstr "" #: xpn.py:1507 msgid "There are new articles in watched threads: " msgstr "" #: xpn.py:1524 xpn.py:1646 xpn.py:1673 msgid "Download Completed" msgstr "" #: xpn.py:1577 xpn_src/Groups_Win.py:162 xpn_src/Newsrc.py:224 msgid "Fetching Headers" msgstr "" #: xpn.py:1590 xpn_src/Groups_Win.py:171 xpn_src/Newsrc.py:233 msgid "Building Articles" msgstr "" #: xpn.py:1592 xpn_src/Groups_Win.py:173 xpn_src/Newsrc.py:235 msgid "No New Headers" msgstr "" #: xpn.py:1611 #, python-format msgid "Refreshing Group %s" msgstr "" #: xpn.py:1679 #, python-format msgid "Downloading Bodies for %s" msgstr "" #: xpn.py:1822 msgid "Select Newsrc Export Path" msgstr "" #: xpn.py:1840 msgid "Select Newsrc File" msgstr "" #: xpn.py:1841 xpn_src/ID_Win.py:28 msgid "Show Hidden Files" msgstr "" #: xpn.py:1866 msgid "" "To correctly import a newsrc file you have to use the same server you used " "when you saved the file.\n" "\n" "By default XPN uses a name like 'server_name.newsrc' so it is possible to " "know wich server was used\n" "\n" "When you try to import a newsrc file XPN searches for the server name in the " "file name.\n" "\n" "\n" "Server To Use:" msgstr "" #: xpn.py:1875 msgid "File does not exist" msgstr "" #: xpn.py:1882 msgid "Newsrc successful imported" msgstr "" #: xpn.py:2107 msgid "Newsgroups" msgstr "" #: xpn.py:2107 msgid "UnRead" msgstr "" #: xpn.py:2287 #, python-format msgid "Purging Group: %s" msgstr "" #: xpn.py:2424 msgid "_File" msgstr "" #: xpn.py:2425 xpn_src/KeyBindings.py:21 msgid "Groups List..." msgstr "" #: xpn.py:2425 msgid "Manage Groups" msgstr "" #: xpn.py:2426 xpn_src/KeyBindings.py:22 msgid "Scoring and Action Rules..." msgstr "" #: xpn.py:2426 msgid "Edit Scoring and Action Rules" msgstr "" #: xpn.py:2427 xpn_src/KeyBindings.py:23 msgid "Server Logs..." msgstr "" #: xpn.py:2428 xpn_src/KeyBindings.py:24 msgid "Export Newsrc..." msgstr "" #: xpn.py:2429 xpn_src/KeyBindings.py:25 msgid "Import Newsrc..." msgstr "" #: xpn.py:2430 xpn_src/KeyBindings.py:26 msgid "Modify Keyboard Shortcuts..." msgstr "" #: xpn.py:2431 xpn_src/KeyBindings.py:27 msgid "Preferences..." msgstr "" #: xpn.py:2431 msgid "Preferences" msgstr "" #: xpn.py:2432 xpn_src/KeyBindings.py:28 xpn_src/KeyBindings.py:130 #: xpn_src/Outbox_Manager.py:432 msgid "Exit" msgstr "" #: xpn.py:2433 msgid "_Search" msgstr "" #: xpn.py:2434 xpn_src/KeyBindings.py:30 msgid "Find Article..." msgstr "" #: xpn.py:2435 xpn_src/KeyBindings.py:32 msgid "Global Search ..." msgstr "" #: xpn.py:2436 msgid "Filter Articles ..." msgstr "" #: xpn.py:2437 xpn_src/KeyBindings.py:33 msgid "Search in the Body..." msgstr "" #: xpn.py:2438 msgid "_View" msgstr "" #: xpn.py:2439 xpn_src/KeyBindings.py:35 msgid "Articles View Options" msgstr "" #: xpn.py:2440 xpn_src/KeyBindings.py:43 msgid "Groups View Options" msgstr "" #: xpn.py:2441 msgid "_Navigate" msgstr "" #: xpn.py:2442 xpn_src/KeyBindings.py:58 msgid "View Next Group" msgstr "" #: xpn.py:2443 xpn_src/KeyBindings.py:59 msgid "Read Previous Article" msgstr "" #: xpn.py:2444 xpn_src/KeyBindings.py:60 msgid "Read Next Article" msgstr "" #: xpn.py:2445 xpn_src/KeyBindings.py:61 msgid "Read Next Unread Article" msgstr "" #: xpn.py:2446 xpn_src/KeyBindings.py:62 msgid "Read Parent Article" msgstr "" #: xpn.py:2447 xpn_src/KeyBindings.py:63 msgid "One-Key Reading" msgstr "" #: xpn.py:2448 xpn_src/KeyBindings.py:64 msgid "One-Key Scroll Up" msgstr "" #: xpn.py:2449 xpn_src/KeyBindings.py:65 msgid "Focus to Article Pane" msgstr "" #: xpn.py:2450 msgid "Focus to Groups Pane" msgstr "" #: xpn.py:2451 xpn_src/KeyBindings.py:67 msgid "Focus to Threads Pane" msgstr "" #: xpn.py:2452 xpn.py:2789 xpn_src/KeyBindings.py:68 msgid "Zoom Article Pane" msgstr "" #: xpn.py:2453 xpn.py:2791 msgid "Zoom Groups Pane" msgstr "" #: xpn.py:2454 xpn_src/KeyBindings.py:70 msgid "Zoom Threads Pane" msgstr "" #: xpn.py:2455 msgid "Subscribed _Groups" msgstr "" #: xpn.py:2456 xpn_src/KeyBindings.py:72 msgid "Get New Headers in Subscribed Groups" msgstr "" #: xpn.py:2457 xpn_src/KeyBindings.py:73 msgid "Get New Headers in Selected Groups" msgstr "" #: xpn.py:2458 xpn_src/KeyBindings.py:74 msgid "Get Marked Article Bodies in Subscribed Groups" msgstr "" #: xpn.py:2459 xpn_src/KeyBindings.py:75 msgid "Get Marked Article Bodies in Selected Groups" msgstr "" #: xpn.py:2460 xpn_src/KeyBindings.py:76 msgid "Expand All Threads" msgstr "" #: xpn.py:2460 msgid "Expand All" msgstr "" #: xpn.py:2461 xpn_src/KeyBindings.py:77 msgid "Collapse All Threads" msgstr "" #: xpn.py:2461 msgid "Collapse All" msgstr "" #: xpn.py:2462 xpn_src/KeyBindings.py:78 msgid "Expand Selected SubThread" msgstr "" #: xpn.py:2463 xpn_src/KeyBindings.py:79 msgid "Collapse Selected SubThread" msgstr "" #: xpn.py:2464 xpn_src/KeyBindings.py:80 msgid "Mark Group ..." msgstr "" #: xpn.py:2465 xpn_src/KeyBindings.py:81 msgid "Mark Selected Groups as Read" msgstr "" #: xpn.py:2466 xpn_src/KeyBindings.py:82 msgid "Mark Selected Groups as Unread" msgstr "" #: xpn.py:2467 xpn_src/KeyBindings.py:83 msgid "Mark Group for Retrieving" msgstr "" #: xpn.py:2468 xpn_src/KeyBindings.py:84 msgid "Keep Articles in Selected Groups" msgstr "" #: xpn.py:2469 xpn_src/KeyBindings.py:85 msgid "Mark All Groups as Read" msgstr "" #: xpn.py:2470 xpn_src/KeyBindings.py:86 msgid "Mark All Groups as Unread" msgstr "" #: xpn.py:2471 xpn_src/KeyBindings.py:87 msgid "Apply Scoring and Action Rules" msgstr "" #: xpn.py:2472 xpn_src/Groups_Vs_ID.py:39 xpn_src/KeyBindings.py:88 msgid "Assign Identities to Groups" msgstr "" #: xpn.py:2473 msgid "_Articles" msgstr "" #: xpn.py:2474 xpn_src/KeyBindings.py:41 msgid "Show/Hide Headers" msgstr "" #: xpn.py:2475 xpn_src/Edit_Mail_Win.py:640 xpn_src/Edit_Win.py:732 #: xpn_src/KeyBindings.py:42 xpn_src/KeyBindings.py:120 msgid "ROT13 Selected Text" msgstr "" #: xpn.py:2476 xpn_src/KeyBindings.py:96 msgid "Flags & Score" msgstr "" #: xpn.py:2477 xpn_src/KeyBindings.py:97 msgid "Mark Article as Read" msgstr "" #: xpn.py:2478 xpn_src/KeyBindings.py:98 msgid "Mark Article as UnRead" msgstr "" #: xpn.py:2479 xpn_src/KeyBindings.py:99 msgid "Mark Article for Retrieving" msgstr "" #: xpn.py:2480 xpn_src/KeyBindings.py:100 msgid "Keep Article" msgstr "" #: xpn.py:2481 xpn_src/KeyBindings.py:101 msgid "Delete Article" msgstr "" #: xpn.py:2482 xpn_src/KeyBindings.py:102 msgid "Mark SubThread as UnRead" msgstr "" #: xpn.py:2483 xpn_src/KeyBindings.py:103 msgid "Mark SubThread as Read" msgstr "" #: xpn.py:2484 xpn_src/KeyBindings.py:104 msgid "Mark SubThread for Retrieving" msgstr "" #: xpn.py:2485 xpn_src/KeyBindings.py:105 msgid "Keep SubThread" msgstr "" #: xpn.py:2486 xpn_src/KeyBindings.py:106 msgid "Watch SubThread" msgstr "" #: xpn.py:2487 xpn_src/KeyBindings.py:107 msgid "Ignore SubThread" msgstr "" #: xpn.py:2488 xpn_src/KeyBindings.py:108 msgid "Raise Author Score" msgstr "" #: xpn.py:2489 xpn_src/KeyBindings.py:109 msgid "Lower Author Score" msgstr "" #: xpn.py:2490 xpn_src/KeyBindings.py:110 msgid "Set Author Score" msgstr "" #: xpn.py:2491 xpn_src/KeyBindings.py:90 msgid "Post New Article..." msgstr "" #: xpn.py:2491 msgid "Post New Article" msgstr "" #: xpn.py:2492 xpn_src/KeyBindings.py:93 msgid "Open Outbox Manager" msgstr "" #: xpn.py:2493 xpn_src/KeyBindings.py:91 msgid "Follow-Up To Newsgroup..." msgstr "" #: xpn.py:2493 msgid "Follow-Up To Newsgroup" msgstr "" #: xpn.py:2494 xpn_src/KeyBindings.py:92 msgid "Reply By Mail..." msgstr "" #: xpn.py:2494 msgid "Reply by Mail" msgstr "" #: xpn.py:2495 xpn_src/KeyBindings.py:95 msgid "Supersede Article..." msgstr "" #: xpn.py:2496 xpn_src/KeyBindings.py:94 msgid "Cancel Article..." msgstr "" #: xpn.py:2497 xpn_src/KeyBindings.py:111 msgid "Help" msgstr "" #: xpn.py:2498 xpn_src/KeyBindings.py:112 msgid "About..." msgstr "" #: xpn.py:2507 xpn_src/KeyBindings.py:44 msgid "Show Threads" msgstr "" #: xpn.py:2508 xpn_src/KeyBindings.py:45 msgid "Show All Read Threads" msgstr "" #: xpn.py:2509 xpn_src/KeyBindings.py:46 msgid "Show Threads Without Watched Articles" msgstr "" #: xpn.py:2510 xpn_src/KeyBindings.py:47 msgid "Show Read Articles" msgstr "" #: xpn.py:2511 xpn_src/KeyBindings.py:48 msgid "Show UnRead Articles" msgstr "" #: xpn.py:2512 xpn_src/KeyBindings.py:49 msgid "Show Kept Articles" msgstr "" #: xpn.py:2513 xpn_src/KeyBindings.py:50 msgid "Show UnKept Articles" msgstr "" #: xpn.py:2514 xpn_src/KeyBindings.py:51 msgid "Show Watched Articles" msgstr "" #: xpn.py:2515 xpn_src/KeyBindings.py:52 msgid "Show Ignored Articles" msgstr "" #: xpn.py:2516 xpn_src/KeyBindings.py:53 msgid "Show UnWatched/UnIgnored Articles" msgstr "" #: xpn.py:2517 xpn_src/KeyBindings.py:54 msgid "Show Articles with Score<0" msgstr "" #: xpn.py:2518 xpn_src/KeyBindings.py:55 msgid "Show Articles with Score=0" msgstr "" #: xpn.py:2519 xpn_src/KeyBindings.py:56 msgid "Show Articles with Score>0" msgstr "" #: xpn.py:2520 xpn_src/KeyBindings.py:36 msgid "View Raw Article" msgstr "" #: xpn.py:2521 xpn_src/KeyBindings.py:37 msgid "Show Spoilered Text" msgstr "" #: xpn.py:2522 xpn_src/KeyBindings.py:38 msgid "Show Quoted Text" msgstr "" #: xpn.py:2523 xpn_src/KeyBindings.py:39 msgid "Show Signatures" msgstr "" #: xpn.py:2524 xpn_src/KeyBindings.py:40 msgid "Fixed Pitch Font" msgstr "" #: xpn.py:2629 msgid "" "An instance of XPN is already running.\n" "\n" "Do you want to open XPN anyway?" msgstr "" #: xpn.py:2715 msgid "Filter Articles by: " msgstr "" #: xpn.py:2719 msgid "Close Filter Toolbar" msgstr "" #: xpn.py:2790 msgid "Zoom Headers Pane" msgstr "" #: xpn.py:2837 msgid "" "Missing Config File.\n" "\n" "Do you want to Configure XPN now?" msgstr "" #: xpn.py:2869 msgid "Unexpected error in the excepthook." msgstr "" #: xpn.py:2877 msgid "" "python %prog [-d] [-cCUSTOM_DIR]\n" "\n" "With command line options you can decide where XPN will save config files " "and articles.\n" "If you don't use any option, the current working directory will be used.\n" "If you use the '--home_dir' option, XPN will create a .xpn directory inside " "your home directory, and will store informations inside that directory.\n" "If you use the '--custom_dir' option, XPN will create a .xpn directory " "inside that custom_directory.\n" "\n" "NOTE: If you set the '--home_dir' option, XPN will ignore the '--custom_dir' " "option (if you used it).\n" "\n" "Examples:\n" "python xpn.py\n" "python xpn.py -d\n" "python xpn.py --custom_dir /home/user/custom" msgstr "" #: xpn.py:2879 msgid "use home directory to store config files and articles" msgstr "" #: xpn.py:2881 msgid "specify an existing directory where store config files and articles" msgstr "" #: xpn_src/add_tag.py:27 msgid "TagLine Added" msgstr "" #: xpn_src/add_tag.py:33 msgid "TagLine length: " msgstr "" #: xpn_src/add_tag.py:43 #, python-format msgid "Found %s tags" msgstr "" #: xpn_src/add_tag.py:50 msgid "XPN TagLines Manager" msgstr "" #: xpn_src/add_tag.py:54 msgid "" "\n" "Insert here a tagline\n" msgstr "" #: xpn_src/Article_Pane.py:27 msgid "Subject: " msgstr "" #: xpn_src/Article_Pane.py:28 msgid "From: " msgstr "" #: xpn_src/Article_Pane.py:29 msgid "Date: " msgstr "" #: xpn_src/Article_Pane.py:31 xpn_src/Article_Pane.py:40 #: xpn_src/Article_Pane.py:418 xpn_src/Article_Pane.py:419 msgid "Expand Headers Row" msgstr "" #: xpn_src/Article_Pane.py:36 xpn_src/Article_Pane.py:413 msgid "Hide Headers" msgstr "" #: xpn_src/Charset_List.py:199 msgid "Available Charsets" msgstr "" #: xpn_src/Charset_List.py:201 msgid "Ordered Charsets" msgstr "" #: xpn_src/Charset_List.py:213 xpn_src/Charset_List.py:237 #: xpn_src/Config_Win.py:582 xpn_src/Config_Win.py:714 #: xpn_src/Groups_Win.py:315 xpn_src/Headers_List.py:141 #: xpn_src/Headers_List.py:160 msgid "List" msgstr "" #: xpn_src/Charset_List.py:247 msgid "XPN will try to encode your articles with these charsets in this order" msgstr "" #: xpn_src/Charset_List.py:284 xpn_src/Headers_List.py:210 msgid "Set Default List" msgstr "" #: xpn_src/Config_Win.py:509 msgid "Servers" msgstr "" #: xpn_src/Config_Win.py:515 msgid "NNTP Servers" msgstr "" #: xpn_src/Config_Win.py:554 msgid "Add a Server" msgstr "" #: xpn_src/Config_Win.py:560 msgid "Edit Selected Server" msgstr "" #: xpn_src/Config_Win.py:566 msgid "Remove Selected Server" msgstr "" #: xpn_src/Config_Win.py:594 msgid "SMTP Server" msgstr "" #: xpn_src/Config_Win.py:614 xpn_src/Server_Win.py:100 msgid "Server requires authentication" msgstr "" #: xpn_src/Config_Win.py:617 msgid "SMTP Server Address | Port Number" msgstr "" #: xpn_src/Config_Win.py:620 xpn_src/Server_Win.py:111 msgid "Username" msgstr "" #: xpn_src/Config_Win.py:623 xpn_src/Server_Win.py:113 msgid "Password" msgstr "" #: xpn_src/Config_Win.py:647 msgid "User Profile" msgstr "" #: xpn_src/Config_Win.py:682 msgid "Add an Identity" msgstr "" #: xpn_src/Config_Win.py:688 msgid "Edit Selected Identity" msgstr "" #: xpn_src/Config_Win.py:694 msgid "Remove Selected Identity" msgstr "" #: xpn_src/Config_Win.py:733 msgid "Fonts and Colors" msgstr "" #: xpn_src/Config_Win.py:742 msgid "Fonts" msgstr "" #: xpn_src/Config_Win.py:749 xpn_src/Edit_Win.py:892 #: xpn_src/KeyBindings.py:115 msgid "Article" msgstr "" #: xpn_src/Config_Win.py:760 msgid "Threads" msgstr "" #: xpn_src/Config_Win.py:771 xpn_src/Config_Win.py:1372 msgid "Groups" msgstr "" #: xpn_src/Config_Win.py:782 msgid "Use System Fonts" msgstr "" #: xpn_src/Config_Win.py:793 msgid "Colors" msgstr "" #: xpn_src/Config_Win.py:801 msgid "Text" msgstr "" #: xpn_src/Config_Win.py:803 msgid "Quote Level 1" msgstr "" #: xpn_src/Config_Win.py:806 msgid "Quote Level 2" msgstr "" #: xpn_src/Config_Win.py:808 msgid "Quote Level 3" msgstr "" #: xpn_src/Config_Win.py:810 msgid "Sign" msgstr "" #: xpn_src/Config_Win.py:812 xpn_src/Config_Win.py:911 msgid "Background" msgstr "" #: xpn_src/Config_Win.py:815 msgid "URL" msgstr "" #: xpn_src/Config_Win.py:831 msgid "Select Text Color" msgstr "" #: xpn_src/Config_Win.py:835 msgid "Select Quote Level 1 Color" msgstr "" #: xpn_src/Config_Win.py:839 msgid "Select Quote Level 2 Color" msgstr "" #: xpn_src/Config_Win.py:843 msgid "Select Quote Level 3 Color" msgstr "" #: xpn_src/Config_Win.py:847 msgid "Select Sign Color" msgstr "" #: xpn_src/Config_Win.py:851 msgid "Select Background Color" msgstr "" #: xpn_src/Config_Win.py:855 msgid "Select URL Color" msgstr "" #: xpn_src/Config_Win.py:888 msgid "Headers Colors" msgstr "" #: xpn_src/Config_Win.py:900 msgid "Select Headers Background Color" msgstr "" #: xpn_src/Config_Win.py:904 msgid "Select Headers Foreground Color" msgstr "" #: xpn_src/Config_Win.py:908 msgid "Color" msgstr "" #: xpn_src/Config_Win.py:925 xpn_src/Config_Win.py:928 msgid "Layout" msgstr "" #: xpn_src/Config_Win.py:951 msgid "" "G: Groups Pane\n" "\n" "H: Headers Pane\n" "\n" "A: Article Pane" msgstr "" #: xpn_src/Config_Win.py:959 msgid "Article Pane" msgstr "" #: xpn_src/Config_Win.py:966 msgid "Display Headers in the Article Pane" msgstr "" #: xpn_src/Config_Win.py:968 msgid "Headers List" msgstr "" #: xpn_src/Config_Win.py:970 xpn_src/Headers_List.py:165 msgid "XPN will show these headers on the top of the Article Pane" msgstr "" #: xpn_src/Config_Win.py:971 msgid "Headers Shown on the Article Pane" msgstr "" #: xpn_src/Config_Win.py:982 msgid "Threads Pane" msgstr "" #: xpn_src/Config_Win.py:989 msgid "Threads expander position" msgstr "" #: xpn_src/Config_Win.py:990 msgid "Subject Column" msgstr "" #: xpn_src/Config_Win.py:991 msgid "From Column" msgstr "" #: xpn_src/Config_Win.py:1013 msgid "Download" msgstr "" #: xpn_src/Config_Win.py:1015 msgid "Visualization" msgstr "" #: xpn_src/Config_Win.py:1017 msgid "Navigation" msgstr "" #: xpn_src/Config_Win.py:1027 msgid "Purge Options" msgstr "" #: xpn_src/Config_Win.py:1035 msgid "Number of days. '0' means never purge read articles" msgstr "" #: xpn_src/Config_Win.py:1036 msgid "Purge read articles after (days)" msgstr "" #: xpn_src/Config_Win.py:1040 msgid "Number of days. '0' means never purge unread articles" msgstr "" #: xpn_src/Config_Win.py:1041 msgid "Purge unread articles after (days)" msgstr "" #: xpn_src/Config_Win.py:1057 xpn_src/Groups_Win.py:440 #: xpn_src/KeyBindings.py:89 msgid "Articles" msgstr "" #: xpn_src/Config_Win.py:1062 msgid "Retrieve Bodies for all new articles" msgstr "" #: xpn_src/Config_Win.py:1063 msgid "Limit the number of articles to download" msgstr "" #: xpn_src/Config_Win.py:1065 msgid "Max number of articles to download" msgstr "" #: xpn_src/Config_Win.py:1078 msgid "Automatic Header Download" msgstr "" #: xpn_src/Config_Win.py:1083 msgid "Download Headers automatically" msgstr "" #: xpn_src/Config_Win.py:1085 msgid "Minutes Between Downloads" msgstr "" #: xpn_src/Config_Win.py:1101 msgid "Sorting Options" msgstr "" #: xpn_src/Config_Win.py:1107 msgid "Ascending Order" msgstr "" #: xpn_src/Config_Win.py:1108 msgid "Sorting Column" msgstr "" #: xpn_src/Config_Win.py:1113 xpn_src/Find_Win.py:163 xpn_src/Find_Win.py:509 #: xpn_src/Outbox_Manager.py:514 xpn_src/Threads_Pane.py:273 msgid "Subject" msgstr "" #: xpn_src/Config_Win.py:1113 xpn_src/Find_Win.py:160 xpn_src/Find_Win.py:506 #: xpn_src/Threads_Pane.py:274 msgid "From" msgstr "" #: xpn_src/Config_Win.py:1113 xpn_src/Outbox_Manager.py:524 #: xpn_src/Threads_Pane.py:275 msgid "Date" msgstr "" #: xpn_src/Config_Win.py:1113 xpn_src/Score.py:805 xpn_src/Threads_Pane.py:276 msgid "Score" msgstr "" #: xpn_src/Config_Win.py:1130 msgid "Charsets" msgstr "" #: xpn_src/Config_Win.py:1136 msgid "Fallback Charset (Reading)" msgstr "" #: xpn_src/Config_Win.py:1148 msgid "Charsets List" msgstr "" #: xpn_src/Config_Win.py:1152 msgid "XPN will try to use the charsets in this order" msgstr "" #: xpn_src/Config_Win.py:1153 msgid "Ordered List (Writing)" msgstr "" #: xpn_src/Config_Win.py:1166 msgid "Threading Method" msgstr "" #: xpn_src/Config_Win.py:1172 msgid "Fast (but imprecise) old Algorithm" msgstr "" #: xpn_src/Config_Win.py:1173 msgid "Slow (but precise) new Algorithm" msgstr "" #: xpn_src/Config_Win.py:1182 xpn_src/Config_Win.py:1221 msgid "Miscellaneous" msgstr "" #: xpn_src/Config_Win.py:1188 msgid "Advance to the Next Article on Mark" msgstr "" #: xpn_src/Config_Win.py:1189 msgid "One Click Enter Group" msgstr "" #: xpn_src/Config_Win.py:1190 msgid "One Click Enter Article" msgstr "" #: xpn_src/Config_Win.py:1191 msgid "Expand Group on Entering" msgstr "" #: xpn_src/Config_Win.py:1192 #, python-format msgid "Scroll Text (% of page)" msgstr "" #: xpn_src/Config_Win.py:1218 msgid "External Apps" msgstr "" #: xpn_src/Config_Win.py:1231 msgid "Web Browser" msgstr "" #: xpn_src/Config_Win.py:1236 msgid "Use Custom Web Browser Launcher" msgstr "" #: xpn_src/Config_Win.py:1240 #, python-format msgid "" "Type your custom command, %s represents the url.\n" "Examples:\n" "\n" "mozilla %s &\n" "xterm -e links %s" msgstr "" #: xpn_src/Config_Win.py:1242 msgid "Web Browser Launcher" msgstr "" #: xpn_src/Config_Win.py:1257 msgid "External Editor" msgstr "" #: xpn_src/Config_Win.py:1261 msgid "Always Use External Editor" msgstr "" #: xpn_src/Config_Win.py:1264 #, python-format msgid "" "Type the editor launcher, %s represents the filename.\n" "Examples:\n" "\n" "xterm -e vim %s\n" "gvim -f %s\n" "notepad.exe %s\n" "\"C:\\Program Files\\Notepad++\\Notepad++.exe\" %s -nosession\n" "\n" "NOTE: This feature works only with *Nix and Windows systems" msgstr "" #: xpn_src/Config_Win.py:1266 msgid "External Editor Command" msgstr "" #: xpn_src/Config_Win.py:1280 msgid "Language" msgstr "" #: xpn_src/Config_Win.py:1288 msgid "English" msgstr "" #: xpn_src/Config_Win.py:1297 msgid "Italian" msgstr "" #: xpn_src/Config_Win.py:1306 msgid "French" msgstr "" #: xpn_src/Config_Win.py:1315 msgid "German" msgstr "" #: xpn_src/Config_Win.py:1327 msgid "" "You must restart XPN in order\n" " to get the translation active" msgstr "" #: xpn_src/Config_Win.py:1347 msgid "XPN Preferences" msgstr "" #: xpn_src/Config_Win.py:1368 xpn_src/Edit_Win.py:855 #: xpn_src/Groups_Win.py:354 xpn_src/Groups_Win.py:369 msgid "Server" msgstr "" #: xpn_src/Config_Win.py:1368 msgid "Configure Server Profiles" msgstr "" #: xpn_src/Config_Win.py:1369 msgid "User" msgstr "" #: xpn_src/Config_Win.py:1369 msgid "Configure User Profile" msgstr "" #: xpn_src/Config_Win.py:1370 msgid "Display" msgstr "" #: xpn_src/Config_Win.py:1370 msgid "Configure Display Profile" msgstr "" #: xpn_src/Config_Win.py:1372 msgid "Configure Group Properties" msgstr "" #: xpn_src/Config_Win.py:1373 msgid "Misc" msgstr "" #: xpn_src/Config_Win.py:1373 msgid "Configure Miscellaneous Properties" msgstr "" #: xpn_src/Config_Win.py:1397 xpn_src/Groups_Vs_ID.py:98 xpn_src/ID_Win.py:381 #: xpn_src/Score.py:1001 xpn_src/Server_Win.py:136 msgid "Close window. Discard changes" msgstr "" #: xpn_src/Config_Win.py:1404 xpn_src/Groups_Vs_ID.py:105 #: xpn_src/ID_Win.py:388 xpn_src/Server_Win.py:143 msgid "Close window and save settings" msgstr "" #: xpn_src/Connections_Handler.py:143 xpn_src/Connections_Handler.py:168 #: xpn_src/Connections_Handler.py:429 xpn_src/Connections_Handler.py:453 #, python-format msgid "" "No connection with server : %s. Configure NNTP Server Address or try later." msgstr "" #: xpn_src/Connections_Handler.py:147 xpn_src/Connections_Handler.py:433 #, python-format msgid "Connection estabilished with server: %s" msgstr "" #: xpn_src/Connections_Handler.py:199 xpn_src/Connections_Handler.py:216 #: xpn_src/Connections_Handler.py:261 xpn_src/Connections_Handler.py:269 #: xpn_src/Connections_Handler.py:311 xpn_src/Connections_Handler.py:349 #: xpn_src/Connections_Handler.py:375 #, python-format msgid "Server error: %s" msgstr "" #: xpn_src/Connections_Handler.py:202 xpn_src/Connections_Handler.py:219 #: xpn_src/Connections_Handler.py:273 xpn_src/Connections_Handler.py:315 #: xpn_src/Connections_Handler.py:353 xpn_src/Connections_Handler.py:381 #, python-format msgid "%s response : %s" msgstr "" #: xpn_src/Connections_Handler.py:265 msgid "Server Error: " msgstr "" #: xpn_src/Connections_Handler.py:265 msgid "You can try on Google:" msgstr "" #: xpn_src/Connections_Handler.py:496 msgid "Connection closed" msgstr "" #: xpn_src/Connections_Handler.py:538 #, python-format msgid "" "No connection with server : %s. Configure SMTP Server Address or try later." msgstr "" #: xpn_src/Connections_Handler.py:542 #, python-format msgid "Connection estabilished with: %s" msgstr "" #: xpn_src/Connections_Handler.py:565 msgid "Unable to send the message. Control Server Logs." msgstr "" #: xpn_src/Connections_Handler.py:568 msgid "Email Sent" msgstr "" #: xpn_src/Dialogs.py:19 msgid "About" msgstr "" #: xpn_src/Dialogs.py:68 msgid "Choose the Server" msgstr "" #: xpn_src/Dialogs.py:91 msgid "First you have to configure at least one Server" msgstr "" #: xpn_src/Dialogs.py:101 msgid "Error Dialog" msgstr "" #: xpn_src/Dialogs.py:129 msgid "Last Error" msgstr "" #: xpn_src/Dialogs.py:131 msgid "Errors Log" msgstr "" #: xpn_src/Dialogs.py:141 msgid "Message-ID Search Dialog" msgstr "" #: xpn_src/Dialogs.py:143 msgid "Message-ID to search" msgstr "" #: xpn_src/Dialogs.py:151 msgid "Search in current group" msgstr "" #: xpn_src/Dialogs.py:152 msgid "Search in subscribed groups" msgstr "" #: xpn_src/Dialogs.py:153 msgid "Search on Google" msgstr "" #: xpn_src/Dialogs.py:187 msgid "Shortcut Dialog" msgstr "" #: xpn_src/Dialogs.py:188 msgid "Type your Shortcut" msgstr "" #: xpn_src/Dialogs.py:190 msgid "Press OK to confirm it" msgstr "" #: xpn_src/Dialogs.py:222 msgid "Window" msgstr "" #: xpn_src/Dialogs.py:224 xpn_src/KeyBindings.py:443 msgid "Shortcut" msgstr "" #: xpn_src/Dialogs.py:226 xpn_src/KeyBindings.py:442 xpn_src/Score.py:903 msgid "Action" msgstr "" #: xpn_src/Edit_Mail_Win.py:105 xpn_src/Edit_Win.py:113 msgid "Error while opening external editor" msgstr "" #: xpn_src/Edit_Mail_Win.py:193 xpn_src/Edit_Win.py:203 msgid "tags.txt not found" msgstr "" #: xpn_src/Edit_Mail_Win.py:217 xpn_src/Edit_Win.py:227 msgid "Signature file not found" msgstr "" #: xpn_src/Edit_Mail_Win.py:362 xpn_src/Edit_Mail_Win.py:363 #: xpn_src/Edit_Win.py:420 xpn_src/Edit_Win.py:421 msgid "* From field appears to be invalid\n" msgstr "" #: xpn_src/Edit_Mail_Win.py:368 xpn_src/Edit_Mail_Win.py:369 msgid "* To field appears to be invalid\n" msgstr "" #: xpn_src/Edit_Mail_Win.py:384 xpn_src/Edit_Win.py:444 msgid "* Article seems to be empty\n" msgstr "" #: xpn_src/Edit_Mail_Win.py:385 xpn_src/Edit_Win.py:445 msgid "* Article doesn't contain new text\n" msgstr "" #: xpn_src/Edit_Mail_Win.py:386 xpn_src/Edit_Win.py:446 #, python-format msgid "* Article contains more than 95% of quoted text\n" msgstr "" #: xpn_src/Edit_Mail_Win.py:392 xpn_src/Edit_Win.py:452 msgid "* Subject field is empty\n" msgstr "" #: xpn_src/Edit_Mail_Win.py:394 xpn_src/Edit_Win.py:460 msgid "* From field is empty\n" msgstr "" #: xpn_src/Edit_Mail_Win.py:398 msgid "* To field is empty\n" msgstr "" #: xpn_src/Edit_Mail_Win.py:422 xpn_src/Edit_Win.py:482 msgid "Errors:" msgstr "" #: xpn_src/Edit_Mail_Win.py:424 xpn_src/Edit_Mail_Win.py:428 #: xpn_src/Edit_Win.py:484 xpn_src/Edit_Win.py:488 msgid "Warnings:" msgstr "" #: xpn_src/Edit_Mail_Win.py:428 xpn_src/Edit_Win.py:488 msgid "" "\n" "\n" "Do you want to send the Article?" msgstr "" #: xpn_src/Edit_Mail_Win.py:457 xpn_src/Edit_Win.py:518 #: xpn_src/Outbox_Manager.py:255 msgid "Problems while opening : " msgstr "" #: xpn_src/Edit_Mail_Win.py:504 xpn_src/Edit_Win.py:563 #, python-format msgid "row:%d, col:%d" msgstr "" #: xpn_src/Edit_Mail_Win.py:635 xpn_src/Edit_Win.py:727 msgid "_Article" msgstr "" #: xpn_src/Edit_Mail_Win.py:636 xpn_src/Edit_Win.py:728 msgid "_Send Article" msgstr "" #: xpn_src/Edit_Mail_Win.py:636 xpn_src/Edit_Win.py:728 #: xpn_src/KeyBindings.py:116 msgid "Send Article" msgstr "" #: xpn_src/Edit_Mail_Win.py:637 xpn_src/Edit_Win.py:729 msgid "Send Article _Later" msgstr "" #: xpn_src/Edit_Mail_Win.py:637 xpn_src/Edit_Win.py:729 #: xpn_src/KeyBindings.py:117 msgid "Send Article Later" msgstr "" #: xpn_src/Edit_Mail_Win.py:638 xpn_src/Edit_Win.py:730 #: xpn_src/KeyBindings.py:118 msgid "Save Article as Draft" msgstr "" #: xpn_src/Edit_Mail_Win.py:639 xpn_src/Edit_Win.py:731 msgid "_Discard Article" msgstr "" #: xpn_src/Edit_Mail_Win.py:639 xpn_src/Edit_Win.py:731 #: xpn_src/KeyBindings.py:119 msgid "Discard Article" msgstr "" #: xpn_src/Edit_Mail_Win.py:640 xpn_src/Edit_Win.py:732 msgid "_ROT13 Selected Text" msgstr "" #: xpn_src/Edit_Mail_Win.py:641 xpn_src/Edit_Win.py:733 msgid "Launch External _Editor" msgstr "" #: xpn_src/Edit_Mail_Win.py:641 xpn_src/Edit_Win.py:733 #: xpn_src/KeyBindings.py:121 msgid "Launch External Editor" msgstr "" #: xpn_src/Edit_Mail_Win.py:642 xpn_src/Edit_Win.py:734 msgid "_Insert Spoiler Char" msgstr "" #: xpn_src/Edit_Mail_Win.py:642 xpn_src/Edit_Win.py:734 #: xpn_src/KeyBindings.py:122 msgid "Insert Spoiler Char" msgstr "" #: xpn_src/Edit_Mail_Win.py:728 msgid "Edit Mail" msgstr "" #: xpn_src/Edit_Mail_Win.py:749 xpn_src/Edit_Win.py:834 #: xpn_src/Groups_Vs_ID.py:50 xpn_src/ID_Win.py:181 msgid "Identity" msgstr "" #: xpn_src/Edit_Mail_Win.py:776 msgid "To : " msgstr "" #: xpn_src/Edit_Mail_Win.py:779 xpn_src/Edit_Win.py:899 msgid "From : " msgstr "" #: xpn_src/Edit_Mail_Win.py:782 xpn_src/Edit_Win.py:902 msgid "Subject : " msgstr "" #: xpn_src/Edit_Mail_Win.py:785 xpn_src/Edit_Win.py:980 msgid "Charset : " msgstr "" #: xpn_src/Edit_Win.py:427 msgid "* Newsgroups field appears to be invalid\n" msgstr "" #: xpn_src/Edit_Win.py:454 msgid "* Newsgroups field is empty\n" msgstr "" #: xpn_src/Edit_Win.py:813 msgid "Edit Article" msgstr "" #: xpn_src/Edit_Win.py:896 msgid "Newsgroups : " msgstr "" #: xpn_src/Edit_Win.py:952 msgid "More Headers" msgstr "" #: xpn_src/Edit_Win.py:956 msgid "Reply-To : " msgstr "" #: xpn_src/Edit_Win.py:959 msgid "Sender : " msgstr "" #: xpn_src/Edit_Win.py:962 msgid "Organization : " msgstr "" #: xpn_src/Edit_Win.py:965 msgid "Followup-To : " msgstr "" #: xpn_src/Edit_Win.py:968 msgid "Mail-Copies-To : " msgstr "" #: xpn_src/Edit_Win.py:971 msgid "Archive : " msgstr "" #: xpn_src/Edit_Win.py:974 msgid "Supersedes : " msgstr "" #: xpn_src/Edit_Win.py:977 msgid "Approved : " msgstr "" #: xpn_src/Edit_Win.py:1019 xpn_src/ID_Win.py:354 msgid "Custom Headers (X-Headers)" msgstr "" #: xpn_src/Edit_Win.py:1101 xpn_src/Groups_Win.py:214 #: xpn_src/Groups_Win.py:215 xpn_src/Newsrc.py:191 msgid "First you have to create at least one Identity" msgstr "" #: xpn_src/Find_Win.py:152 msgid "Find Article" msgstr "" #: xpn_src/Find_Win.py:166 xpn_src/Find_Win.py:512 xpn_src/ID_Win.py:331 msgid "Message-ID" msgstr "" #: xpn_src/Find_Win.py:169 xpn_src/Find_Win.py:515 msgid "References" msgstr "" #: xpn_src/Find_Win.py:172 xpn_src/Find_Win.py:518 xpn_src/ID_Win.py:228 msgid "Body" msgstr "" #: xpn_src/Find_Win.py:180 xpn_src/Find_Win.py:526 msgid "Fields" msgstr "" #: xpn_src/Find_Win.py:206 xpn_src/Find_Win.py:348 msgid "Start from the Beginning" msgstr "" #: xpn_src/Find_Win.py:207 xpn_src/Find_Win.py:349 xpn_src/Find_Win.py:553 #: xpn_src/Groups_Win.py:345 msgid "Use Regular Expression" msgstr "" #: xpn_src/Find_Win.py:208 xpn_src/Find_Win.py:350 xpn_src/Find_Win.py:554 msgid "Case Insensitive" msgstr "" #: xpn_src/Find_Win.py:210 xpn_src/Find_Win.py:556 msgid "Rule used to combine search results" msgstr "" #: xpn_src/Find_Win.py:212 xpn_src/Find_Win.py:558 msgid "AND" msgstr "" #: xpn_src/Find_Win.py:213 xpn_src/Find_Win.py:559 msgid "OR" msgstr "" #: xpn_src/Find_Win.py:222 xpn_src/Find_Win.py:567 xpn_src/Score.py:734 msgid "Rules" msgstr "" #: xpn_src/Find_Win.py:336 msgid "Search in the Body" msgstr "" #: xpn_src/Find_Win.py:344 msgid "Text or Regular Expression" msgstr "" #: xpn_src/Find_Win.py:498 msgid "Global Search" msgstr "" #: xpn_src/Groups_Vs_ID.py:46 msgid "Group" msgstr "" #: xpn_src/Groups_Win.py:84 msgid "Please wait, I'm downloading the list" msgstr "" #: xpn_src/Groups_Win.py:146 msgid "Searching..." msgstr "" #: xpn_src/Groups_Win.py:182 xpn_src/Newsrc.py:243 msgid "Group subscribed" msgstr "" #: xpn_src/Groups_Win.py:224 msgid "The Group Name seems to be wrong" msgstr "" #: xpn_src/Groups_Win.py:246 msgid "Group removed" msgstr "" #: xpn_src/Groups_Win.py:299 xpn_src/Groups_Win.py:354 #: xpn_src/Groups_Win.py:440 msgid "NewsGroups" msgstr "" #: xpn_src/Groups_Win.py:333 msgid "Search Group" msgstr "" #: xpn_src/Groups_Win.py:337 msgid "Start searching" msgstr "" #: xpn_src/Groups_Win.py:340 msgid "Perform Live Search" msgstr "" #: xpn_src/Groups_Win.py:349 msgid "Show Full List" msgstr "" #: xpn_src/Groups_Win.py:354 msgid "Mode" msgstr "" #: xpn_src/Groups_Win.py:379 msgid "Get Newsgroups List" msgstr "" #: xpn_src/Groups_Win.py:383 msgid "This could take several minutes" msgstr "" #: xpn_src/Groups_Win.py:396 msgid "Articles Number" msgstr "" #: xpn_src/Groups_Win.py:402 msgid "Download this number of articles (headers only)" msgstr "" #: xpn_src/Groups_Win.py:406 xpn_src/KeyBindings.py:71 msgid "Subscribed Groups" msgstr "" #: xpn_src/Groups_Win.py:427 msgid "Subscribe selected groups" msgstr "" #: xpn_src/Groups_Win.py:437 msgid "UnSubscribe selected groups" msgstr "" #: xpn_src/Groups_Win.py:450 msgid "Subscribe Manually" msgstr "" #: xpn_src/Groups_Win.py:465 msgid "Close this window" msgstr "" #: xpn_src/Groups_Win.py:482 msgid "Building Newsgroups list" msgstr "" #: xpn_src/Groups_Win.py:489 msgid "You have to download newsgroups list" msgstr "" #: xpn_src/Groups_Win.py:494 msgid "Newsgroups list loaded" msgstr "" #: xpn_src/Headers_List.py:125 msgid "Standard Headers" msgstr "" #: xpn_src/Headers_List.py:127 msgid "Shown Headers" msgstr "" #: xpn_src/Headers_List.py:204 msgid "Add Manually" msgstr "" #: xpn_src/ID_Win.py:27 msgid "Select Signature File" msgstr "" #: xpn_src/ID_Win.py:97 msgid "Please set the Identity Name" msgstr "" #: xpn_src/ID_Win.py:165 msgid "Identity Settings" msgstr "" #: xpn_src/ID_Win.py:171 msgid "Personal Informations" msgstr "" #: xpn_src/ID_Win.py:198 msgid "Name or NickName" msgstr "" #: xpn_src/ID_Win.py:200 msgid "E-Mail address" msgstr "" #: xpn_src/ID_Win.py:208 msgid "Use different From field in mail replies" msgstr "" #: xpn_src/ID_Win.py:212 msgid "Name or NickName (for Mail replies)" msgstr "" #: xpn_src/ID_Win.py:215 msgid "E-Mail address (for Mail replies)" msgstr "" #: xpn_src/ID_Win.py:233 msgid "Headers" msgstr "" #: xpn_src/ID_Win.py:239 msgid "Compose" msgstr "" #: xpn_src/ID_Win.py:248 msgid " Wrap column" msgstr "" #: xpn_src/ID_Win.py:253 msgid "Attribution line" msgstr "" #: xpn_src/ID_Win.py:258 msgid "" "%s = Subject\n" "%g = Newsgroups\n" "%f = From\n" "%n = Nick\n" "%e = Email\n" "%d = Date" msgstr "" #: xpn_src/ID_Win.py:269 msgid "Signature" msgstr "" #: xpn_src/ID_Win.py:279 msgid "Use random taglines" msgstr "" #: xpn_src/ID_Win.py:280 msgid "Change Signature Path" msgstr "" #: xpn_src/ID_Win.py:284 msgid "Add a Tagline" msgstr "" #: xpn_src/ID_Win.py:297 msgid "Optional Headers" msgstr "" #: xpn_src/ID_Win.py:310 msgid "Reply-To" msgstr "" #: xpn_src/ID_Win.py:313 msgid "Organization" msgstr "" #: xpn_src/ID_Win.py:315 msgid "Mail-Copies-To" msgstr "" #: xpn_src/ID_Win.py:337 msgid "Generate Message-ID" msgstr "" #: xpn_src/ID_Win.py:341 msgid "" "You can write here a FQDN (Fully Qualified Domain Name) that will be used to " "compose the Message-ID.\n" "Otherwise if you leave this field blank XPN will use your Host Name." msgstr "" #: xpn_src/ID_Win.py:343 msgid "Fully Qualified Domain Name" msgstr "" #: xpn_src/KeyBindings.py:20 msgid "File" msgstr "" #: xpn_src/KeyBindings.py:29 msgid "Search" msgstr "" #: xpn_src/KeyBindings.py:31 msgid "Filter Articles..." msgstr "" #: xpn_src/KeyBindings.py:34 msgid "View" msgstr "" #: xpn_src/KeyBindings.py:57 msgid "Navigate" msgstr "" #: xpn_src/KeyBindings.py:66 msgid "Focus to groups Pane" msgstr "" #: xpn_src/KeyBindings.py:69 msgid "Zoom groups Pane" msgstr "" #: xpn_src/KeyBindings.py:125 msgid "Outbox" msgstr "" #: xpn_src/KeyBindings.py:126 xpn_src/Outbox_Manager.py:428 msgid "Send Queued Articles" msgstr "" #: xpn_src/KeyBindings.py:127 xpn_src/Outbox_Manager.py:429 msgid "Send Queued Mails" msgstr "" #: xpn_src/KeyBindings.py:128 xpn_src/Outbox_Manager.py:430 msgid "Edit Article/Mail" msgstr "" #: xpn_src/KeyBindings.py:129 xpn_src/Outbox_Manager.py:431 msgid "Delete Article/Mail" msgstr "" #: xpn_src/KeyBindings.py:281 xpn_src/KeyBindings.py:287 #: xpn_src/KeyBindings.py:350 xpn_src/KeyBindings.py:382 msgid "Edit Window" msgstr "" #: xpn_src/KeyBindings.py:282 xpn_src/KeyBindings.py:295 #: xpn_src/KeyBindings.py:340 xpn_src/KeyBindings.py:375 msgid "Main Window" msgstr "" #: xpn_src/KeyBindings.py:288 xpn_src/KeyBindings.py:294 #: xpn_src/KeyBindings.py:359 xpn_src/KeyBindings.py:389 msgid "Outbox Window" msgstr "" #: xpn_src/KeyBindings.py:299 msgid "Found duplicated shortcuts on different windows" msgstr "" #: xpn_src/KeyBindings.py:299 msgid "That's not a problem, the shortcut will work only on the active window " msgstr "" #: xpn_src/KeyBindings.py:301 xpn_src/KeyBindings.py:363 xpn_src/Score.py:423 msgid "No Errors" msgstr "" #: xpn_src/KeyBindings.py:361 msgid "Found duplicated shortcuts on the same windows" msgstr "" #: xpn_src/KeyBindings.py:426 msgid "Keyboard Shortcuts" msgstr "" #: xpn_src/KeyBindings.py:448 msgid "Change Shortcut" msgstr "" #: xpn_src/KeyBindings.py:451 msgid "Default Shortcuts" msgstr "" #: xpn_src/KeyBindings.py:454 msgid "Clear Shortcuts" msgstr "" #: xpn_src/KeyBindings.py:457 msgid "Duplicates Warnings" msgstr "" #: xpn_src/KeyBindings.py:460 msgid "Duplicates Errors" msgstr "" #: xpn_src/Newsrc.py:150 msgid "Newsrc successful exported" msgstr "" #: xpn_src/Outbox_Manager.py:65 msgid "OutBox" msgstr "" #: xpn_src/Outbox_Manager.py:68 msgid "OutGoing Articles" msgstr "" #: xpn_src/Outbox_Manager.py:71 msgid "OutGoing Mails" msgstr "" #: xpn_src/Outbox_Manager.py:75 msgid "Drafts" msgstr "" #: xpn_src/Outbox_Manager.py:78 msgid "Draft Articles" msgstr "" #: xpn_src/Outbox_Manager.py:81 msgid "Draft Mails" msgstr "" #: xpn_src/Outbox_Manager.py:85 msgid "Sent" msgstr "" #: xpn_src/Outbox_Manager.py:88 msgid "Sent Articles" msgstr "" #: xpn_src/Outbox_Manager.py:91 msgid "Sent Mails" msgstr "" #: xpn_src/Outbox_Manager.py:99 xpn_src/Outbox_Manager.py:273 msgid "Problems while opening News OutBox" msgstr "" #: xpn_src/Outbox_Manager.py:107 xpn_src/Outbox_Manager.py:335 msgid "Problems while opening Mail OutBox" msgstr "" #: xpn_src/Outbox_Manager.py:115 msgid "Problems while opening News Drafts" msgstr "" #: xpn_src/Outbox_Manager.py:123 msgid "Problems while opening Mail Drafts" msgstr "" #: xpn_src/Outbox_Manager.py:131 msgid "Problems while opening Sent Articles" msgstr "" #: xpn_src/Outbox_Manager.py:139 msgid "Problems while opening Sent Mails" msgstr "" #: xpn_src/Outbox_Manager.py:170 msgid "Problems while opening folder :" msgstr "" #: xpn_src/Outbox_Manager.py:180 xpn_src/Outbox_Manager.py:293 msgid "Problems while opening article :" msgstr "" #: xpn_src/Outbox_Manager.py:246 #, python-format msgid "Problems while deleting the article: %s" msgstr "" #: xpn_src/Outbox_Manager.py:247 msgid "Article Deleted" msgstr "" #: xpn_src/Outbox_Manager.py:295 msgid "Sending Article: " msgstr "" #: xpn_src/Outbox_Manager.py:321 #, python-format msgid "Sent %d Articles" msgstr "" #: xpn_src/Outbox_Manager.py:346 msgid "Problems while opening mail :" msgstr "" #: xpn_src/Outbox_Manager.py:348 msgid "Sending Mail: " msgstr "" #: xpn_src/Outbox_Manager.py:373 #, python-format msgid "Sent %d Mails" msgstr "" #: xpn_src/Outbox_Manager.py:427 msgid "_Outbox" msgstr "" #: xpn_src/Outbox_Manager.py:428 msgid "_Send Queued Articles" msgstr "" #: xpn_src/Outbox_Manager.py:429 msgid "Send Queued _Mails" msgstr "" #: xpn_src/Outbox_Manager.py:430 msgid "_Edit Article/Mail" msgstr "" #: xpn_src/Outbox_Manager.py:431 msgid "_Delete Article/Mail" msgstr "" #: xpn_src/Outbox_Manager.py:432 msgid "_Exit" msgstr "" #: xpn_src/Outbox_Manager.py:452 msgid "Outbox Manager" msgstr "" #: xpn_src/Outbox_Manager.py:490 msgid "Folder" msgstr "" #: xpn_src/Outbox_Manager.py:495 msgid "Number" msgstr "" #: xpn_src/Outbox_Manager.py:519 msgid "Newsgroups/To" msgstr "" #: xpn_src/Score.py:122 msgid "Syntax Error: Unknown Action on line:: " msgstr "" #: xpn_src/Score.py:124 msgid "Syntax Error: Bad Score Modifier on line:: " msgstr "" #: xpn_src/Score.py:126 msgid "Syntax Error: Unknown Header Name on line:: " msgstr "" #: xpn_src/Score.py:128 msgid "Syntax Error: Bad Match Rule on line:: " msgstr "" #: xpn_src/Score.py:180 msgid "Syntax Error: Missing scope for line :: " msgstr "" #: xpn_src/Score.py:182 msgid "Syntax Error: Bad Line:: " msgstr "" #: xpn_src/Score.py:371 msgid "Scope/Score Mod" msgstr "" #: xpn_src/Score.py:372 msgid "Header" msgstr "" #: xpn_src/Score.py:373 msgid "Match Rule" msgstr "" #: xpn_src/Score.py:676 msgid "Scoring Rules" msgstr "" #: xpn_src/Score.py:692 msgid "Correct Rules" msgstr "" #: xpn_src/Score.py:702 msgid "Score File Editor" msgstr "" #: xpn_src/Score.py:720 msgid "ReScan Rules" msgstr "" #: xpn_src/Score.py:722 msgid "Show Errors" msgstr "" #: xpn_src/Score.py:746 xpn_src/Score.py:844 msgid "Groups Scope" msgstr "" #: xpn_src/Score.py:768 xpn_src/Score.py:865 msgid "Condition" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Contains String" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Doesn't Contain String" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Matches RegEx" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Doesn't Match RegEx" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Greater Than" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Not Greater Than" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Lower Than" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Not Lower Than" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Equal To (numbers only)" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Different From (numbers only)" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "In Range" msgstr "" #: xpn_src/Score.py:780 xpn_src/Score.py:877 msgid "Out Of Range" msgstr "" #: xpn_src/Score.py:788 xpn_src/Score.py:885 xpn_src/Score.py:966 msgid "Case Sensitive" msgstr "" #: xpn_src/Score.py:792 xpn_src/Score.py:889 msgid "Lower Limit" msgstr "" #: xpn_src/Score.py:793 xpn_src/Score.py:890 msgid "Upper Limit" msgstr "" #: xpn_src/Score.py:811 msgid "Raise Score" msgstr "" #: xpn_src/Score.py:811 msgid "Lower Score" msgstr "" #: xpn_src/Score.py:811 msgid "Set Score" msgstr "" #: xpn_src/Score.py:825 xpn_src/Score.py:939 msgid "Add Rule" msgstr "" #: xpn_src/Score.py:832 msgid "New Scoring Rule" msgstr "" #: xpn_src/Score.py:911 msgid "Kill" msgstr "" #: xpn_src/Score.py:911 msgid "Mark Read" msgstr "" #: xpn_src/Score.py:911 msgid "Mark Unread" msgstr "" #: xpn_src/Score.py:911 msgid "Mark for Download" msgstr "" #: xpn_src/Score.py:911 msgid "UnMark for Download" msgstr "" #: xpn_src/Score.py:911 msgid "Retrieve" msgstr "" #: xpn_src/Score.py:911 msgid "Keep" msgstr "" #: xpn_src/Score.py:911 msgid "UnKeep" msgstr "" #: xpn_src/Score.py:911 msgid "Watch" msgstr "" #: xpn_src/Score.py:911 msgid "Ignore" msgstr "" #: xpn_src/Score.py:911 msgid "UnSetWatchIgnore" msgstr "" #: xpn_src/Score.py:911 msgid "SetColor" msgstr "" #: xpn_src/Score.py:919 msgid "Foreground Color" msgstr "" #: xpn_src/Score.py:920 msgid "Background Color" msgstr "" #: xpn_src/Score.py:946 msgid "New Action Rule" msgstr "" #: xpn_src/Score.py:957 msgid "Regular Expression" msgstr "" #: xpn_src/Score.py:964 msgid "Test Regular Expression" msgstr "" #: xpn_src/Score.py:974 msgid "Test Text" msgstr "" #: xpn_src/Score.py:991 msgid "RE Tester" msgstr "" #: xpn_src/Score.py:1006 msgid "Close window. Save Changes" msgstr "" #: xpn_src/Server_Win.py:53 msgid "Please set the Server Name" msgstr "" #: xpn_src/Server_Win.py:81 msgid "Server Settings" msgstr "" #: xpn_src/Server_Win.py:85 msgid "NNTP Server" msgstr "" #: xpn_src/Server_Win.py:102 msgid "Use SSL (Secure Socket Layer)" msgstr "" #: xpn_src/Server_Win.py:107 msgid "NNTP Server Address" msgstr "" #: xpn_src/Server_Win.py:108 msgid "Port Number" msgstr "" #: xpn_src/Show_Logs.py:48 msgid "Server Logs Viewer" msgstr "" #: xpn_src/Show_Logs.py:55 msgid "Server Logs" msgstr "" xpn-1.2.6/xpn_src/0000755000175000017500000000000011141275756012140 5ustar antantxpn-1.2.6/xpn_src/Edit_Win.py0000644000175000017500000013445011141275756014223 0ustar antantimport gtk import pango import sys import time import cPickle import os import re import ConfigParser from random import randint,seed from locale import getdefaultlocale from email.Utils import parseaddr, formatdate from xpn_src.Article import Article_To_Send from xpn_src.Dialogs import Dialog_YES_NO, Dialog_OK from xpn_src.Charset_List import encodings_list, guess_list, encodings_tip, load_ordered_list from xpn_src.Connections_Handler import Connection, SSLConnection from xpn_src.UserDir import get_wdir from xpn_src.KeyBindings import load_shortcuts ui_string=""" """ class Edit_Win: def show(self): self.win.show_all() #setting the focus if self.is_fup: self.textview.grab_focus() else: if self.newsgroups_entry.child.get_text()=="": self.newsgroups_entry.child.grab_focus() else: self.subj_entry.grab_focus() def delete_event(self,widget,event,data=None): self.editwin_width,self.editwin_height=self.win.get_size() self.save_sizes() return False def destroy(self,obj): for connection in self.connectionsPool.itervalues(): connection.closeConnection() self.save_sizes() self.win.destroy() if self.outboxManager: self.outboxManager.populateFolderTree() def guess_encoding(self,text): for best_enc in guess_list: try: unicode(text,best_enc,"strict") except: pass else: break return best_enc def external_editor(self,obj,command): body="" bounds=self.buffer.get_bounds() if bounds: start,stop=bounds body=self.buffer.get_text(start,stop,True).decode("utf-8") self.buffer.delete(start,stop) try: system_enc=getdefaultlocale()[1] body=body.encode(system_enc,"replace") except: body=body.encode(self.fallback_charset,"replace") filename=(os.path.join(self.wdir,"temp_article.txt")) f=open(filename,"w") f.write(body) f.close() command=command.replace("%s",filename) result=os.system(command) if result==0: f=open(filename,"r") body=f.read().split("\n") f.close() os.remove(filename) best_enc=self.guess_encoding("".join(body)) body=[unicode(line,best_enc,"strict") for line in body] self.show_article(body) else: self.statusbar.push(1,_("Error while opening external editor")) def update_newsgroups_entry(self,value,subscribed): for group,server,id in subscribed: self.newsgroups_entry.append_text(group) newsgroups=value self.newsgroups_entry.child.set_text(newsgroups.encode("utf-8")) def update_subject_entry(self,subj): if subj[0:3].lower()!="re:": subj="Re: "+subj self.subj_entry.set_text(subj.encode("utf-8")) def update_references(self,article_references): mom=article_references.split() article_references=" ".join(mom) #in this way I removed FWSP tabs if len(mom)>21: #The number of References is greater than 21 for i in range(0,len(mom)-21): mom.remove(mom[1]) refs="" for i in range(len(mom)): refs=refs+mom[i]+" " article_references=refs.strip() refs_len=len(article_references) if refs_len>980: #References plus "References: " excedes 998 octets mom=article_references.split() while refs_len>980: mom_len=len(mom[1]) mom.remove(mom[1]) refs_len=refs_len-mom_len refs="" for i in range(len(mom)): refs=refs+mom[i]+" " article_references=refs.strip() article_references=article_references.strip() return article_references def wrap_line(self,string_to_wrap,wrap=73): split_string=string_to_wrap.split() new_line="" lines=[] for word in split_string: if len(new_line)+len(word)+10: if line[0]!=">": quoted_body.append("> "+line) else: quoted_body.append(">"+line) else: quoted_body.append(">"+line) self.show_article(quoted_body) def tag_line(self): try: f=open(os.path.join(self.wdir,"tags.txt"),"r") except IOError: return _("tags.txt not found") else: list=f.readlines() f.close() seed() if len(list)>0: tag=list[randint(0,len(list)-1)] best_enc=self.guess_encoding(tag) tag=unicode(tag,best_enc) tag_wrapped=self.wrap_line(tag) tag="" for line in tag_wrapped: tag=tag+line+"\n" return tag else: return "XPN:: http://xpn.altervista.org" def add_sign(self): sign=[] delimiter=False if self.cp_id.get(self.id_name,"sign")!="": try: sign_file=open(os.path.join(self.wdir,self.cp_id.get(self.id_name,"sign")),"r") except IOError: sign=_("Signature file not found") best_enc="utf-8" else: sign=sign_file.readlines() best_enc=self.guess_encoding("".join(sign)) sign_file.close() self.insert_with_tags("\n-- \n","sign") delimiter=True use_tags=self.cp_id.get(self.id_name,"use_tags") if use_tags=="True": tag=self.tag_line() if delimiter==False: self.insert_with_tags("\n-- \n","sign") self.insert_with_tags(tag,"sign") for i in range(len(sign)): self.insert_with_tags(sign[i].decode(best_enc),"sign") def show_article(self,article): is_sign=False is_quote=False def quote_depth(line): count=0 for char in line: if char==">": count=count+1 else: break if count>3: count=3 return str(count) for line in article: line=line.replace("\r","") #this is needed for some strange articles if len(line)>0: if line[0]==">": is_quote=True elif (len(line)==2 and line[0:2]=="--") or (len(line)==3 and line[0:3]=="-- "): is_sign=True is_quote=False else: is_quote=False if is_quote and not is_sign: quote_level=quote_depth(line) self.insert_with_tags(line,"quote"+quote_level) elif is_sign: self.insert_with_tags(line,"sign") else: self.insert_with_tags(line,"text") self.insert("\n") def set_text_color(self,color): text_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.text_tag: self.text_tag=gtk.TextTag("text") self.tag_table.add(self.text_tag) self.text_tag.set_property("foreground-gdk",text_color) def set_quote_color(self,color,level): if level==1: quote1_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.quote1_tag: self.quote1_tag=gtk.TextTag("quote1") self.tag_table.add(self.quote1_tag) self.quote1_tag.set_property("foreground-gdk",quote1_color) elif level==2: quote2_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.quote2_tag: self.quote2_tag=gtk.TextTag("quote2") self.tag_table.add(self.quote2_tag) self.quote2_tag.set_property("foreground-gdk",quote2_color) else: quote3_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.quote3_tag: self.quote3_tag=gtk.TextTag("quote3") self.tag_table.add(self.quote3_tag) self.quote3_tag.set_property("foreground-gdk",quote3_color) def set_sign_color(self,color): sign_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.sign_tag: self.sign_tag=gtk.TextTag("sign") self.tag_table.add(self.sign_tag) self.sign_tag.set_property("foreground-gdk",sign_color) def set_background(self,configs): color=configs["background_color"] color=gtk.gdk.color_parse(color) self.textview.modify_base(gtk.STATE_NORMAL,color) def set_foreground(self,configs): color=configs["text_color"] color=gtk.gdk.color_parse(color) self.textview.modify_text(gtk.STATE_NORMAL,color) def insert(self,string): mark=self.buffer.get_insert() iter=self.buffer.get_iter_at_mark(mark) self.buffer.insert(iter,string.encode("utf-8")) def insert_with_tags(self,string,tag): self.buffer.insert_with_tags_by_name(self.buffer.get_end_iter(),string.encode("utf-8"),tag) def rot13(self,text): "Rot13 the string passed" string_coded = "" dic={'a':'n','b':'o','c':'p','d':'q','e':'r','f':'s','g':'t', 'h':'u','i':'v','j':'w','k':'x','l':'y','m':'z', 'n':'a','o':'b','p':'c','q':'d','r':'e','s':'f','t':'g', 'u':'h','v':'i','w':'j','x':'k','y':'l','z':'m', 'A':'N','B':'O','C':'P','D':'Q','E':'R','F':'S','G':'T', 'H':'U','I':'V','J':'W','K':'X','L':'Y','M':'Z', 'N':'A','O':'B','P':'C','Q':'D','R':'E','S':'F','T':'G', 'U':'H','V':'I','W':'J','X':'K','Y':'L','Z':'M'} for c in text: char=dic.get(c,c) string_coded=string_coded+char return string_coded def apply_rot13(self,obj): bounds=self.buffer.get_selection_bounds() if bounds: start=bounds[0] stop=bounds[1] text=self.buffer.get_text(start,stop,True).decode("utf-8") text_rotted=self.rot13(text) self.buffer.delete_selection(False,False) self.insert(text_rotted) def get_custom_headers(self,old_article): custom_names=[] custom_values=[] if self.reply_to_entry.get_text()!="": custom_names.append("Reply-To") custom_values.append(self.reply_to_entry.get_text().decode("utf-8")) if self.sender_entry.get_text()!="": custom_names.append("Sender") custom_values.append(self.sender_entry.get_text().decode("utf-8")) if self.organization_entry.get_text()!="": custom_names.append("Organization") custom_values.append(self.organization_entry.get_text().decode("utf-8")) if self.followup_to_entry.get_text()!="": custom_names.append("Followup-To") custom_values.append(self.followup_to_entry.get_text().decode("utf-8")) if self.mail_copies_to_entry.get_text()!="": custom_names.append("Mail-Copies-To") custom_values.append(self.mail_copies_to_entry.get_text().decode("utf-8")) if self.archive_entry.get_text()!="": custom_names.append("Archive") custom_values.append(self.archive_entry.get_text().decode("utf-8")) if self.supersedes_entry.get_text()!="": custom_names.append("Supersedes") custom_values.append(self.supersedes_entry.get_text().decode("utf-8")) if self.approved_entry.get_text()!="": custom_names.append("Approved") custom_values.append(self.approved_entry.get_text().decode("utf-8")) bounds=self.custom_headers_buffer.get_bounds() if bounds: start,stop=bounds headers=self.custom_headers_buffer.get_text(start,stop,True).decode("utf-8").split("\n") for line in headers: if ":" in line: div_pos=line.find(":") name=line[:div_pos].strip() value=line[div_pos+1:].strip() if len(name)>2: if name[0:2].lower()=="x-": custom_names.append(name) else: custom_names.append("X-"+name) if old_article!=None and ("face" not in name.lower()): custom_values.append(value.replace("%n",old_article.nick).replace("%e",old_article.email).replace("%f",old_article.from_name).replace("%d",old_article.date_parsed).replace("%g",old_article.ngroups).replace("%s",old_article.subj)) else: custom_values.append(value) return custom_names,custom_values def check_article(self,newsgroups,from_name,subject): """Checks if the article is wellformed. Performs checks on newsgroups,from_name and subject header fields and on the body. Returns two strings, errors, warnings """ def check_from(from_name): nick,mail=parseaddr(from_name) if not nick and not mail: return _("* From field appears to be invalid\n") elif "@" not in mail: return _("* From field appears to be invalid\n") else: return "" def check_newsgroups(newsgroups): regex="^([+\w.-]+,)*[+\w.-]+$" match=re.compile(regex).search(newsgroups) if not match: return _("* Newsgroups field appears to be invalid\n"),"" else: if len(newsgroups.split(","))>4: return "","* You are crossposting on more than 4 Newsgroups\n" else: return "","" def check_body(body): quoted=0 text=0 total=len(body) if self.is_fup: for attr_line in self.attr_line_splitted: if attr_line in body :body.remove(attr_line) for line in body: if line=="--" or line=="-- ": break elif line.startswith(">"): quoted=quoted+1 elif line.strip()!="": text=text+1 else: continue if text+quoted==0: return _("* Article seems to be empty\n"),"" elif text==0: return _("* Article doesn't contain new text\n"),"" elif quoted*100/float(quoted+text)>95: return "",_("* Article contains more than 95% of quoted text\n") else: return "","" errors="" warnings="" if not subject: errors=errors+_("* Subject field is empty\n") if not newsgroups: errors=errors+_("* Newsgroups field is empty\n") else: groups_errors,groups_warnings=check_newsgroups(newsgroups) warnings=warnings+groups_warnings errors=errors+groups_errors if not from_name: errors=errors+_("* From field is empty\n") else: errors=errors+check_from(from_name) bounds=self.buffer.get_bounds() if bounds: start,stop=bounds text=self.buffer.get_text(start,stop,True).decode("utf-8") body=text.split("\n") else: body=[] body_errors,body_warnings=check_body(body) errors=errors+body_errors warnings=warnings+body_warnings return errors,warnings def send_article(self,obj,old_article,send_later=False,isDraft=False): newsgroups=self.newsgroups_entry.child.get_text().decode("utf-8") from_name=self.from_entry.get_text().decode("utf-8") subject=self.subj_entry.get_text().decode("utf-8") if not isDraft: errors,warnings=self.check_article(newsgroups,from_name,subject) else: errors,warnings=None,None if errors: message=""+_("Errors:")+"\n\n"+errors if warnings: message=message+"\n\n"+_("Warnings:")+"\n\n"+warnings dialog=Dialog_OK(message) do_send=False elif warnings: message=""+_("Warnings:")+"\n\n"+warnings+_("\n\nDo you want to send the Article?") dialog=Dialog_YES_NO(message) do_send=dialog.resp else: do_send=True if do_send: references=self.references user_agent=self.VERSION output_charset=self.charset_combo.child.get_text() bounds=self.buffer.get_bounds() if bounds: start,stop=bounds text=self.buffer.get_text(start,stop,True).decode("utf-8") body=text.split("\n") else: body=[] custom_names,custom_values=self.get_custom_headers(old_article) article_to_send=Article_To_Send(newsgroups,from_name,subject,references,user_agent,output_charset,self.ordered_list,body,custom_names,custom_values,self.cp_id.get(self.id_name,"gen_mid"),self.cp_id.get(self.id_name,"fqdn")) article=article_to_send.get_article() article_backup=dict() # this is needed for outbox/sent storing date=formatdate(localtime=True) server_name=self.server_combo.get_active_text() id_name=self.id_name for item in ["newsgroups","from_name","subject","references","user_agent","output_charset","body","custom_names","custom_values","date","server_name","id_name"]: article_backup[item]=eval(item) def _store_article(dirName,article_backup): try: out_files=os.listdir(dirName) except: self.statusbar.push(1,_("Problems while opening : ")+dirName) else: num=len(out_files) numbers=map(int,out_files) if not numbers:numbers=[-1] number=max((max(numbers),num)) f=open(os.path.join(dirName,str(number+1)),"wb") cPickle.dump(article_backup,f,1) f.close() if self.pathToArticle and not self.isSent: try: os.remove(os.path.join(self.wdir,self.pathToArticle)) except: pass self.destroy(None) if send_later: if isDraft: outDir="draft" else: outDir="outbox" _store_article(os.path.join(self.wdir,outDir,"news"),article_backup) else: message,articlePosted=self.connectionsPool[server_name].sendArticle(article) if not articlePosted: self.statusbar.push(1,message) else: _store_article(os.path.join(self.wdir,"sent","news"),article_backup) def update_position_and_cset(self,arg1=None,arg2=None,arg4=None): #getting the position pos_mark=self.buffer.get_insert() pos=self.buffer.get_iter_at_mark(pos_mark) line_number=pos.get_line() chars=pos.get_line_offset() #getting the encoding bounds=self.buffer.get_bounds() start,stop=bounds text=self.buffer.get_text(start,stop,True).decode("utf-8") for best_enc in self.ordered_list: try: text.encode(best_enc,"strict") except: pass else: break self.charset_combo.child.set_text(best_enc) self.row_col_label.set_text(_("row:%d, col:%d") % (int(line_number),int(chars))) self.best_charset_label.set_text(best_enc) def wrap_on_change(self,obj,configs): def get_line_from_buffer(iter_start,buffer): chars_in_line=iter_start.get_chars_in_line()-1 if chars_in_line<0: chars_in_line=0 iter_end=iter_start.copy() iter_end.set_line_offset(chars_in_line) line=buffer.get_text(iter_start,iter_end,True).decode("utf-8") return line,iter_end,chars_in_line wrap=int(self.cp_id.get(self.id_name,"wrap")) pos_mark=self.buffer.get_insert() start=self.buffer.get_start_iter() #pos is cursor position pos=self.buffer.get_iter_at_mark(pos_mark) line_number=pos.get_line() #start is the beginning of the line edited start.set_line(line_number) line,end_line,line_length=get_line_from_buffer(start,self.buffer) if (line_length>wrap) and (" " in line) and (not line.startswith(">")): pos_start=start.copy() #pos_start is equal to end_line-1 pos_start.set_line_offset(wrap) char=self.buffer.get_text(pos_start,end_line,True).decode("utf-8") offset_before_wrap=self.buffer.get_iter_at_mark(self.buffer.get_insert()).get_offset() if char!=" ": success=False i=0 pos_end=pos_start.copy() while not success and i"): new_lines.append(new_line) end_line=new_line_end_iter else: break line_number=line_number+1 if new_lines: new_lines[0]=word+" "+new_lines[0] new_text=" ".join([line for line in new_lines]) new_text_wrapped="\n".join(self.wrap_line(new_text,wrap)) self.buffer.delete(pos_start,end_line) self.buffer.insert(pos_start,"\n"+new_text_wrapped.encode("utf-8")) iter_insert=self.buffer.get_iter_at_mark(self.buffer.get_insert()) iter_insert.set_offset(offset_before_wrap) self.buffer.place_cursor(iter_insert) else: self.buffer.delete(pos_start,end_line) self.buffer.insert(pos_start,"\n"+word.encode("utf-8")) else: i=i+1 else: self.buffer.delete(pos_start,end_line) self.buffer.insert(pos_start,"\n") self.update_position_and_cset() def update_custom_headers(self,): self.reply_to_entry.set_text(self.cp_id.get(self.id_name,"reply-to").encode("utf-8")) self.organization_entry.set_text(self.cp_id.get(self.id_name,"organization").encode("utf-8")) self.mail_copies_to_entry.set_text(self.cp_id.get(self.id_name,"mail-copies-to").encode("utf-8")) try: f=open(os.path.join(self.wdir,"dats",self.id_name+"_custom_headers.txt"),"r") except IOError: pass else: headers=f.read().decode("utf-8") self.custom_headers_buffer.set_text(headers.encode("utf-8")) f.close() def insert_spoiler_char(self,obj): pos_mark=self.buffer.get_insert() pos=self.buffer.get_iter_at_mark(pos_mark) self.buffer.insert(pos,chr(12)) def save_sizes(self): try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"rb") except IOError: sizes={} else: sizes=cPickle.load(f) if not self.editwin_width: sizes["editwin_width"],sizes["editwin_height"]=self.win.get_size() else: sizes["editwin_width"]=self.editwin_width sizes["editwin_height"]=self.editwin_height sizes["editwin_pos_x"],sizes["editwin_pos_y"]=self.win.get_position() try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"wb") except IOError: pass else: cPickle.dump(sizes,f,1) f.close() def clear_pane(self): start,end=self.buffer.get_bounds() self.buffer.delete(start,end) def set_sizes(self): try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"rb") except IOError: self.win.maximize() else: sizes=cPickle.load(f) f.close() editwin_width=sizes.get("editwin_width",None) editwin_height=sizes.get("editwin_height",None) if editwin_width and editwin_height: self.win.resize(int(editwin_width),int(editwin_height)) else: self.win.maximize() editwin_pos_x=sizes.get("editwin_pos_x",None) editwin_pos_y=sizes.get("editwin_pos_y",None) if editwin_pos_x and editwin_pos_y: self.win.move(int(editwin_pos_x),int(editwin_pos_y)) def load_draft(self,article): self.from_entry.set_text(article.get("from_name","").encode("utf-8")) self.subj_entry.set_text(article.get("subject","").encode("utf-8")) self.clear_pane() self.show_article([line.encode("utf-8") for line in article.get("body","")]) self.references=self.update_references(article.get("references","")) i=0 headers=[] for name in article["custom_names"]: if name=="Reply-To": entry = self.reply_to_entry elif name=="Sender": entry = self.sender_entry elif name=="Organization": entry = self.organization_entry elif name=="Followup-To": entry = self.followup_to_entry elif name=="Mail-Copies-To": entry = self.mail_copies_to_entry elif name=="Archive": entry = self.archive_entry elif name=="Supersedes": entry = self.supersedes_entry elif name=="Approved": entry = self.approved_entry else: headers.append(name+": "+article["custom_values"][i]) entry=None if entry: entry.set_text(article["custom_values"][i].encode("utf-8")) i=i+1 headers="\n".join(headers) self.custom_headers_buffer.set_text(headers.encode("utf-8")) def create_ui(self,configs,article): self.ui = gtk.UIManager() accelgroup = self.ui.get_accel_group() actiongroup= gtk.ActionGroup("EditWindowActions") self.win.add_accel_group(accelgroup) ecuts=load_shortcuts("edit") actions=[("Article",None,_("_Article")), ("send","xpn_send",_("_Send Article"),ecuts["send"],_("Send Article"),self.send_article,article), ("send_later","xpn_send_queue",_("Send Article _Later"),ecuts["send_later"],_("Send Article Later"),self.send_article,article,True), ("save_draft",gtk.STOCK_SAVE,_("Save Article as Draft"),ecuts["save_draft"],_("Save Article as Draft"),self.send_article,article,True,True), ("discard","xpn_discard",_("_Discard Article"),ecuts["discard"],_("Discard Article"),self.destroy), ("rot13","xpn_rot13",_("_ROT13 Selected Text"),ecuts["rot13"],_("ROT13 Selected Text"),self.apply_rot13), ("editor","xpn_editor",_("Launch External _Editor"),ecuts["editor"],_("Launch External Editor"),self.external_editor,configs["editor_launcher"]), ("spoiler","xpn_spoiler_char",_("_Insert Spoiler Char"),ecuts["spoiler"],_("Insert Spoiler Char"),self.insert_spoiler_char)] for action in actions: if len(action)<7: actiongroup.add_actions([action]) else: actiongroup.add_actions([action[0:6]],action[6:]) self.ui.insert_action_group(actiongroup,0) merge_id = self.ui.add_ui_from_string(ui_string) def load_id(self): nick=self.cp_id.get(self.id_name,"nick").encode("utf-8") email=self.cp_id.get(self.id_name,"email").encode("utf-8") nick=nick+" <"+email+">" self.from_entry.set_text(nick) self.update_custom_headers() def id_changed(self,obj,art,is_fup): self.id_name=self.id_combo.get_active_text() self.load_id() start,end=self.buffer.get_bounds() body=self.buffer.get_text(start,end,True).decode("utf-8").split("\n") found=False #removing old sign i=0 for line in reversed(body): i=i+1 if line=="-- ": found=True break for x in range(i): body.pop() if not found: body=self.buffer.get_text(start,end,True).decode("utf-8").split("\n") #removing old sign if is_fup: found= False i=0 #removing old attribution line old_body=body[:] for line in body: if line==self.attr_line_splitted[-1]: found=True i=i+1 break i=i+1 for x in range(i): body.pop(0) if body[0]=="": body.pop(0) if not found: body=old_body start,end=self.buffer.get_bounds() self.buffer.delete(start,end) if is_fup: self.add_attribution_line(art) #start,insert_point=self.buffer.get_bounds() #self.buffer.create_mark("insert_point_after_text",insert_point,True) self.show_article(body) self.add_sign() def __init__(self,configs,newsgroups,article,selected_text,subscribed_groups,mode="Normal",draft_article=None,pathToArticle="",outboxManager=None,isSent=False,server_name="",id_name=""): if article==None or mode=="Supersede" or mode=="Draft": is_fup=False else: is_fup=True print type(id_name),repr(id_name) self.id_name=id_name.encode("utf-8") print type(self.id_name),repr(self.id_name) self.outboxManager=outboxManager self.pathToArticle=pathToArticle self.isSent=isSent self.wdir=get_wdir() self.fallback_charset=configs["fallback_charset"] self.win=gtk.Window(gtk.WINDOW_TOPLEVEL) self.win.connect("delete_event",self.delete_event) #self.win.connect("destroy",self.destroy) self.win.set_title(_("Edit Article")) self.win.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/post.xpm")) #self.win.maximize() #main_vbox main_vbox=gtk.VBox() self.win.add(main_vbox) self.create_ui(configs,article) menubar=self.ui.get_widget("/EditMenuBar") main_vbox.pack_start(menubar,False,True,0) menubar.show() toolbar=self.ui.get_widget("/EditToolBar") main_vbox.pack_start(toolbar,False,False,0) toolbar.show() #toolbar.set_icon_size(gtk.ICON_SIZE_LARGE_TOOLBAR) toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) toolbar.set_style(gtk.TOOLBAR_ICONS) toolbar.set_style(gtk.SHADOW_NONE) id_label=gtk.Label(""+_("Identity")+"") id_label.set_alignment(0,0.5) id_label.set_use_markup(True) id_hbox=gtk.HBox() self.id_combo=gtk.combo_box_new_text() self.cp_id=ConfigParser.ConfigParser() self.cp_id.read(os.path.join(get_wdir(),"dats","id.txt")) positions=dict() i=0 for id in self.cp_id.sections(): self.id_combo.append_text(id) positions[id]=i i=i+1 if self.id_name: self.id_combo.set_active(positions[self.id_name]) else: self.id_combo.set_active(0) self.id_name=self.id_combo.get_active_text() id_sep=gtk.VSeparator() server_label=gtk.Label(""+_("Server")+"") server_label.set_alignment(0,0.5) server_label.set_use_markup(True) self.server_combo=gtk.combo_box_new_text() cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) positions=dict() i=0 for server in cp.sections(): self.server_combo.append_text(cp.get(server,"server")) positions[server]=i i=i+1 if server_name: self.server_combo.set_active(positions[server_name]) else: self.server_combo.set_active(0) #Connection self.connectionsPool=dict() for server in cp.sections(): if cp.get(server,"nntp_use_ssl")=="True": self.connectionsPool[server]=SSLConnection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) else: self.connectionsPool[server]=Connection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) id_hbox.pack_start(id_label,False,True,4) id_hbox.pack_start(self.id_combo,False,True,4) id_hbox.pack_start(id_sep,False,False,4) id_hbox.pack_start(server_label,False,True,4) id_hbox.pack_start(self.server_combo,False,True,4) main_vbox.pack_start(id_hbox,False,False,4) self.headers_notebook=gtk.Notebook() self.headers_label=gtk.Label(_("Article")) self.headers_table=gtk.Table(3,2,False) self.headers_table.set_border_width(2) self.newsgroups_label=gtk.Label(""+_("Newsgroups : ")+"") self.newsgroups_label.set_use_markup(True) self.newsgroups_label.set_alignment(1,0.5) self.from_label=gtk.Label(""+_("From : ")+"") self.from_label.set_use_markup(True) self.from_label.set_alignment(1,0.5) self.subj_label=gtk.Label(""+_("Subject : ")+"") self.subj_label.set_use_markup(True) self.subj_label.set_alignment(1,0.5) #self.newsgroups_entry=gtk.Entry() self.newsgroups_entry=gtk.combo_box_entry_new_text() self.from_entry=gtk.Entry() self.subj_entry=gtk.Entry() self.headers_table.attach(self.newsgroups_label,0,1,0,1,gtk.FILL,gtk.FILL) self.headers_table.attach(self.from_label,0,1,1,2,gtk.FILL,gtk.FILL) self.headers_table.attach(self.subj_label,0,1,2,3,gtk.FILL,gtk.FILL) self.headers_table.attach(self.newsgroups_entry,1,2,0,1) self.headers_table.attach(self.from_entry,1,2,1,2) self.headers_table.attach(self.subj_entry,1,2,2,3) #buffer self.buffer=gtk.TextBuffer() self.quote1_tag=None self.quote2_tag=None self.quote3_tag=None self.sign_tag=None self.text_tag=None color=configs["text_color"] self.set_text_color(color) color=configs["quote1_color"] self.set_quote_color(color,1) color=configs["quote2_color"] self.set_quote_color(color,2) color=configs["quote3_color"] self.set_quote_color(color,3) color=configs["sign_color"] self.set_sign_color(color) #TextView text_scrolledwin=gtk.ScrolledWindow() text_scrolledwin.set_border_width(2) text_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) text_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.textview=gtk.TextView(self.buffer) self.textview.set_wrap_mode(gtk.WRAP_WORD) self.textview.set_indent(4) text_scrolledwin.add(self.textview) self.text_vbox=gtk.VBox() self.text_vbox.pack_start(self.headers_table,False,False) self.text_vbox.pack_start(text_scrolledwin,True,True) self.headers_notebook.append_page(self.text_vbox,self.headers_label) self.custom_headers_label=gtk.Label(_("More Headers")) self.custom_headers_table=gtk.Table(8,2,False) self.custom_headers_table.set_border_width(4) self.reply_to_label=gtk.Label(""+_("Reply-To : ")+"") self.reply_to_label.set_use_markup(True) self.reply_to_label.set_alignment(1,0.5) self.sender_label=gtk.Label(""+_("Sender : ")+"") self.sender_label.set_use_markup(True) self.sender_label.set_alignment(1,0.5) self.organization_label=gtk.Label(""+_("Organization : ")+"") self.organization_label.set_use_markup(True) self.organization_label.set_alignment(1,0.5) self.followup_to_label=gtk.Label(""+_("Followup-To : ")+"") self.followup_to_label.set_use_markup(True) self.followup_to_label.set_alignment(1,0.5) self.mail_copies_to_label=gtk.Label(""+_("Mail-Copies-To : ")+"") self.mail_copies_to_label.set_use_markup(True) self.mail_copies_to_label.set_alignment(1,0.5) self.archive_label=gtk.Label(""+_("Archive : ")+"") self.archive_label.set_use_markup(True) self.archive_label.set_alignment(1,0.5) self.supersedes_label=gtk.Label(""+_("Supersedes : ")+"") self.supersedes_label.set_use_markup(True) self.supersedes_label.set_alignment(1,0.5) self.approved_label=gtk.Label(""+_("Approved : ")+"") self.approved_label.set_use_markup(True) self.approved_label.set_alignment(1,0.5) self.charset_label=gtk.Label(""+_("Charset : ")+"") self.charset_label.set_use_markup(True) self.charset_label.set_alignment(1,0.5) self.reply_to_entry=gtk.Entry() self.sender_entry=gtk.Entry() self.organization_entry=gtk.Entry() self.followup_to_entry=gtk.Entry() self.mail_copies_to_entry=gtk.Entry() self.archive_entry=gtk.Entry() self.supersedes_entry=gtk.Entry() self.supersedes_entry.set_sensitive(False) self.approved_entry=gtk.Entry() self.charset_combo=gtk.combo_box_entry_new_text() for encoding in encodings_list: self.charset_combo.append_text(encoding) self.charset_tooltip=gtk.Tooltips() self.charset_tooltip.set_tip(self.charset_combo.child,encodings_tip) self.charset_combo.child.set_editable(False) self.custom_headers_table.attach(self.reply_to_label,0,1,0,1,gtk.FILL,gtk.FILL) self.custom_headers_table.attach(self.sender_label,0,1,1,2,gtk.FILL,gtk.FILL) self.custom_headers_table.attach(self.organization_label,0,1,2,3,gtk.FILL,gtk.FILL) self.custom_headers_table.attach(self.followup_to_label,0,1,3,4,gtk.FILL,gtk.FILL) self.custom_headers_table.attach(self.mail_copies_to_label,0,1,4,5,gtk.FILL,gtk.FILL) self.custom_headers_table.attach(self.archive_label,0,1,5,6,gtk.FILL,gtk.FILL) self.custom_headers_table.attach(self.supersedes_label,0,1,6,7,gtk.FILL,gtk.FILL) self.custom_headers_table.attach(self.approved_label,0,1,7,8,gtk.FILL,gtk.FILL) self.custom_headers_table.attach(self.charset_label,0,1,8,9,gtk.FILL,gtk.FILL) self.custom_headers_table.attach(self.reply_to_entry,1,2,0,1) self.custom_headers_table.attach(self.sender_entry,1,2,1,2) self.custom_headers_table.attach(self.organization_entry,1,2,2,3) self.custom_headers_table.attach(self.followup_to_entry,1,2,3,4) self.custom_headers_table.attach(self.mail_copies_to_entry,1,2,4,5) self.custom_headers_table.attach(self.archive_entry,1,2,5,6) self.custom_headers_table.attach(self.supersedes_entry,1,2,6,7) self.custom_headers_table.attach(self.approved_entry,1,2,7,8) self.custom_headers_table.attach(self.charset_combo,1,2,8,9) self.custom_headers_frame=gtk.Frame(_("Custom Headers (X-Headers)")) self.custom_headers_frame.set_border_width(4) self.custom_headers_scrolledwin=gtk.ScrolledWindow() self.custom_headers_scrolledwin.set_border_width(4) self.custom_headers_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.custom_headers_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.custom_headers_buffer=gtk.TextBuffer() self.custom_headers_textview=gtk.TextView(self.custom_headers_buffer) self.custom_headers_scrolledwin.add(self.custom_headers_textview) self.custom_headers_frame.add(self.custom_headers_scrolledwin) self.custom_headers_vbox=gtk.VBox() self.custom_headers_vbox.pack_start(self.custom_headers_table,False,False) self.custom_headers_vbox.pack_start(self.custom_headers_frame,True,True) self.headers_notebook.append_page(self.custom_headers_vbox,self.custom_headers_label) main_vbox.pack_start(self.headers_notebook,True,True,0) #statusbar statusbar_hbox=gtk.HBox() statusbar_hbox.set_border_width(2) self.row_col_label=gtk.Label() vsep=gtk.VSeparator() vsep2=gtk.VSeparator() self.best_charset_label=gtk.Label() self.statusbar=gtk.Statusbar() statusbar_hbox.pack_start(self.row_col_label,False,True,2) statusbar_hbox.pack_start(vsep,False,False,2) statusbar_hbox.pack_start(self.best_charset_label,False,True,2) statusbar_hbox.pack_start(vsep2,False,False,2) statusbar_hbox.pack_start(self.statusbar,True,True,2) main_vbox.pack_start(statusbar_hbox,False,False,0) #check for a valid ID if self.cp_id.sections(): #some updates self.ordered_list=load_ordered_list() self.update_newsgroups_entry(newsgroups,subscribed_groups) self.references="" if is_fup: self.update_subject_entry(article.subj) self.references=self.update_references(article.ref+" "+article.msgid) self.add_attribution_line(article) self.update_body(article,selected_text) start,insert_point=self.buffer.get_bounds() self.buffer.create_mark("insert_point_after_text",insert_point,True) else: insert_point,stop=self.buffer.get_bounds() self.buffer.create_mark("insert_point",insert_point,True) self.add_sign() self.buffer.connect("changed",self.wrap_on_change,configs) self.buffer.connect("mark_set",self.update_position_and_cset) if selected_text==None: insert_pos=self.buffer.get_iter_at_mark(self.buffer.get_mark("insert_point")) else: insert_pos=self.buffer.get_iter_at_mark(self.buffer.get_mark("insert_point_after_text")) self.buffer.place_cursor(insert_pos) self.set_background(configs) self.set_foreground(configs) self.update_position_and_cset() self.is_fup=is_fup if mode=="Supersede": self.supersedes_entry.set_text(article.msgid.encode("utf-8")) self.subj_entry.set_text(article.subj.encode("utf-8")) self.references=self.update_references(article.ref) self.clear_pane() self.show_article(article.body) if mode=="Draft": self.load_draft(draft_article) if configs["external_editor"]=="True": self.external_editor(None,configs["editor_launcher"]) self.load_id() self.id_combo.connect("changed",self.id_changed,article,is_fup) self.set_sizes() self.editwin_width=None self.editwin_height=None self.textview.modify_font(pango.FontDescription(configs["font_name"])) self.show() else: self.win.destroy() Dialog_OK(_("First you have to create at least one Identity")) xpn-1.2.6/xpn_src/Article_Pane.py0000644000175000017500000005140311141275756015043 0ustar antantimport gtk, gobject import pango import webbrowser from os import remove as remove_file from urllib import quote as url_quote from xml.sax.saxutils import escape from xpn_src.XFace import XFaceToBuffer,XFaceToBMP from xpn_src.Headers_List import load_headers_list import StringIO import base64 class Article_Pane: def show(self): self.vbox.show() def hide(self): self.vbox.hide() def unparent(self): self.vbox.unparent() def get_widget(self): return self.vbox def update_expander_label(self): if not self.frame_shown: val=""+_("Subject: ")+""+escape(self.subj) val=val+" "+_("From: ")+""+escape(self.nick) val=val+" "+_("Date: ")+""+escape(self.date_parsed) if not self.subj and not self.nick and not self.date_parsed: val=""+_("Expand Headers Row")+"" self.expander.get_label_widget().set_label(val) def show_hide_headers(self,button,signal): if not self.frame_shown: self.expander_tooltip.set_tip(self.expander,_("Hide Headers")) self.expander.get_label_widget().set_label("") self.frame_shown=True else: self.expander_tooltip.set_tip(self.expander,_("Expand Headers Row")) self.frame_shown=False self.update_expander_label() def add_parts_buttons(self,buttons_list): self.multiparts_buttons=[] for name,body in buttons_list: if len(self.multiparts_buttons)>0: group=self.multiparts_buttons[0] else: group=None button=gtk.RadioButton(group) button.set_mode(False) image=gtk.Image() image.set_from_file("pixmaps/part.xpm") label=gtk.Label(name) hbox=gtk.HBox() hbox.pack_start(image,False,True,2) hbox.pack_start(label,True,True,2) hbox.show_all() button.add(hbox) self.multiparts_hbox.pack_start(button,True,True,2) button.show() self.multiparts_buttons.append(button) self.multiparts_hbox.show() def clear_multiparts_area(self): try: self.multiparts_buttons except: self.multiparts_buttons=[] for button in self.multiparts_buttons: self.multiparts_hbox.remove(button) self.multiparts_buttons=[] self.multiparts_hbox.hide() def clear(self): self.update_headers_labels(None) self.delete_all() self.clear_multiparts_area() self.hide_faces() def update_headers_labels(self,article): if article: self.nick=article.nick self.subj=article.subj self.date_parsed=article.date_parsed else: self.nick="" self.subj="" self.date_parsed="" for header,(label_name,label_value) in self.values.iteritems(): if article: value=article.get_hdr(header) else: value="" if value: label_name.show() label_value.show() label_value.set_text(value.encode("utf-8")) else: label_name.hide() label_value.hide() label_value.set_text("") self.update_expander_label() def delete_all(self): start,end=self.buffer.get_bounds() self.buffer.delete(start,end) def insert(self,string): mark=self.buffer.get_insert() iter=self.buffer.get_iter_at_mark(mark) self.buffer.insert(iter,string.encode("utf-8")) def insert_with_tags(self,string,tag): self.buffer.insert_with_tags_by_name(self.buffer.get_end_iter(),string.encode("utf-8"),tag) def insert_with_tags_at_iter(self,iter,string,tag): self.buffer.insert_with_tags_by_name(iter,string.encode("utf-8"),tag) def set_url_color(self,color): url_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.tag_url: self.tag_url=gtk.TextTag("url") self.tag_table.add(self.tag_url) self.tag_url.set_property("underline",pango.UNDERLINE_SINGLE) self.tag_mid=gtk.TextTag("mid") self.tag_table.add(self.tag_mid) self.tag_mid.set_property("underline",pango.UNDERLINE_SINGLE) self.tag_url.set_property("foreground-gdk",url_color) self.tag_mid.set_property("foreground-gdk",url_color) def set_spoiler_color(self): spoiler_color=gtk.gdk.color_parse("#FF0000") self.tag_table=self.buffer.get_tag_table() if not self.tag_spoiler: self.tag_spoiler=gtk.TextTag("spoiler") self.tag_table.add(self.tag_spoiler) self.tag_spoiler.set_property("foreground-gdk",spoiler_color) self.tag_spoiler.set_property("background-gdk",spoiler_color) def set_text_color(self,color): text_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.text_tag: self.text_tag=gtk.TextTag("text") self.tag_table.add(self.text_tag) self.text_tag.set_property("foreground-gdk",text_color) if not self.text_tag_bold: self.text_tag_bold=gtk.TextTag("text_bold") self.tag_table.add(self.text_tag_bold) self.text_tag_bold.set_property("weight",800) self.text_tag_bold.set_property("foreground-gdk",text_color) if not self.text_tag_italic: self.text_tag_italic=gtk.TextTag("text_italic") self.tag_table.add(self.text_tag_italic) self.text_tag_italic.set_property("style",pango.STYLE_ITALIC) self.text_tag_italic.set_property("foreground-gdk",text_color) if not self.text_tag_underline: self.text_tag_underline=gtk.TextTag("text_underline") self.tag_table.add(self.text_tag_underline) self.text_tag_underline.set_property("underline",pango.UNDERLINE_SINGLE) self.text_tag_underline.set_property("foreground-gdk",text_color) def set_quote_color(self,color,level): if level==1: quote1_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.quote1_tag: self.quote1_tag=gtk.TextTag("quote1") self.tag_table.add(self.quote1_tag) self.quote1_tag.set_property("foreground-gdk",quote1_color) if not self.quote1_tag_bold: self.quote1_tag_bold=gtk.TextTag("quote1_bold") self.tag_table.add(self.quote1_tag_bold) self.quote1_tag_bold.set_property("weight",1000) self.quote1_tag_bold.set_property("foreground-gdk",quote1_color) if not self.quote1_tag_italic: self.quote1_tag_italic=gtk.TextTag("quote1_italic") self.tag_table.add(self.quote1_tag_italic) self.quote1_tag_italic.set_property("style",pango.STYLE_ITALIC) self.quote1_tag_italic.set_property("foreground-gdk",quote1_color) if not self.quote1_tag_underline: self.quote1_tag_underline=gtk.TextTag("quote1_underline") self.tag_table.add(self.quote1_tag_underline) self.quote1_tag_underline.set_property("underline",pango.UNDERLINE_SINGLE) self.quote1_tag_underline.set_property("foreground-gdk",quote1_color) elif level==2: quote2_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.quote2_tag: self.quote2_tag=gtk.TextTag("quote2") self.tag_table.add(self.quote2_tag) self.quote2_tag.set_property("foreground-gdk",quote2_color) if not self.quote2_tag_bold: self.quote2_tag_bold=gtk.TextTag("quote2_bold") self.tag_table.add(self.quote2_tag_bold) self.quote2_tag_bold.set_property("weight",1000) self.quote2_tag_bold.set_property("foreground-gdk",quote2_color) if not self.quote2_tag_italic: self.quote2_tag_italic=gtk.TextTag("quote2_italic") self.tag_table.add(self.quote2_tag_italic) self.quote2_tag_italic.set_property("style",pango.STYLE_ITALIC) self.quote2_tag_italic.set_property("foreground-gdk",quote2_color) if not self.quote2_tag_underline: self.quote2_tag_underline=gtk.TextTag("quote2_underline") self.tag_table.add(self.quote2_tag_underline) self.quote2_tag_underline.set_property("underline",pango.UNDERLINE_SINGLE) self.quote2_tag_underline.set_property("foreground-gdk",quote2_color) else: quote3_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.quote3_tag: self.quote3_tag=gtk.TextTag("quote3") self.tag_table.add(self.quote3_tag) self.quote3_tag.set_property("foreground-gdk",quote3_color) if not self.quote3_tag_bold: self.quote3_tag_bold=gtk.TextTag("quote3_bold") self.tag_table.add(self.quote3_tag_bold) self.quote3_tag_bold.set_property("weight",1000) self.quote3_tag_bold.set_property("foreground-gdk",quote3_color) if not self.quote3_tag_italic: self.quote3_tag_italic=gtk.TextTag("quote3_italic") self.tag_table.add(self.quote3_tag_italic) self.quote3_tag_italic.set_property("style",pango.STYLE_ITALIC) self.quote3_tag_italic.set_property("foreground-gdk",quote3_color) if not self.quote3_tag_underline: self.quote3_tag_underline=gtk.TextTag("quote3_underline") self.tag_table.add(self.quote3_tag_underline) self.quote3_tag_underline.set_property("underline",pango.UNDERLINE_SINGLE) self.quote3_tag_underline.set_property("foreground-gdk",quote3_color) def set_sign_color(self,color): sign_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.sign_tag: self.sign_tag=gtk.TextTag("sign") self.tag_table.add(self.sign_tag) self.sign_tag.set_property("foreground-gdk",sign_color) if not self.sign_tag_bold: self.sign_tag_bold=gtk.TextTag("sign_bold") self.tag_table.add(self.sign_tag_bold) self.sign_tag_bold.set_property("weight",800) self.sign_tag_bold.set_property("foreground-gdk",sign_color) if not self.sign_tag_italic: self.sign_tag_italic=gtk.TextTag("sign_italic") self.tag_table.add(self.sign_tag_italic) self.sign_tag_italic.set_property("style",pango.STYLE_ITALIC) self.sign_tag_italic.set_property("foreground-gdk",sign_color) if not self.sign_tag_underline: self.sign_tag_underline=gtk.TextTag("sign_underline") self.tag_table.add(self.sign_tag_underline) self.sign_tag_underline.set_property("underline",pango.UNDERLINE_SINGLE) self.sign_tag_underline.set_property("foreground-gdk",sign_color) def set_background(self,color): color=gtk.gdk.color_parse(color) self.textview.modify_base(gtk.STATE_NORMAL,color) self.textview.modify_text(gtk.STATE_NORMAL,gtk.gdk.color_parse("#FFFFFF")) def get_url_at_coords(self,old_x,old_y): x,y=self.textview.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT,int(old_x),int(old_y)) iter=self.textview.get_iter_at_location(x,y) is_url=iter.has_tag(self.tag_url) is_mid=iter.has_tag(self.tag_mid) url="" if is_url: #let's get the url start=iter.copy() stop=iter.copy() start.backward_to_tag_toggle(self.tag_url) stop.forward_to_tag_toggle(self.tag_url) url=self.buffer.get_text(start,stop,True) if is_mid: #let's get the url start=iter.copy() stop=iter.copy() start.backward_to_tag_toggle(self.tag_mid) stop.forward_to_tag_toggle(self.tag_mid) url=self.buffer.get_text(start,stop,True) return url,is_url def mouse_move(self,obj,event): cursor_std=gtk.gdk.Cursor(gtk.gdk.XTERM) cursor_url=gtk.gdk.Cursor(gtk.gdk.HAND2) if event.is_hint: x,y,state=event.window.get_pointer() else: x,y=event.get_coords() url,is_url=self.get_url_at_coords(x,y) if url!="": event.window.set_cursor(cursor_url) else: event.window.set_cursor(cursor_std) def button_press(self,obj,event): if (event.button==1): url,is_url=self.get_url_at_coords(event.x,event.y) if url!="": if is_url: if self.use_custom_browser: launcher=webbrowser.get("xpn_launcher") launcher.open(url) else: webbrowser.open(url) else: if url.startswith("news:"): url=url.replace("news:","") self.vbox.emit("mid_clicked",url) def set_face_x_face(self,face,x_face): if face: self.set_face(face) elif x_face: self.set_x_face(x_face) else: self.hide_faces() def set_x_face(self,x_face): buff=XFaceToBMP(x_face) f1=StringIO.StringIO(buff) f1.seek(0) x_face_decoded=f1.read() f1.close() pixbuf_loader=gtk.gdk.PixbufLoader() pixbuf_loader.set_size(48,48) pixbuf_loader.write(x_face_decoded) pixbuf_loader.close() pixbuf=pixbuf_loader.get_pixbuf() self.x_face_image.set_from_pixbuf(pixbuf) self.face_image.hide() self.x_face_image.show() self.face_frame.show() def set_face(self,face): f1=StringIO.StringIO(face) f2=StringIO.StringIO() try: base64.decode(f1,f2) except: f1.close() f2.close() else: f1.close() f2.seek(0) face_decoded=f2.read() f2.close() pixbuf_loader=gtk.gdk.PixbufLoader() pixbuf_loader.set_size(48,48) pixbuf_loader.write(face_decoded) pixbuf_loader.close() pixbuf=pixbuf_loader.get_pixbuf() self.face_image.set_from_pixbuf(pixbuf) self.face_image.show() self.x_face_image.hide() self.face_frame.show() def hide_faces(self): self.face_frame.hide() self.x_face_image.hide() self.face_image.hide() def set_headers_colors(self,bg,fg): bgcolor=gtk.gdk.color_parse(bg) fgcolor=gtk.gdk.color_parse(fg) self.evbox.modify_bg( gtk.STATE_NORMAL, bgcolor ) #self.evbox.modify_fg( gtk.STATE_NORMAL, fgcolor ) label=self.expander.get_label_widget() label.modify_fg( gtk.STATE_NORMAL, fgcolor ) for child in self.headers_table.get_children(): child.modify_fg( gtk.STATE_NORMAL, fgcolor ) def repopulate_headers(self): self.values=dict() hlist=load_headers_list() for child in self.headers_table.get_children(): self.headers_table.remove(child) i=0 for header in hlist: label=gtk.Label(""+header+":"+"") label.set_use_markup(True) label.set_alignment(1,0.5) value=gtk.Label("") value.set_alignment(0,0.5) value.set_padding(5,1) self.values[header]=(label,value) self.headers_table.attach(label,0,1,i,i+1,gtk.FILL,gtk.FILL) self.headers_table.attach(value,1,2,i,i+1) i=i+1 label.show() value.show() def __init__(self,show_headers,configs): #VBox self.vbox=gtk.VBox() gobject.signal_new("mid_clicked",gtk.VBox,gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)) self.expander=gtk.Expander() self.evbox=gtk.EventBox() self.evbox.add(self.expander) self.evbox.show_all() self.vbox.pack_start(self.evbox,False,True,0) self.expander_tooltip=gtk.Tooltips() if show_headers==True: self.expander.set_expanded(True) self.expander_tooltip.set_tip(self.expander,_("Hide Headers")) exp_label=gtk.Label("") self.frame_shown=True else: self.expander.set_expanded(False) self.expander_tooltip.set_tip(self.expander,_("Expand Headers Row")) exp_label=gtk.Label(""+_("Expand Headers Row")+"") self.frame_shown=False exp_label.set_use_markup(True) exp_label.show() self.expander.set_label_widget(exp_label) self.expander.connect("notify::expanded",self.show_hide_headers) self.multiparts_hbox=gtk.HBox() self.vbox.pack_start(self.multiparts_hbox,False,True,2) self.multiparts_hbox.hide() self.headers_table=gtk.Table(6,2,False) self.headers_table.set_border_width(2) headers_hbox=gtk.HBox() headers_hbox.pack_start(self.headers_table,True,True,4) headers_hbox.set_border_width(2) self.x_face_image=gtk.Image() self.x_face_image.set_size_request(48,48) self.face_image=gtk.Image() self.face_image.set_size_request(48,48) faces_hbox=gtk.HBox() fake_label=gtk.Label() faces_vbox=gtk.VBox() self.face_frame=gtk.Frame() #self.face_frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT) faces_hbox.set_size_request(48,48) faces_hbox.pack_start(self.face_image,False,False) faces_hbox.pack_start(self.x_face_image,False,False) faces_vbox.pack_start(self.face_frame,False,False) faces_vbox.pack_start(fake_label,True,True) self.face_frame.add(faces_hbox) headers_hbox.pack_start(faces_vbox,False,False) self.expander.add(headers_hbox) headers_hbox.show_all() self.x_face_image.hide() self.face_image.hide() self.face_frame.hide() self.repopulate_headers() #TextScrolledWindow self.text_scrolledwin=gtk.ScrolledWindow() self.text_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.text_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.vbox.pack_start(self.text_scrolledwin,True,True,0) self.text_scrolledwin.show() #TextBuffer self.buffer=gtk.TextBuffer() #TextView self.textview=gtk.TextView(self.buffer) self.text_scrolledwin.add(self.textview) self.textview.set_wrap_mode(gtk.WRAP_WORD) self.textview.set_editable(False) self.textview.set_cursor_visible(False) self.textview.show() self.textview.add_events(gtk.gdk.POINTER_MOTION_MASK|gtk.gdk.POINTER_MOTION_HINT_MASK) self.textview.connect("motion-notify-event",self.mouse_move) self.textview.connect("button-release-event",self.button_press) self.quote1_tag=None self.quote1_tag_bold=None self.quote1_tag_italic=None self.quote1_tag_underline=None self.quote2_tag=None self.quote2_tag_bold=None self.quote2_tag_italic=None self.quote2_tag_underline=None self.quote3_tag=None self.quote3_tag_bold=None self.quote3_tag_italic=None self.quote3_tag_underline=None self.sign_tag=None self.sign_tag_bold=None self.sign_tag_italic=None self.sign_tag_underline=None self.text_tag=None self.text_tag_bold=None self.text_tag_italic=None self.text_tag_underline=None self.tag_url=None self.tag_mid=None self.tag_spoiler=None color=configs["text_color"] self.set_text_color(color) color=configs["quote1_color"] self.set_quote_color(color,1) color=configs["quote2_color"] self.set_quote_color(color,2) color=configs["quote3_color"] self.set_quote_color(color,3) color=configs["sign_color"] self.set_sign_color(color) color=configs["background_color"] self.set_background(color) color=configs["url_color"] self.set_url_color(color) self.set_spoiler_color() self.set_headers_colors(configs["headers_bg_color"],configs["headers_fg_color"]) if configs["custom_browser"]=="True": self.use_custom_browser=True webbrowser.register("xpn_launcher",None,webbrowser.GenericBrowser(configs["browser_launcher"])) else: self.use_custom_browser=False xpn-1.2.6/xpn_src/Charset_List.py0000644000175000017500000003302611141275756015102 0ustar antantimport gtk import gobject import cPickle import os from locale import getdefaultlocale from xpn_src.UserDir import get_wdir try: system_enc=getdefaultlocale()[1] except: system_enc="US-ASCII" guess_list=[system_enc,"US-ASCII","ISO-8859-1","ISO-8859-2","ISO-8859-3","ISO-8859-4","ISO-8859-5", "ISO-8859-6","ISO-8859-7","ISO-8859-8","ISO-8859-9","ISO-8859-10","ISO-8859-13", "ISO-8859-14","ISO-8859-15","ISO-2022-JP","ISO-2022-KR","KOI8-R","KOI8-U","GB2312","BIG5", "WINDOWS-1250","WINDOWS-1251","WINDOWS-1252","WINDOWS-1253","WINDOWS-1254", "WINDOWS-1255","WINDOWS-1256","WINDOWS-1257","WINDOWS-1258","MACCYRILLIC","MACICELAND", "MACLATIN2","MACROMAN","MACTURKISH","UTF-8"] encodings_list=["US-ASCII","ISO-8859-1","ISO-8859-2","ISO-8859-3","ISO-8859-4","ISO-8859-5", "ISO-8859-6","ISO-8859-7","ISO-8859-8","ISO-8859-9","ISO-8859-10","ISO-8859-13", "ISO-8859-14","ISO-8859-15","ISO-2022-JP","ISO-2022-KR","KOI8-R","KOI8-U","GB2312","BIG5", "UTF-7","UTF-8","WINDOWS-1250","WINDOWS-1251","WINDOWS-1252","WINDOWS-1253","WINDOWS-1254", "WINDOWS-1255","WINDOWS-1256","WINDOWS-1257","WINDOWS-1258","MACCYRILLIC","MACICELAND", "MACLATIN2","MACROMAN","MACTURKISH"] encodings_tip="US-ASCII (English) \ \nISO-8859-1 (West Europe, latin1) \ \nISO-8859-2 (Central and Eastern Europe, latin2) \ \nISO-8859-3 (Esperanto, Maltese, latin3) \ \nISO-8859-4 (Baltic languages, latin4) \ \nISO-8859-5 (Cyrillic) \ \nISO-8859-6 (Arabic) \ \nISO-8859-7 (Greek) \ \nISO-8859-8 (Hebrew) \ \nISO-8859-9 (Turkish, latin5) \ \nISO-8859-10 (Nordish languages, latin6) \ \nISO-8859-13 (Baltic languages) \ \nISO-8859-14 (Celtic languages, latin8) \ \nISO-8859-15 (Western Europe) \ \nISO-2022-JP (Japanese) \ \nISO-2022-KR (Korean) \ \nKOI8-R (Russian) \ \nKOI8-U (Ukrainian) \ \nGB-2312 (Simplified Chinese) \ \nBIG5 (Traditional Chinese) \ \nUTF-7 (All languages) \ \nUTF-8 (All languages) \ \nWINDOWS-1250 (Central and Eastern Europe, cp1250) \ \nWINDOWS-1251 (Cyrillic, cp1251) \ \nWINDOWS-1252 (Western Europe, cp1252) \ \nWINDOWS-1253 (Greek, cp1253) \ \nWINDOWS-1254 (Turkish, cp1254) \ \nWINDOWS-1255 (Hebrew, cp1255) \ \nWINDOWS-1256 (Arabic, cp1256) \ \nWINDOWS-1257 (Baltic Languages, cp1257) \ \nWINDOWS-1258 (Vietnamese, cp1258) \ \nMACCYRILLIC (Cyrillic) \ \nMACICELAND (Icelandic) \ \nMACLATIN2 (Central and Eastern Europe) \ \nMACROMAN (Western Europe) \ \nMACTURKISH (Turkish)" ordered_list=["US-ASCII","ISO-8859-1","ISO-8859-2","ISO-8859-3","ISO-8859-4","ISO-8859-5", "ISO-8859-6","ISO-8859-7","ISO-8859-8","ISO-8859-9","ISO-8859-10","ISO-8859-13", "ISO-8859-14","ISO-8859-15","UTF-8"] def load_ordered_list(): try: f=open(os.path.join(get_wdir(),"dats/charset_list.dat"),"rb") except IOError: list=ordered_list else: list=cPickle.load(f) f.close() if not list: list=ordered_list return list class CharsetList: def delete_event(self,widget,event,data=None): return False def destroy(self,widget): self.window.destroy() if __name__=="__main__": gtk.main_quit() def close_ok(self,obj): self.dump_tree(self.right_list) self.destroy(None) def close_cancel(self,obj): self.destroy(None) def fill_lists(self): for encoding in encodings_list: self.left_model.append([encoding]) list=load_ordered_list() for encoding in list: self.right_model.append([encoding]) def get_charset_list(self,treeview): model=treeview.get_model() iter=model.get_iter_first() list=[] while iter: list.append(model.get_value(iter,0)) iter=model.iter_next(iter) return list def dump_tree(self,treeview): list=self.get_charset_list(self.right_list) f=open(os.path.join(get_wdir(),"dats/charset_list.dat"),"wb") cPickle.dump(list,f,1) f.close() #CODICE PER IL DRAG E DROP #def data_get(self,treeview,context,selection,info,timestamp): # model,iter=treeview.get_selection().get_selected() # text=model.get_value(iter,0) # if treeview==self.left_list: # selection.set("Charset",8,text) # else: # selection.set("Ord",8,text) #def data_received_right(self,treeview,context,x,y,selection,info,timestamp): # model=treeview.get_model() # data=selection.data # drop_info=treeview.get_dest_row_at_pos(x,y) # if drop_info: # path,position=drop_info # iter=model.get_iter(path) # if not (data in self.get_charset_list(treeview)) or selection.target=="Ord": # if (position==gtk.TREE_VIEW_DROP_BEFORE or position== gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): # model.insert_before(iter,[data]) # else: # model.insert_after(iter,[data]) # else: # if not (data in self.get_charset_list(treeview)) or selection.target=="Ord": # model.append([data]) # if context.action ==gtk.gdk.ACTION_MOVE: # context.finish(True,True,timestamp) #def data_received_left(self,treeview,context,x,y,selection,info,timestamp): # if context.action ==gtk.gdk.ACTION_MOVE: # context.finish(True,True,timestamp) def set_default_list(self,obj): self.right_model.clear() for encoding in ordered_list: self.right_model.append([encoding]) def add_ordered(self,obj): model_left,path_left_list=self.left_list.get_selection().get_selected_rows() for path in path_left_list: iter_left=model_left.get_iter(path) encoding=model_left.get_value(iter_left,0) if not (encoding in self.get_charset_list(self.right_list)): self.right_model.append([encoding]) def remove_ordered(self,obj): model_right,path_right_list=self.right_list.get_selection().get_selected_rows() for i in range(len(path_right_list)): path=path_right_list[i] if i!=0: path=list(path) path[0]=path[0]-i path=tuple(path) iter_right=model_right.get_iter(path) self.right_model.remove(iter_right) def move_up(self,obj): model,path_list=self.right_list.get_selection().get_selected_rows() for path in path_list: iter_to_move=model.get_iter(path) new_path=list(path) if new_path[0]>0: new_path[0]=new_path[0]-1 new_path=tuple(new_path) iter_previous=model.get_iter(new_path) model.swap(iter_to_move,iter_previous) def move_down(self,obj): model,path_list=self.right_list.get_selection().get_selected_rows() path_list.reverse() for path in path_list: iter_to_move=model.get_iter(path) iter_next=model.iter_next(iter_to_move) if iter_next!=None: model.swap(iter_to_move,iter_next) def __init__(self): self.window=gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event",self.delete_event) self.window.connect("destroy",self.destroy) self.window.set_title("Charset List") self.window.set_position(gtk.WIN_POS_CENTER) self.window.set_size_request(400,400) self.table=gtk.Table(3,2,False) self.table.set_border_width(4) label_left=gtk.Label(""+_("Available Charsets")+"") label_left.set_use_markup(True) label_right=gtk.Label(""+_("Ordered Charsets")+"") label_right.set_use_markup(True) self.left_scrolledwin=gtk.ScrolledWindow() self.left_scrolledwin.set_border_width(4) self.left_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.left_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.left_list=gtk.TreeView() self.left_list.set_border_width(4) self.left_model=gtk.ListStore(gobject.TYPE_STRING) self.left_scrolledwin.add(self.left_list) self.left_list.set_model(self.left_model) text_renderer=gtk.CellRendererText() self.left_column=gtk.TreeViewColumn(_("List"),text_renderer,text=0) self.left_list.append_column(self.left_column) self.left_list.set_rules_hint(True) self.left_list.set_headers_visible(False) #self.left_list.enable_model_drag_source(False,[("Charset",gtk.TARGET_SAME_APP,0)],gtk.gdk.ACTION_COPY) #self.left_list.enable_model_drag_dest([("Delete",gtk.TARGET_SAME_APP,2)],gtk.gdk.ACTION_MOVE) #self.left_list.connect("drag-data-get",self.data_get) #self.left_list.connect("drag-data-received",self.data_received_left) self.left_list_tooltip=gtk.Tooltips() self.left_list_tooltip.set_tip(self.left_list,encodings_tip) self.left_list.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.right_scrolledwin=gtk.ScrolledWindow() self.right_scrolledwin.set_border_width(4) self.right_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.right_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.right_list=gtk.TreeView() self.right_list.set_border_width(4) self.right_model=gtk.ListStore(gobject.TYPE_STRING) self.right_scrolledwin.add(self.right_list) self.right_list.set_model(self.right_model) text_renderer=gtk.CellRendererText() self.right_column=gtk.TreeViewColumn(_("List"),text_renderer,text=0) self.right_list.append_column(self.right_column) self.right_list.set_rules_hint(True) self.right_list.set_headers_visible(False) #self.right_list.enable_model_drag_dest([("Charset",gtk.TARGET_SAME_APP,0),("Ord",gtk.TARGET_SAME_WIDGET,1)],gtk.gdk.ACTION_COPY|gtk.gdk.ACTION_MOVE) #self.right_list.enable_model_drag_source(False,[("Ord",gtk.TARGET_SAME_WIDGET,1),("Delete",gtk.TARGET_SAME_APP,2)],gtk.gdk.ACTION_MOVE) #self.right_list.connect("drag-data-received",self.data_received_right) #self.right_list.connect("drag-data-get",self.data_get) self.right_list_tooltip=gtk.Tooltips() self.right_list_tooltip.set_tip(self.right_list,_("XPN will try to encode your articles with these charsets in this order")) self.right_list.set_reorderable(True) self.right_list.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.to_right_button=gtk.Button() to_right_button_image=gtk.Image() to_right_button_image.set_from_stock(gtk.STOCK_GO_FORWARD,gtk.ICON_SIZE_MENU) self.to_right_button.add(to_right_button_image) self.to_right_button.connect("clicked",self.add_ordered) self.to_left_button=gtk.Button() to_left_button_image=gtk.Image() to_left_button_image.set_from_stock(gtk.STOCK_GO_BACK,gtk.ICON_SIZE_MENU) self.to_left_button.add(to_left_button_image) self.to_left_button.connect("clicked",self.remove_ordered) vbox_buttons=gtk.VBox() vbox_buttons.pack_start(self.to_right_button,False,True,10) vbox_buttons.pack_start(self.to_left_button,False,True,10) up_button_image=gtk.Image() up_button_image.set_from_stock(gtk.STOCK_GO_UP,gtk.ICON_SIZE_MENU) self.up_button=gtk.Button() self.up_button.add(up_button_image) self.up_button.connect("clicked",self.move_up) down_button_image=gtk.Image() down_button_image.set_from_stock(gtk.STOCK_GO_DOWN,gtk.ICON_SIZE_MENU) self.down_button=gtk.Button() self.down_button.add(down_button_image) self.down_button.connect("clicked",self.move_down) vbox_buttons2=gtk.VBox() vbox_buttons2.pack_start(self.up_button,False,False,10) vbox_buttons2.pack_start(self.down_button,False,False,10) self.default_button=gtk.Button(_("Set Default List")) self.default_button.connect("clicked",self.set_default_list) self.table.attach(label_left,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL) self.table.attach(vbox_buttons,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.EXPAND) self.table.attach(label_right,2,3,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL) self.table.attach(self.left_scrolledwin,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL) self.table.attach(self.right_scrolledwin,2,3,1,2,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL) self.table.attach(vbox_buttons2,3,4,1,2,gtk.FILL,gtk.EXPAND) self.table.attach(self.default_button,2,3,2,3,gtk.FILL|gtk.EXPAND,gtk.FILL) vbox=gtk.VBox() hbox=gtk.HBox() self.ok_button=gtk.Button(None,gtk.STOCK_OK) self.ok_button.connect("clicked",self.close_ok) self.cancel_button=gtk.Button(None,gtk.STOCK_CANCEL) self.cancel_button.connect("clicked",self.close_cancel) hbox.pack_start(self.cancel_button,True,True,2) hbox.pack_start(self.ok_button,True,True,2) vbox.pack_start(self.table,True,True,4) vbox.pack_start(hbox,False,True,2) self.window.add(vbox) self.fill_lists() self.window.show_all() if __name__=="__main__": ch_list=CharsetList() gtk.main() xpn-1.2.6/xpn_src/Config_File.py0000644000175000017500000000776311141275756014673 0ustar antantimport gtk import os from xpn_src.UserDir import get_wdir class Config_File: def get_configs(self): return self.configs def write_configs(self): f=open(os.path.join(get_wdir(),"config.txt"),"w") for key in self.configs.keys(): f.write(key+"="+self.configs[key].encode("utf-8")+"\n") f.close() def __init__(self): self.configs={} self.configs["server"]="" self.configs["port"]="119" self.configs["auth"]="False" self.configs["username"]="" self.configs["password"]="" self.configs["nntp_use_ssl"]="False" self.configs["smtp_server"]="" self.configs["smtp_port"]="25" self.configs["smtp_auth"]="False" self.configs["smtp_username"]="" self.configs["smtp_password"]="" self.configs["use_mail_from"]="False" self.configs["quote1_color"]="#0000FF" self.configs["quote2_color"]="#00AAFF" self.configs["quote3_color"]="#AAAAFF" self.configs["sign_color"]="#FF0000" self.configs["text_color"]="#000000" self.configs["background_color"]="#FFFFFF" self.configs["url_color"]="#1D921C" self.configs["headers_bg_color"]="#F7EDB5" self.configs["headers_fg_color"]="#000000" self.configs["font_name"]="Sans 9" self.configs["font_threads_name"]="Sans 9" self.configs["font_groups_name"]="Sans 9" self.configs["use_system_fonts"]="True" self.configs["fixed"]="False" self.configs["layout"]="1" self.configs["show_headers"]="True" self.configs["oneclick"]="False" self.configs["oneclick_article"]="False" self.configs["expand_group"]="False" self.configs["charset"]="ISO-8859-1" self.configs["fallback_charset"]="ISO-8859-1" self.configs["custom_browser"]="False" self.configs["browser_launcher"]="" self.configs["purge_read"]="5" self.configs["purge_unread"]="10" self.configs["limit_articles"]="False" self.configs["limit_articles_number"]="500" self.configs["download_timeout"]="30" self.configs["automatic_download"]="False" self.configs["threading_method"]="2" self.configs["external_editor"]="False" self.configs["editor_launcher"]="" self.configs["show_read_articles"]="True" self.configs["show_unread_articles"]="True" self.configs["show_threads_without_watched"]="True" self.configs["show_all_read_threads"]="True" self.configs["show_unkept_articles"]="True" self.configs["show_kept_articles"]="True" self.configs["show_watched_articles"]="True" self.configs["show_ignored_articles"]="True" self.configs["show_unwatchedignored_articles"]="True" self.configs["show_score_neg_articles"]="True" self.configs["show_score_zero_articles"]="True" self.configs["show_score_pos_articles"]="True" self.configs["raw"]="False" self.configs["show_quote"]="True" self.configs["show_sign"]="True" self.configs["show_spoiler"]="False" self.configs["download_bodies"]="False" self.configs["scroll_fraction"]="50" self.configs["lang"]="en" self.configs["ascend_order"]="True" self.configs["sort_col"]="Date" self.configs["show_threads"]="True" self.configs["advance_on_mark"]="False" self.configs["exp_column"]="Subject" try: f=open(os.path.join(get_wdir(),"config.txt"),"r") except IOError: self.found_config_file=False else: #parsing config file to a dict self.found_config_file=True lista=f.readlines() for i in range(len(lista)): ind=lista[i].find("=") if ind>0: left=lista[i][0:ind].strip() right=lista[i].strip("\r\n")[ind+1:].strip(" ") self.configs[left]=right.decode("utf-8") xpn-1.2.6/xpn_src/Score.py0000700000175000017500000013374211141275756013570 0ustar antantimport time import re import gtk import gobject import pango import cPickle import os from email.Utils import parsedate_tz, mktime_tz from xpn_src.Article import Article from xpn_src.Dialogs import Dialog_OK from xpn_src.UserDir import get_wdir try: set() except: from sets import Set as set def escape(data): """Escape &, <, and > in a string of data. """ # must do ampersand first data = data.replace("&", "&") data = data.replace(">", ">") data = data.replace("<", "<") return data class Score_Rules: def valid_re(self,regex): try : re.compile(regex) except: return False else: return True def match_is_valid(self,match,header): interval_re=re.compile(r"\[\d+,\d+\]") header_is_string=lambda header: header.lower() in ("from","subject","date","message-id","references","xref") header_is_number=lambda header: header.lower() in ("age","lines","bytes","xpost","score") #match is a string case insensitive match_is_string_c_ins=lambda match: (match[0]=="\"" and match[-1]=="\"") or \ (match[0]=="{" and match[-1]=="}" and self.valid_re(match[1:])) #match is a string case sensitive: match_is_string_c_sens=lambda match: match[0].lower()=="c" and ((match[1]=="\"" and match[-1]=="\"") or \ (match[1]=="{" and match[-1]=="}" and self.valid_re(match[2:]))) #match is a inverted string case insensitive: match_is_string_c_ins_neg=lambda match: match[0]=="~" and match_is_string_c_ins(match[1:]) #match is a inverted string case sensitive: match_is_string_c_sens_neg=lambda match: match[0]=="~" and match_is_string_c_sens(match[1:]) #match is a string: match_is_string = lambda match: match_is_string_c_ins_neg(match) or match_is_string_c_sens_neg(match) or\ match_is_string_c_ins(match) or match_is_string_c_sens(match) match_is_numb=lambda match: (match[0]=="%" and ( ((match[1]==">" or match[1]=="<" or match[1]=="=") and \ (match[2:].isdigit() or (match[2]=="-" and match[3:].isdigit()))) or \ (match[1]=="[" and interval_re.search(match[1:])) )) match_is_numb_neg= lambda match: match[0]=="~" and match_is_numb(match[1:]) #match is a number: match_is_number = lambda match: match_is_numb(match) or match_is_numb_neg(match) if len(match)>2: if (header_is_string(header) and (match_is_string(match))) or \ (header_is_number(header) and (match_is_number(match))): return True else: return False else: return False def score_mod_is_valid(self,score_mod): if score_mod[0]=="=": if (score_mod[1]=="+" or score_mod[1]=="-"): return score_mod[2:].isdigit() else: return False if score_mod[0]=="+" or score_mod[0]=="-": return score_mod[1:].isdigit() else: if score_mod[1:].startswith("setcolor"): regex=re.compile("(^setcolor)\((([a-z]+)|(#\w+));(([a-z]+)|(#\w+))\)") match=regex.match(score_mod[1:]) if match: if (match.groups()[0] and match.groups()[1] and match.groups()[4]): return True else: return False else: return False else: return score_mod[1:] in self.actions def header_is_valid(self,header,score_mod): if score_mod[0]=="!": return header in self.action_headers else: return header in self.headers def scan_for_rule(self,line): scope_number=len(self.group_scope_list)-1 ind1=line.find(" ") score_mod="" header="" match="" if ind1!=-1: score_mod=line[:ind1].strip().lower() line2=line[ind1+1:] ind2=line2.strip().find(" ") if ind2!=-1: header=line2.strip()[:ind2].strip().lower() match=line2.strip()[ind2+1:].strip() if not self.score_mod_is_valid(score_mod): if score_mod[0]=="!": self.errors.append(""+_("Syntax Error: Unknown Action on line:: ")+"\n%s\n" % (escape(line),)) else: self.errors.append(""+_("Syntax Error: Bad Score Modifier on line:: ")+"\n%s\n" % (escape(line),)) elif not self.header_is_valid(header,score_mod): self.errors.append(""+_("Syntax Error: Unknown Header Name on line:: ")+"\n%s\n" % (escape(line),)) elif not self.match_is_valid(match,header): self.errors.append(""+_("Syntax Error: Bad Match Rule on line:: ")+"\n%s\n" % (escape(line),)) else: self.group_rules_list[scope_number].append({"score_mod":score_mod,"header":header,"match":match}) def scan_for_block(self,line): scope=line[1:-1].strip() groups=[] if scope!="": if scope=="*": groups="*" else: groups=scope.split(" ") self.raw_scopes.append(line) return groups def load_file(self): "Score file parser" try: f=open(os.path.join(self.wdir,"scores.txt"),"r") except IOError: lines=[] else: lines=f.readlines() lines=[line.strip("\n").decode("utf-8") for line in lines] f.close() return lines def load_rules(self,lines): self.raw_file="\n".join(lines) self.group_scope_list=[] self.group_rules_list=[] self.errors=[] self.raw_scopes=[] current_group_scope=[] for line in lines: line=line.strip() if line!="": if line[0]!="#": #It's not empty nor a comment if line[0]=="[" and line[-1]=="]": #This is the group scope current_group_scope=self.scan_for_block(line) self.group_scope_list.append(current_group_scope) self.group_rules_list.append([]) elif line[0]=="+" or line[0]=="-" or line[0]=="=" or line[0]=="!": #This is a rule if current_group_scope: self.scan_for_rule(line) else: self.errors.append(""+_("Syntax Error: Missing scope for line :: ")+"\n%s\n" % (escape(line),)) else: self.errors.append(""+_("Syntax Error: Bad Line:: ")+"\n%s\n" % (escape(line),)) def build_match_rule(self,match): def build_plain_match_rule(match,index=1): """ Builds the match rule without the inverter information, index point to the start of the match (i.e. without the ~)""" if match[0].lower()=="c": #case sensitive if match[1]=="{": #regular expression match_rule=lambda field,regex: bool(re.compile(regex[index+1:-1],re.UNICODE).search(field)) else: #normal match match_rule=lambda field,word: bool(field.find(word[index+1:-1])+1) elif match[0].lower()!="%": #case sensitive if match[0]=="{": #regular expression match_rule=lambda field,regex: bool(re.compile(regex[index:-1],re.UNICODE|re.IGNORECASE).search(field)) else: #normal match match_rule=lambda field,word: bool(field.lower().find(word[index:-1].lower())+1) else: #numeric rule if match[1]==">": match_rule=lambda field,num: field>int(num[index+1:]) elif match[1]=="<": match_rule=lambda field,num: field9999: score=9999 if score<-9999: score=-9999 return score else: score=score+int(score_mod) i=i+1 if score>9999: score=9999 if score<-9999: score=-9999 return score def apply_action_rules(self,xpn_article,group): score=xpn_article.get_score() i=0 time_now=mktime_tz(parsedate_tz(time.ctime())) age=(time_now-xpn_article.secs)/(24.0*60*60) #compatibility check #there is no need here, it's has been already performed in apply_score_rules xpost=xpn_article.xref.count(":") fields={"subject":xpn_article.subj,"from":xpn_article.from_name,"date":xpn_article.date, "message-id":xpn_article.msgid,"references":xpn_article.ref,"age":age,"xref":xpn_article.xref, "bytes":xpn_article.bytes,"lines":xpn_article.lines,"xpost":xpost,"score":score} actions=[] for group_scope in self.group_scope_list: if group_scope=="*" or (group in group_scope): #current group is in this scope for rule in self.group_rules_list[i]: #let's apply rule match_rule=self.build_match_rule(rule["match"]) if match_rule(fields[rule["header"]],rule["match"]): action=rule["score_mod"] if action[0]=="!": #this is an action if action[1:]=="kill": #xpn_article=None pass #need this to let reapply_rules work elif action[1:]=="markread": xpn_article.is_read=True elif action[1:]=="markunread": xpn_article.is_read=False elif action[1:]=="mark": xpn_article.marked_for_download=True elif action[1:]=="unmark": xpn_article.marked_for_download=False elif action[1:]=="keep": xpn_article.keep=True elif action[1:]=="unkeep": xpn_article.keep=False elif action[1:]=="watch": xpn_article.watch=True xpn_article.ignore=False elif action[1:]=="ignore": xpn_article.watch=False xpn_article.ignore=True xpn_article.is_read=True elif action[1:]=="unsetwatchignore": xpn_article.watch=False xpn_article.ignore=False elif action[1:].startswith("setcolor"): regex=re.compile("(^setcolor)\((([a-z]+)|(#\w+));(([a-z]+)|(#\w+))\)") matches=regex.match(action[1:]) xpn_article.fg_color=str(matches.groups()[1]) xpn_article.bg_color=str(matches.groups()[4]) actions.append(action[1:]) i=i+1 return xpn_article,actions def __init__(self): self.wdir=get_wdir() self.headers=["from","subject","date","message-id","references","age","xref","xpost","bytes","lines"] self.action_headers=["from","subject","date","message-id","references","age","xref","xpost","bytes","lines","score"] self.actions=["kill","markread","markunread","mark","unmark","retrieve","keep","unkeep","watch","ignore","unsetwatchignore","setcolor"] self.group_scope_list=[] self.group_rules_list=[] self.errors=[] self.raw_file="" self.raw_scopes=[] self.lines=self.load_file() self.load_rules(self.lines) class Rules_Tree: def get_widget(self): return self.scrolledwin def insert(self,iter_parent,iter_sibling,values): iter=self.model.insert_before(iter_parent,iter_sibling) for i in range(len(values)): if i<3: value=values[i].encode("utf-8") else: value=values[i] self.model.set_value(iter,i,value) return iter def __init__(self): self.scrolledwin=gtk.ScrolledWindow() self.scrolledwin.set_border_width(4) self.scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.rules_tree=gtk.TreeView() self.rules_tree.set_border_width(4) self.model=gtk.TreeStore(gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_INT) text_renderer_scope=gtk.CellRendererText() text_renderer_scope.set_property("weight",1000) text_renderer=gtk.CellRendererText() self.column1=gtk.TreeViewColumn(_("Scope/Score Mod"),text_renderer_scope,text=0,weight=3) self.column2=gtk.TreeViewColumn(_("Header"),text_renderer,text=1) self.column3=gtk.TreeViewColumn(_("Match Rule"),text_renderer,text=2) self.rules_tree.append_column(self.column1) self.rules_tree.append_column(self.column2) self.rules_tree.append_column(self.column3) self.scrolledwin.add(self.rules_tree) self.rules_tree.set_model(self.model) class Score_Win: def delete_event(self,widget,event,data=None): return False def destroy(self,widget): lines=self.score_rules.load_file() self.score_rules.load_rules(lines) self.window.destroy() def show(self): self.window.show_all() self.match_value2_entry.hide() self.match_value2_label.hide() self.match_value_label.hide() self.action_match_value2_entry.hide() self.action_match_value2_label.hide() self.action_match_value_label.hide() self.color1_entry.hide() self.color1_button.hide() self.color1_label.hide() self.color2_entry.hide() self.color2_button.hide() self.color2_label.hide() def show_rules(self): self.rules_tree.model.clear() iter_scope=None group_scope_list=self.score_rules.group_scope_list group_rules_list=self.score_rules.group_rules_list for i in range(len(group_scope_list)): if group_scope_list[i]=="*": scope="[*]" else: scope="[ "+",\n".join(group_scope_list[i])+" ]" iter_scope=self.rules_tree.insert(None,None,[str(scope),"","",pango.WEIGHT_BOLD]) for rule in group_rules_list[i]: self.rules_tree.insert(iter_scope,None,[rule["score_mod"],rule["header"],rule["match"],pango.WEIGHT_NORMAL]) def show_errors(self,obj): errors="\n".join(self.score_rules.errors) if errors: self.dialog=Dialog_OK(errors.encode("utf-8")) else: self.dialog=Dialog_OK(_("No Errors")) def close_window(self,obj): start,stop=self.file_buffer.get_bounds() text=self.file_buffer.get_text(start,stop,True) f=open(os.path.join(self.wdir,"scores.txt"),"w") f.write(text) f.close() self.window.destroy() def rescan_rules(self,obj): start,stop=self.file_buffer.get_bounds() lines=self.file_buffer.get_text(start,stop,True).decode("utf-8").split("\n") self.score_rules.load_rules(lines) self.score_rules.lines=lines self.show_rules() subscribed=self.art_db.getSubscribed() subscribed=["["+subscribed[i][0]+"]" for i in range(len(subscribed))] popdown=self.score_rules.raw_scopes for item in subscribed: if item not in popdown: popdown.append(item) if "[*]" not in popdown: popdown.insert(0,"[*]") model=self.scope_combo.get_model() model.clear() self.scope_combo.set_model(model) model=self.action_scope_combo.get_model() model.clear() self.action_scope_combo.set_model(model) for item in popdown: self.scope_combo.append_text(item) self.action_scope_combo.append_text(item) iter_first=self.scope_combo.get_model().get_iter_first() self.scope_combo.set_active_iter(iter_first) iter_first=self.action_scope_combo.get_model().get_iter_first() self.action_scope_combo.set_active_iter(iter_first) def add_new_rule(self,obj): scope=self.scope_combo.child.get_text().decode("utf-8") header=self.score_rules.headers[self.header_opt_menu.get_active()] match_type=self.match_type_opt_menu.get_active() match_type, match_type_inverted =match_type/2,match_type%2 match_value=self.match_value_entry.get_text().decode("utf-8") case=self.case_checkbutton.get_active() action_type=self.score_mod_opt_menu.get_active() number=self.score_mod_spinbutton.get_value_as_int() if scope!="" and match_value!="": rule=[] if action_type==0 and number<0: number=repr(abs(number)) elif action_type==1: number=repr(abs(number)) elif action_type==2 and number>=0: number="+"+repr(number) else: number=repr(number) rule.append(["+","-","="][action_type]+number) rule.append(header.capitalize()) if match_type==0: match_value="\""+match_value+"\"" elif match_type==1: match_value="{"+match_value+"}" elif match_type==2: match_value="%>"+match_value elif match_type==3: match_value="%<"+match_value elif match_type==4: match_value="%="+match_value else: match_value2=self.match_value2_entry.get_text().decode("utf-8") match_value="%["+match_value+","+match_value2+"]" if (match_type in [0,1]) and case: match_value="c"+match_value if match_type_inverted: match_value="~"+match_value rule.append(match_value) rule=" ".join(rule) found_scope=False for i in range(len(self.score_rules.lines)): if scope==self.score_rules.lines[i]: found_scope=True break if found_scope==True: found_block_end=False for j in range(i,len(self.score_rules.lines)): if self.score_rules.lines[j]=="": found_block_end=True break if found_block_end: self.score_rules.lines.insert(j,rule) else: self.score_rules.lines.insert(i+1,rule) if found_scope==False: self.score_rules.lines.append("") self.score_rules.lines.append(scope) self.score_rules.lines.append(rule) self.score_rules.lines.append("") self.file_buffer.set_text(("\n".join(self.score_rules.lines)).encode("utf-8")) self.rescan_rules(None) def add_new_action_rule(self,obj): scope=self.action_scope_combo.child.get_text().decode("utf-8") header=self.score_rules.action_headers[self.action_header_opt_menu.get_active()] action_match_type=self.action_match_type_opt_menu.get_active() action_match_type, action_match_type_inverted =action_match_type/2,action_match_type%2 action_value=self.action_match_value_entry.get_text().decode("utf-8") case=self.action_case_checkbutton.get_active() #values=["Kill","Mark Read","Mark Unread","Mark for Download","UnMark for Download","Retrieve","Keep","UnKeep","Watch","Ignore","UnSetWatchIgnore"] action_type=self.action_type_opt_menu.get_active() if scope!="" and action_value!="": rule=[] if action_type!=11: rule.append(["!kill","!markread","!markunread","!mark","!unmark","!retrieve","!keep","!unkeep","!watch","!ignore","!unsetwatchignore"][action_type]) else: color_fg=self.color1_entry.get_text().decode("utf-8") color_bg=self.color2_entry.get_text().decode("utf-8") if color_fg=="": color_fg="Default" if color_bg=="": color_bg="Default" rule.append("!setcolor(%s;%s)" % (color_fg,color_bg)) rule.append(header.capitalize()) if action_match_type==0: action_value="\""+action_value+"\"" elif action_match_type==1: action_value="{"+action_value+"}" elif action_match_type==2: action_value="%>"+action_value elif action_match_type==3: action_value="%<"+action_value elif action_match_type==4: action_value="%="+action_value else: action_value2=self.action_match_value2_entry.get_text().decode("utf-8") action_value="%["+action_value+","+action_value2+"]" if (action_match_type in [0,1]) and case: action_value="c"+action_value if action_match_type_inverted: action_value="~"+action_value rule.append(action_value) rule=" ".join(rule) found_scope=False for i in range(len(self.score_rules.lines)): if scope==self.score_rules.lines[i]: found_scope=True break if found_scope==True: found_block_end=False for j in range(i,len(self.score_rules.lines)): if self.score_rules.lines[j]=="": found_block_end=True break if found_block_end: self.score_rules.lines.insert(j,rule) else: self.score_rules.lines.insert(i+1,rule) if found_scope==False: self.score_rules.lines.append("") self.score_rules.lines.append(scope) self.score_rules.lines.append(rule) self.score_rules.lines.append("") self.file_buffer.set_text(("\n".join(self.score_rules.lines)).encode("utf-8")) self.rescan_rules(None) def test_re(self,obj): RE=self.re_entry.get_text().decode("utf-8") bounds=self.text_buffer.get_bounds() if bounds and RE: start,stop=bounds test_text=self.text_buffer.get_text(start,stop,True).decode("utf-8") self.text_buffer.delete(start,stop) self.text_buffer.set_text(test_text.encode("utf-8")) if self.test_case_checkbutton.get_active()==True: matches=re.compile(RE,re.UNICODE).finditer(test_text) else: matches=re.compile(RE,re.UNICODE|re.IGNORECASE).finditer(test_text) for match in matches: match_start,match_stop,match_text= match.start(), match.end(), match.group() iter_start=self.text_buffer.get_iter_at_offset(match_start) iter_stop=self.text_buffer.get_iter_at_offset(match_stop) self.text_buffer.delete(iter_start,iter_stop) self.text_buffer.insert_with_tags_by_name(iter_start,match_text.encode("utf-8"),"match") def match_type_changed(self,obj): if self.match_type_opt_menu.get_active()/2==5: self.match_value2_entry.show() self.match_value2_label.show() self.match_value_label.show() self.match_value_entry.set_size_request(-1,-1) self.match_value2_entry.set_size_request(-1,-1) else: self.match_value2_entry.hide() self.match_value2_label.hide() self.match_value_label.hide() self.match_value_entry.set_size_request(200,-1) def action_match_type_changed(self,obj): if self.action_match_type_opt_menu.get_active()/2==5: self.action_match_value2_entry.show() self.action_match_value2_label.show() self.action_match_value_label.show() self.action_match_value_entry.set_size_request(-1,-1) self.action_match_value2_entry.set_size_request(-1,-1) else: self.action_match_value2_entry.hide() self.action_match_value2_label.hide() self.action_match_value_label.hide() self.action_match_value_entry.set_size_request(200,-1) def action_type_changed(self,obj): if self.action_type_opt_menu.get_active()==11: self.color1_label.show() self.color1_entry.show() self.color1_button.show() self.color2_entry.show() self.color2_button.show() self.color2_label.show() else: self.color1_label.hide() self.color1_entry.hide() self.color1_button.hide() self.color2_entry.hide() self.color2_button.hide() self.color2_label.hide() def get_color_from_button(self,color_button): def gdkcolor_to_hex(gdk_color): colors=[gdk_color.red,gdk_color.green,gdk_color.blue] colors= [("0"+str(hex(col*255/65535))[2:])[-2:].upper() for col in (colors)] color = "#"+colors[0]+colors[1]+colors[2] return color color=color_button.get_color() color=gdkcolor_to_hex(color) if color_button==self.color1_button: self.color1_entry.set_text(color) else: self.color2_entry.set_text(color) def __init__(self,score_rules,main_win): self.score_rules=score_rules self.wdir=get_wdir() self.art_db=main_win.art_db self.window=gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event",self.delete_event) self.window.connect("destroy",self.destroy) self.window.set_title(_("Scoring Rules")) self.window.set_position(gtk.WIN_POS_CENTER) self.window.set_default_size(450,450) self.window.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/score.xpm")) main_vbox=gtk.VBox() main_vbox.set_border_width(2) self.notebook=gtk.Notebook() #Rules Page vpaned=gtk.VPaned() vpaned.set_border_width(4) rules_vbox=gtk.VBox() rules_vbox_label=gtk.Label(""+_("Correct Rules")+"") rules_vbox_label.set_alignment(0,0.5) rules_vbox_label.set_use_markup(True) rules_vbox.pack_start(rules_vbox_label,False,False,4) self.rules_tree=Rules_Tree() rules_table=gtk.Table(1,1,False) rules_table.attach(self.rules_tree.get_widget(),0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,16) rules_vbox.pack_start(rules_table,True,True) file_vbox=gtk.VBox() file_vbox_label=gtk.Label(""+_("Score File Editor")+"") file_vbox_label.set_alignment(0,0.5) file_vbox_label.set_use_markup(True) file_vbox.pack_start(file_vbox_label,False,False,4) file_table=gtk.Table(3,2,False) file_scrolledwin=gtk.ScrolledWindow() file_scrolledwin.set_border_width(4) file_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) file_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.file_buffer=gtk.TextBuffer() self.file_view=gtk.TextView(self.file_buffer) self.file_view.set_border_width(4) self.file_view.modify_font(pango.FontDescription("Monospace 8")) self.file_buffer.set_text(self.score_rules.raw_file.encode("utf-8")) file_scrolledwin.add(self.file_view) file_butt_hbox=gtk.HBox() file_butt_hbox.set_border_width(4) self.button_rescan=gtk.Button(_("ReScan Rules")) self.button_rescan.connect("clicked",self.rescan_rules) self.button_show_errors=gtk.Button(_("Show Errors")) self.button_show_errors.connect("clicked",self.show_errors) file_butt_hbox.pack_start(self.button_rescan,True,True,2) file_butt_hbox.pack_start(self.button_show_errors,True,True,2) file_table.attach(file_scrolledwin,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,16) file_table.attach(file_butt_hbox,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16) file_vbox.pack_start(file_table,True,True) vpaned.add(file_vbox) vpaned.add(rules_vbox) rules_label=gtk.Label(""+_("Rules")+"") rules_label.set_use_markup(True) self.notebook.append_page(vpaned,rules_label) #New Score Rule Page new_rule_vbox=gtk.VBox() new_rule_vbox.set_border_width(4) scope_vbox=gtk.VBox() scope_vbox.set_border_width(4) scope_label=gtk.Label(""+_("Groups Scope")+"") scope_label.set_alignment(0,0.5) scope_label.set_use_markup(True) scope_vbox.pack_start(scope_label,False,False,4) self.scope_combo=gtk.combo_box_entry_new_text() popdown=self.score_rules.raw_scopes if "[*]" not in popdown: popdown.insert(0,"[*]") subscribed=self.art_db.getSubscribed() subscribed=["["+subscribed[i][0]+"]" for i in range(len(subscribed))] popdown=popdown+subscribed for item in popdown: self.scope_combo.append_text(item) self.scope_combo.set_active(0) self.scope_combo.set_size_request(250,-1) scope_hbox=gtk.HBox() scope_hbox.set_border_width(4) scope_hbox.pack_start(self.scope_combo,True,False,2) scope_vbox.add(scope_hbox) condition_main_vbox=gtk.VBox() condition_label=gtk.Label(""+_("Condition")+"") condition_label.set_alignment(0,0.5) condition_label.set_use_markup(True) condition_main_vbox.pack_start(condition_label,False,False,4) condition_table=gtk.Table(3,1,False) condition_hbox=gtk.HBox() self.header_opt_menu=gtk.combo_box_new_text() self.header_opt_menu.set_size_request(130,-1) for header in self.score_rules.headers: self.header_opt_menu.append_text(header.capitalize()) self.header_opt_menu.set_active(0) condition_hbox.pack_start(self.header_opt_menu,True,False,2) values=[_("Contains String"),_("Doesn't Contain String"),_("Matches RegEx"),_("Doesn't Match RegEx"), _("Greater Than"), _("Not Greater Than"), _("Lower Than"),_("Not Lower Than"), _("Equal To (numbers only)"),_("Different From (numbers only)"), _("In Range"),_("Out Of Range")] self.match_type_opt_menu=gtk.combo_box_new_text() self.match_type_opt_menu.set_size_request(130,-1) for value in values: self.match_type_opt_menu.append_text(value) self.match_type_opt_menu.set_active(0) self.match_type_opt_menu.connect("changed",self.match_type_changed) condition_hbox.pack_start(self.match_type_opt_menu,True,False) self.case_checkbutton=gtk.CheckButton(_("Case Sensitive")) self.match_value_entry=gtk.Entry() self.match_value_entry.set_size_request(200,-1) self.match_value2_entry=gtk.Entry() self.match_value_label=gtk.Label(_("Lower Limit")) self.match_value2_label=gtk.Label(_("Upper Limit")) match_value_hbox=gtk.HBox() match_value_hbox.pack_start(self.match_value_label,True,False,2) match_value_hbox.pack_start(self.match_value_entry,True,True,2) match_value_hbox.pack_start(self.match_value2_label,True,False,2) match_value_hbox.pack_start(self.match_value2_entry,True,True,2) condition_table.attach(condition_hbox,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) condition_table.attach(match_value_hbox,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) condition_table.attach(self.case_checkbutton,0,1,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) condition_main_vbox.pack_start(condition_table,True,True) score_mod_vbox=gtk.VBox() score_mod_label=gtk.Label(""+_("Score")+"") score_mod_label.set_use_markup(True) score_mod_label.set_alignment(0,0.5) score_mod_vbox.pack_start(score_mod_label,False,False,4) score_mod_table=gtk.Table(1,1,False) score_mod_hbox=gtk.HBox() values=[_("Raise Score"),_("Lower Score"), _("Set Score")] self.score_mod_opt_menu=gtk.combo_box_new_text() for value in values: self.score_mod_opt_menu.append_text(value) self.score_mod_opt_menu.set_active(0) self.score_mod_opt_menu.set_size_request(130,-1) score_mod_hbox.pack_start(self.score_mod_opt_menu,True,False,2) score_mod_table.attach(score_mod_hbox,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) score_mod_vbox.add(score_mod_table) self.score_mod_spinbutton=gtk.SpinButton(gtk.Adjustment(value=100,lower=-9999,upper=9999,step_incr=100,page_incr=1000)) self.score_mod_spinbutton.set_size_request(130,-1) score_mod_hbox.pack_start(self.score_mod_spinbutton,True,False,2) #add rule button self.add_rule_button=gtk.Button(_("Add Rule")) self.add_rule_button.connect("clicked",self.add_new_rule) new_rule_vbox.pack_start(scope_vbox,False,True,2) new_rule_vbox.pack_start(condition_main_vbox,True,True,2) new_rule_vbox.pack_start(score_mod_vbox,True,True,2) new_rule_vbox.pack_start(self.add_rule_button,True,False,2) new_rule_label=gtk.Label(""+_("New Scoring Rule")+"") new_rule_label.set_use_markup(True) self.notebook.append_page(new_rule_vbox,new_rule_label) #New Action Rule Page new_action_rule_vbox=gtk.VBox() new_action_rule_vbox.set_border_width(4) action_scope_vbox=gtk.VBox() action_scope_vbox.set_border_width(4) action_scope_label=gtk.Label(""+_("Groups Scope")+"") action_scope_label.set_use_markup(True) action_scope_label.set_alignment(0,0.5) action_scope_vbox.pack_start(action_scope_label,False,False,4) self.action_scope_combo=gtk.combo_box_entry_new_text() popdown=self.score_rules.raw_scopes if "[*]" not in popdown: popdown.insert(0,"[*]") subscribed=self.art_db.getSubscribed() subscribed=["["+subscribed[i][0]+"]" for i in range(len(subscribed))] popdown=popdown+subscribed for item in popdown: self.action_scope_combo.append_text(item) self.action_scope_combo.set_active(0) self.action_scope_combo.set_size_request(250,-1) action_scope_hbox=gtk.HBox() action_scope_hbox.set_border_width(4) action_scope_hbox.pack_start(self.action_scope_combo,True,False,2) action_scope_vbox.add(action_scope_hbox) action_condition_main_vbox=gtk.VBox() action_condition_label=gtk.Label(""+_("Condition")+"") action_condition_label.set_alignment(0,0.5) action_condition_label.set_use_markup(True) action_condition_main_vbox.pack_start(action_condition_label,False,False,4) action_condition_table=gtk.Table(3,1,False) action_condition_hbox=gtk.HBox() self.action_header_opt_menu=gtk.combo_box_new_text() self.action_header_opt_menu.set_size_request(130,-1) for header in self.score_rules.action_headers: self.action_header_opt_menu.append_text(header.capitalize()) self.action_header_opt_menu.set_active(0) action_condition_hbox.pack_start(self.action_header_opt_menu,True,False,2) values=[_("Contains String"),_("Doesn't Contain String"),_("Matches RegEx"),_("Doesn't Match RegEx"), _("Greater Than"), _("Not Greater Than"), _("Lower Than"),_("Not Lower Than"), _("Equal To (numbers only)"),_("Different From (numbers only)"), _("In Range"),_("Out Of Range")] self.action_match_type_opt_menu=gtk.combo_box_new_text() self.action_match_type_opt_menu.set_size_request(130,-1) for value in values: self.action_match_type_opt_menu.append_text(value) self.action_match_type_opt_menu.set_active(0) self.action_match_type_opt_menu.connect("changed",self.action_match_type_changed) action_condition_hbox.pack_start(self.action_match_type_opt_menu,True,False) self.action_case_checkbutton=gtk.CheckButton(_("Case Sensitive")) self.action_match_value_entry=gtk.Entry() self.action_match_value_entry.set_size_request(200,-1) self.action_match_value2_entry=gtk.Entry() self.action_match_value_label=gtk.Label(_("Lower Limit")) self.action_match_value2_label=gtk.Label(_("Upper Limit")) action_match_value_hbox=gtk.HBox() action_match_value_hbox.pack_start(self.action_match_value_label,True,False,2) action_match_value_hbox.pack_start(self.action_match_value_entry,True,True,2) action_match_value_hbox.pack_start(self.action_match_value2_label,True,False,2) action_match_value_hbox.pack_start(self.action_match_value2_entry,True,True,2) action_condition_table.attach(action_condition_hbox,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) action_condition_table.attach(action_match_value_hbox,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) action_condition_table.attach(self.action_case_checkbutton,0,1,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) action_condition_main_vbox.add(action_condition_table) action_vbox=gtk.VBox() action_label=gtk.Label(""+_("Action")+"") action_label.set_use_markup(True) action_label.set_alignment(0,0.5) action_vbox.pack_start(action_label,False,False,4) action_table=gtk.Table(1,1,False) action_hbox=gtk.HBox() action_setcolor_hbox=gtk.HBox() action_setcolor_color_hbox=gtk.HBox() values=[_("Kill"),_("Mark Read"),_("Mark Unread"),_("Mark for Download"),_("UnMark for Download"),_("Retrieve"),_("Keep"),_("UnKeep"),_("Watch"),_("Ignore"),_("UnSetWatchIgnore"),_("SetColor")] self.action_type_opt_menu=gtk.combo_box_new_text() for value in values: self.action_type_opt_menu.append_text(value) self.action_type_opt_menu.set_active(0) self.action_type_opt_menu.set_size_request(130,-1) self.action_type_opt_menu.connect("changed",self.action_type_changed) action_hbox.pack_start(self.action_type_opt_menu,True,False,2) self.color1_label=gtk.Label(_("Foreground Color")) self.color2_label=gtk.Label(_("Background Color")) self.color1_entry=gtk.Entry() self.color2_entry=gtk.Entry() self.color1_button=gtk.ColorButton() self.color2_button=gtk.ColorButton() self.color1_button.connect("color_set",self.get_color_from_button) self.color2_button.connect("color_set",self.get_color_from_button) action_setcolor_color_hbox.pack_start(self.color1_label,True,False) action_setcolor_color_hbox.pack_start(self.color2_label,True,False) action_setcolor_hbox.pack_start(self.color1_entry,True,False,2) action_setcolor_hbox.pack_start(self.color1_button,True,False,2) action_setcolor_hbox.pack_start(self.color2_entry,True,False,2) action_setcolor_hbox.pack_start(self.color2_button,True,False,2) action_table.attach(action_hbox,0,1,0,1,gtk.EXPAND|gtk.FILL,16,6) action_table.attach(action_setcolor_color_hbox,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) action_table.attach(action_setcolor_hbox,0,1,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) action_vbox.pack_start(action_table,True,True) #add action rule button self.add_action_rule_button=gtk.Button(_("Add Rule")) self.add_action_rule_button.connect("clicked",self.add_new_action_rule) new_action_rule_vbox.pack_start(action_scope_vbox,False,True,2) new_action_rule_vbox.pack_start(action_condition_main_vbox,True,True,2) new_action_rule_vbox.pack_start(action_vbox,True,True,2) new_action_rule_vbox.pack_start(self.add_action_rule_button,True,False,2) new_action_rule_label=gtk.Label(""+_("New Action Rule")+"") new_action_rule_label.set_use_markup(True) self.notebook.append_page(new_action_rule_vbox,new_action_rule_label) #RegEx Tester Page re_tester_vbox=gtk.VBox() re_tester_vbox.set_border_width(4) re_vbox=gtk.VBox() re_label=gtk.Label(""+_("Regular Expression")+"") re_label.set_use_markup(True) re_label.set_alignment(0,0.5) re_vbox.pack_start(re_label,False,False,4) re_table=gtk.Table(1,1,False) re_table.set_border_width(2) self.re_entry=gtk.Entry() re_test_button=gtk.Button(_("Test Regular Expression")) re_test_button.connect("clicked",self.test_re) self.test_case_checkbutton=gtk.CheckButton(_("Case Sensitive")) re_table.attach(self.re_entry,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) re_table.attach(self.test_case_checkbutton,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) re_table.attach(re_test_button,0,1,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) re_vbox.add(re_table) re_tester_vbox.pack_start(re_vbox,False,True,2) text_vbox=gtk.VBox() text_label=gtk.Label(""+_("Test Text")+"") text_label.set_alignment(0,0.5) text_label.set_use_markup(True) text_vbox.pack_start(text_label,False,False,4) text_table=gtk.Table(1,1,False) text_scrolledwin=gtk.ScrolledWindow() text_scrolledwin.set_border_width(4) text_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) text_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.text_buffer=gtk.TextBuffer() self.text_view=gtk.TextView(self.text_buffer) self.text_view.set_border_width(4) text_scrolledwin.add(self.text_view) text_table.attach(text_scrolledwin,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,16) text_vbox.pack_start(text_table,True,True) re_tester_vbox.pack_start(text_vbox,True,True,2) re_tester_label=gtk.Label(""+_("RE Tester")+"") re_tester_label.set_use_markup(True) self.notebook.append_page(re_tester_vbox,re_tester_label) #OK CANCEL buttons main_buttons_hbox=gtk.HBox() main_buttons_hbox.set_border_width(4) cancel_button=gtk.Button(None,gtk.STOCK_CANCEL) cancel_button_tooltip=gtk.Tooltips() cancel_button_tooltip.set_tip(cancel_button,_("Close window. Discard changes")) cancel_button.connect("clicked",self.destroy) main_buttons_hbox.pack_start(cancel_button,True,True,0) ok_button=gtk.Button(None,gtk.STOCK_OK) ok_button_tooltip=gtk.Tooltips() ok_button_tooltip.set_tip(ok_button,_("Close window. Save Changes")) ok_button.connect("clicked",self.close_window) main_buttons_hbox.pack_start(ok_button,True,True,2) vpaned.set_position(200) main_vbox.pack_start(self.notebook,True,True,0) main_vbox.pack_start(main_buttons_hbox,False,False,0) self.window.add(main_vbox) #some init self.show_rules() tag_table=self.text_buffer.get_tag_table() tag_match=gtk.TextTag("match") tag_table.add(tag_match) color_bg=gtk.gdk.color_parse("#0000FF") color_fg=gtk.gdk.color_parse("#FFFFFF") tag_match.set_property("weight",1000) tag_match.set_property("background-gdk",color_bg) tag_match.set_property("foreground-gdk",color_fg) if __name__=="__main__": Score_Rules() xpn-1.2.6/xpn_src/UserDir.py0000644000175000017500000000435111141275756014072 0ustar antantimport sys import os def getHomeDir(): ''' Try to find user's home directory, otherwise return current directory.''' try: path1=os.path.expanduser("~") except: path1="" try: path2=os.environ["HOME"] except: path2="" try: path3=os.path.join(os.environ["HOMEDRIVE"],os.environ["HOMEPATH"]) except: path3="" try: path4=os.environ["USERPROFILE"] except: path4="" if not os.path.exists(path1): if not os.path.exists(path2): if not os.path.exists(path3): if not os.path.exists(path4): return os.getcwd() else: return path4 else: return path3 else: return path2 else: return path1 def get_wdir(): return wdir wdir="" class UserDir: def __init__(self,cwd=False,userHome=False,customPath=""): '''Init user dir. Arguments: cwd :if True XPN will use it's own directory userHome :if True XPN will create a .xpn directory inside user's home directory. customPath:if True XPN will create a .xpn directry inside user's defined path. ''' global wdir if cwd: self.dir="" elif userHome: self.dir=os.path.join(getHomeDir(),".xpn") else: if os.path.exists(customPath): self.dir=os.path.join(customPath,".xpn") else: self.dir="" wdir=self.dir def Create(self): if not os.path.isdir(self.dir) and self.dir: if not os.path.exists(self.dir): try: os.mkdir(self.dir) except: print "Error: Can't create \"%s\"." % self.dir return 1 else: print "Error: Please remove \"%s\" file." % self.dir return 2 #then check write access try: f=file(os.path.join(self.dir,"write-test"),"w") except IOError: print "Error: Can't write in \"%s\"." % self.dir return 3 else: f.write("test") f.close() os.remove(os.path.join(self.dir,"write-test")) return 0 xpn-1.2.6/xpn_src/Groups_Vs_ID.py0000700000175000017500000001037111141275756015010 0ustar antantimport gtk import cPickle import os import ConfigParser from xpn_src.UserDir import get_wdir class Groups_Vs_ID: def show(self): self.win.show_all() def delete_event(self,widget,event,data=None): return False def destroy(self,obj): self.win.destroy() def save_configs(self,obj): subscribed=self.art_db.getSubscribed() new_list=[] subscribed_groups=[] for group in subscribed: combo=self.id_dict[group[0]] id_name=combo.get_active_text() new_group=[group[0] ,group[1], group[2], id_name] subscribed_groups.append([group[0], group[2], id_name]) new_list.append(new_group) self.art_db.updateSubscribed(new_list) self.main_win.subscribed_groups=subscribed_groups[:] self.win.destroy() def __init__(self,subscribed_groups,main_win): self.main_win=main_win self.art_db=main_win.art_db n_rows=len(subscribed_groups) self.win=gtk.Window(gtk.WINDOW_TOPLEVEL) self.win.connect("delete_event",self.delete_event) self.win.set_title(_("Assign Identities to Groups")) self.win.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/conf.xpm")) self.win.set_position(gtk.WIN_POS_CENTER) main_vbox=gtk.VBox() main_vbox.set_border_width(4) group_label=gtk.Label(""+_("Group")+"") group_label.set_alignment(0,0) group_label.set_use_markup(True) id_label=gtk.Label(""+_("Identity")+"") id_label.set_alignment(0,0) id_label.set_use_markup(True) groups_table=gtk.Table(n_rows,2,False) groups_table.set_border_width(8) groups_table.attach(group_label,0,1,0,1,False,False,4) groups_table.attach(id_label,1,2,0,1,False,False,4) self.entries=[] self.combos=[] cp_id=ConfigParser.ConfigParser() cp_id.read(os.path.join(get_wdir(),"dats","id.txt")) ids=cp_id.sections() j=0 positions=dict() for id in ids: positions[id.decode("utf-8")]=j j=j+1 i=0 self.id_dict=dict() for group in subscribed_groups: entry=gtk.Entry() entry.set_editable(False) entry.set_text(group[0]) combo=gtk.combo_box_new_text() for id in ids: combo.append_text(id) combo.set_active(positions.get(group[2],0)) self.id_dict[group[0]]=combo groups_table.attach(entry,0,1,i+1,i+2,gtk.EXPAND|gtk.FILL,gtk.FILL) groups_table.attach(combo,1,2,i+1,i+2,gtk.FILL,gtk.EXPAND|gtk.SHRINK) self.entries.append(entry) self.combos.append(combo) i=i+1 viewport=gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_ETCHED_IN) scrolledwin=gtk.ScrolledWindow() scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) #buttons hbox buttons_hbox=gtk.HBox() #cancel_button self.cancel_button=gtk.Button(None,gtk.STOCK_CANCEL) self.cancel_button_tooltip=gtk.Tooltips() self.cancel_button_tooltip.set_tip(self.cancel_button,_("Close window. Discard changes")) self.cancel_button.connect("clicked",self.destroy) buttons_hbox.pack_start(self.cancel_button,True,True,0) #ok_button self.ok_button=gtk.Button(None,gtk.STOCK_OK) self.ok_button.connect("clicked",self.save_configs) self.ok_button_tooltip=gtk.Tooltips() self.ok_button_tooltip.set_tip(self.ok_button,_("Close window and save settings")) buttons_hbox.pack_start(self.ok_button,True,True,0) self.ok_button.set_border_width(5) self.cancel_button.set_border_width(5) viewport.add(groups_table) scrolledwin.add(viewport) main_vbox.pack_start(scrolledwin,True,True,4) main_vbox.pack_start(buttons_hbox,False,False,0) self.win.add(main_vbox) #self.win.set_default_size(300,300) self.win.set_size_request(350,300) xpn-1.2.6/xpn_src/Config_Win.py0000644000175000017500000020525711141275756014547 0ustar antantimport gtk import pango import gobject import webbrowser import os import gettext import ConfigParser from xpn_src.Config_File import Config_File from xpn_src.add_tag import Tags_Window from xpn_src.Charset_List import encodings_list, encodings_tip, CharsetList from xpn_src.Headers_List import HeadersList from xpn_src.UserDir import get_wdir from xpn_src.Connections_Handler import Connection, SSLConnection from xpn_src.Server_Win import NNTPServer_Win from xpn_src.ID_Win import ID_Win class Config_Win: def show(self): self.win.show_all() def delete_event(self,widget,event,data=None): return False def destroy(self,obj): self.win.destroy() def gdkcolor_to_hex(self,gdk_color): colors=[gdk_color.red,gdk_color.green,gdk_color.blue] colors= [("0"+str(hex(col*255/65535))[2:])[-2:].upper() for col in (colors)] color = "#"+colors[0]+colors[1]+colors[2] return color def update_text_color_entry(self,obj): color=obj.get_color() color=self.gdkcolor_to_hex(color) if obj==self.text_color_button: self.apply_text_color(self.text_color_entry,obj,color) elif obj==self.quote1_color_button: self.apply_text_color(self.quote1_color_entry,obj,color) elif obj==self.quote2_color_button: self.apply_text_color(self.quote2_color_entry,obj,color) elif obj==self.quote3_color_button: self.apply_text_color(self.quote3_color_entry,obj,color) elif obj==self.sign_color_button: self.apply_text_color(self.sign_color_entry,obj,color) elif obj==self.url_color_button: self.apply_text_color(self.url_color_entry,obj,color) else: self.apply_text_color(self.headers_color_entry,obj,color) def update_back_color_entry(self,obj): color=obj.get_color() color=self.gdkcolor_to_hex(color) self.apply_back_color(obj,color) def apply_text_color(self,widget,button,color): style=widget.get_style().copy() gdk_color=gtk.gdk.color_parse(color) style.text[gtk.STATE_NORMAL]=gdk_color button.set_color(gdk_color) widget.set_style(style) def apply_back_color(self,button,color): if not button==self.headers_bg_color_button: style=self.text_color_entry.get_style().copy() gdk_color=gtk.gdk.color_parse(color) style.base[gtk.STATE_NORMAL]=gdk_color self.text_color_entry.set_style(style) style=self.quote1_color_entry.get_style().copy() style.base[gtk.STATE_NORMAL]=gdk_color self.quote1_color_entry.set_style(style) style=self.quote2_color_entry.get_style().copy() style.base[gtk.STATE_NORMAL]=gdk_color self.quote2_color_entry.set_style(style) style=self.quote3_color_entry.get_style().copy() style.base[gtk.STATE_NORMAL]=gdk_color self.quote3_color_entry.set_style(style) style=self.sign_color_entry.get_style().copy() style.base[gtk.STATE_NORMAL]=gdk_color self.sign_color_entry.set_style(style) self.background2_color_label.set_text(color) style=self.url_color_entry.get_style().copy() style.base[gtk.STATE_NORMAL]=gdk_color self.url_color_entry.set_style(style) else: style=self.headers_color_entry.get_style().copy() gdk_color=gtk.gdk.color_parse(color) style.base[gtk.STATE_NORMAL]=gdk_color self.headers_color_entry.set_style(style) self.headers2_bg_color_label.set_text(color) button.set_color(gdk_color) def get_text_color(self,widget): style=widget.get_style().copy() gdk_color=style.text[gtk.STATE_NORMAL] color=self.gdkcolor_to_hex(gdk_color) return color def get_back_color(self,widget): style=widget.get_style().copy() gdk_color=style.base[gtk.STATE_NORMAL] color=self.gdkcolor_to_hex(gdk_color) return color def update_all(self,configs): self.mail_server_entry.set_text(configs["smtp_server"]) self.mail_port_entry.set_text(configs["smtp_port"]) if configs["smtp_auth"]=="True": self.mail_server_auth_checkbutton.set_active(True) else: self.mail_server_auth_checkbutton.set_active(False) self.mail_server_username.set_sensitive(False) self.mail_server_password.set_sensitive(False) self.mail_username_label.set_sensitive(False) self.mail_password_label.set_sensitive(False) self.mail_server_username.set_text(configs["smtp_username"]) self.mail_server_password.set_text(configs["smtp_password"]) self.font_article_button.set_font_name(configs["font_name"].encode("utf-8")) self.font_threads_button.set_font_name(configs["font_threads_name"].encode("utf-8")) self.font_groups_button.set_font_name(configs["font_groups_name"].encode("utf-8")) self.use_system_fonts_checkbutton.set_active(configs.get("use_system_fonts","True")=="True") self.change_fonts_status(None) self.apply_back_color(self.background_color_button,configs["background_color"]) self.text_color_entry.set_text("Text Color") self.apply_text_color(self.text_color_entry,self.text_color_button,configs["text_color"]) self.quote1_color_entry.set_text(">Quoted Text Level 1 Color") self.apply_text_color(self.quote1_color_entry,self.quote1_color_button,configs["quote1_color"]) self.quote2_color_entry.set_text(">Quoted Text Level 2 Color") self.apply_text_color(self.quote2_color_entry,self.quote2_color_button,configs["quote2_color"]) self.quote3_color_entry.set_text(">Quoted Text Level 3 Color") self.apply_text_color(self.quote3_color_entry,self.quote3_color_button,configs["quote3_color"]) self.sign_color_entry.set_text("Sign Color") self.apply_text_color(self.sign_color_entry,self.sign_color_button,configs["sign_color"]) self.url_color_entry.set_text("http://xpn.altervista.org") self.apply_text_color(self.url_color_entry,self.url_color_button,configs["url_color"]) self.headers_color_entry.set_text("Header: sample") self.apply_text_color(self.headers_color_entry,self.headers_fg_color_button,configs["headers_fg_color"]) self.apply_back_color(self.headers_bg_color_button,configs["headers_bg_color"]) self.layout_radiobuttons[0].set_active(True) layout_number=int(self.configs["layout"]) self.layout_radiobuttons[layout_number-1].set_active(True) if self.configs["exp_column"]=="From": self.thread_exp_radiobutton2.set_active(True) else: self.thread_exp_radiobutton1.set_active(True) self.headers_checkbutton.set_active(configs.get("show_headers","False")=="True") self.oneclick_checkbutton.set_active(configs.get("oneclick","False")=="True") self.advance_on_mark_checkbutton.set_active(configs.get("advance_on_mark","False")=="True") self.oneclick_article_checkbutton.set_active(configs.get("oneclick_article","False")=="True") self.expand_groups_checkbutton.set_active(configs.get("expand_group","False")=="True") self.one_key_spin.set_value(int(configs["scroll_fraction"])) self.sort_order_checkbutton.set_active(configs.get("ascend_order","False")=="True") self.sort_combo.child.set_text(configs["sort_col"].encode("utf-8").capitalize()) self.fallback_charset_combo.child.set_text(configs["fallback_charset"]) if configs["custom_browser"]=="True": self.browser_checkbutton.set_active(True) self.browser_entry.set_text(configs["browser_launcher"].encode("utf-8")) else: self.browser_checkbutton.set_active(False) self.browser_entry.set_sensitive(False) self.editor_checkbutton.set_active(eval(configs["external_editor"])) self.editor_entry.set_text(configs["editor_launcher"].encode("utf-8")) self.purge_read_spinbutton.set_value(int(configs["purge_read"])) self.purge_unread_spinbutton.set_value(int(configs["purge_unread"])) self.download_bodies_checkbutton.set_active(eval(configs["download_bodies"])) if configs["limit_articles"]=="True": self.limit_articles_checkbutton.set_active(True) self.limit_articles_spinbutton.set_sensitive(True) else: self.limit_articles_spinbutton.set_sensitive(False) self.limit_articles_spinbutton.set_value(int(configs["limit_articles_number"])) if configs["automatic_download"]=="True": self.auto_download_checkbutton.set_active(True) self.auto_download_spinbutton.set_sensitive(True) else: self.auto_download_spinbutton.set_sensitive(False) self.auto_download_spinbutton.set_value(int(configs["download_timeout"])) try: self.configs["threading_method"] # upgrading check except KeyError: self.config["threading_method"]=2 # upgrading check if self.configs["threading_method"]=="1": self.threading_method_radiobutton1.set_active(True) else: self.threading_method_radiobutton2.set_active(True) if self.configs["lang"]=="en": self.lang_en_radiobutton.set_active(True) elif configs["lang"]=="it": self.lang_it_radiobutton.set_active(True) elif configs["lang"]=="fr": self.lang_fr_radiobutton.set_active(True) elif configs["lang"]=="de": self.lang_de_radiobutton.set_active(True) else: self.lang_en_radiobutton.set_active(True) def save_configs(self,object,conf): conf.configs["smtp_server"]=self.mail_server_entry.get_text().decode("utf-8") conf.configs["smtp_port"]=self.mail_port_entry.get_text() if self.mail_server_auth_checkbutton.get_active(): conf.configs["smtp_auth"]="True" conf.configs["smtp_username"]=self.mail_server_username.get_text() conf.configs["smtp_password"]=self.mail_server_password.get_text() else: conf.configs["smtp_auth"]="False" conf.configs["smtp_username"]="" conf.configs["smtp_password"]="" conf.configs["font_name"]=self.font_article_button.get_font_name() conf.configs["font_threads_name"]=self.font_threads_button.get_font_name() conf.configs["font_groups_name"]=self.font_groups_button.get_font_name() conf.configs["use_system_fonts"]=str(bool(self.use_system_fonts_checkbutton.get_active())) conf.configs["text_color"]=self.get_text_color(self.text_color_entry) conf.configs["quote1_color"]=self.get_text_color(self.quote1_color_entry) conf.configs["quote2_color"]=self.get_text_color(self.quote2_color_entry) conf.configs["quote3_color"]=self.get_text_color(self.quote3_color_entry) conf.configs["sign_color"]=self.get_text_color(self.sign_color_entry) conf.configs["background_color"]=self.get_back_color(self.text_color_entry) conf.configs["url_color"]=self.get_text_color(self.url_color_entry) conf.configs["headers_fg_color"]=self.get_text_color(self.headers_color_entry) conf.configs["headers_bg_color"]=self.get_back_color(self.headers_color_entry) for rbutton in self.layout_radiobuttons: if rbutton.get_active(): conf.configs["layout"]=str(self.layout_radiobuttons.index(rbutton)+1) break if self.thread_exp_radiobutton1.get_active(): conf.configs["exp_column"]="Subject" else: conf.configs["exp_column"]="From" conf.configs["show_headers"]=str(bool(self.headers_checkbutton.get_active())) conf.configs["oneclick"]=str(bool(self.oneclick_checkbutton.get_active())) conf.configs["advance_on_mark"]=str(bool(self.advance_on_mark_checkbutton.get_active())) conf.configs["oneclick_article"]=str(bool(self.oneclick_article_checkbutton.get_active())) conf.configs["expand_group"]=str(bool(self.expand_groups_checkbutton.get_active())) conf.configs["scroll_fraction"]=repr(self.one_key_spin.get_value_as_int()) conf.configs["sort_col"]=self.sort_combo.child.get_text().decode("utf-8") conf.configs["ascend_order"]=str(bool(self.sort_order_checkbutton.get_active())) conf.configs["fallback_charset"]=self.fallback_charset_combo.child.get_text() # if self.browser_checkbutton.get_active() and self.browser_entry.get_text().strip() and \ # self.exists(self.browser_entry.get_text().strip()): if self.browser_checkbutton.get_active() and self.browser_entry.get_text().strip(): conf.configs["custom_browser"]="True" conf.configs["browser_launcher"]=self.browser_entry.get_text().decode("utf-8") else: conf.configs["custom_browser"]="False" conf.configs["browser_launcher"]="" if self.exists(self.editor_entry.get_text().strip()): conf.configs["editor_launcher"]=self.editor_entry.get_text().decode("utf-8") else: conf.configs["editor_launcher"]="" conf.configs["external_editor"]=str(bool(self.editor_checkbutton.get_active())) conf.configs["purge_read"]=repr(self.purge_read_spinbutton.get_value_as_int()) conf.configs["purge_unread"]=repr(self.purge_unread_spinbutton.get_value_as_int()) conf.configs["download_bodies"]=repr(bool(self.download_bodies_checkbutton.get_active())) conf.configs["limit_articles"]=repr(bool(self.limit_articles_checkbutton.get_active())) conf.configs["limit_articles_number"]=repr(self.limit_articles_spinbutton.get_value_as_int()) conf.configs["automatic_download"]=repr(bool(self.auto_download_checkbutton.get_active())) conf.configs["download_timeout"]=repr(self.auto_download_spinbutton.get_value_as_int()) if self.threading_method_radiobutton1.get_active(): conf.configs["threading_method"]="1" else: conf.configs["threading_method"]="2" if self.lang_en_radiobutton.get_active(): conf.configs["lang"]="en" elif self.lang_it_radiobutton.get_active(): conf.configs["lang"]="it" elif self.lang_fr_radiobutton.get_active(): conf.configs["lang"]="fr" elif self.lang_de_radiobutton.get_active(): conf.configs["lang"]="de" else: conf.configs["lang"]="en" conf.write_configs() self.win.destroy() self.apply_changes(conf.configs) def exists(self, text): result=text.rfind("%s") ## if the string doesn't exist result=-1, we return 0 return result+1 def apply_changes(self,configs): #change the font if self.use_system_fonts_checkbutton.get_active(): self.main_win.article_pane.textview.modify_font(pango.FontDescription("")) self.main_win.threads_pane.threads_tree.modify_font(pango.FontDescription("")) self.main_win.groups_pane.groups_list.modify_font(pango.FontDescription("")) else: if configs["fixed"]=="False": self.main_win.article_pane.textview.modify_font(pango.FontDescription(configs["font_name"])) self.main_win.threads_pane.threads_tree.modify_font(pango.FontDescription(configs["font_threads_name"])) self.main_win.groups_pane.groups_list.modify_font(pango.FontDescription(configs["font_groups_name"])) #show-hide headers to_show = configs["show_headers"]=="True" self.main_win.article_pane.expander.set_expanded(to_show) #update_colors self.main_win.article_pane.set_text_color(configs["text_color"]) self.main_win.article_pane.set_quote_color(configs["quote1_color"],1) self.main_win.article_pane.set_quote_color(configs["quote2_color"],2) self.main_win.article_pane.set_quote_color(configs["quote3_color"],3) self.main_win.article_pane.set_sign_color(configs["sign_color"]) self.main_win.article_pane.set_background(configs["background_color"]) self.main_win.article_pane.set_url_color(configs["url_color"]) self.main_win.article_pane.set_headers_colors(configs["headers_bg_color"],configs["headers_fg_color"]) self.main_win.groups_pane.set_background(configs["background_color"]) self.main_win.groups_pane.set_foreground(configs["text_color"]) self.main_win.threads_pane.set_background(configs["background_color"]) self.main_win.threads_pane.set_foreground(configs["text_color"]) #show thread cause possible sorting changes self.main_win.show_threads(self.main_win.groups_pane.get_first_selected_group()) #update expander column self.main_win.threads_pane.threads_tree.remove_column(self.main_win.threads_pane.column2) self.main_win.threads_pane.threads_tree.remove_column(self.main_win.threads_pane.column3) if configs["exp_column"]=="From": self.main_win.threads_pane.threads_tree.insert_column(self.main_win.threads_pane.column3,1) self.main_win.threads_pane.threads_tree.insert_column(self.main_win.threads_pane.column2,2) self.main_win.threads_pane.threads_tree.set_expander_column(self.main_win.threads_pane.column3) else: self.main_win.threads_pane.threads_tree.insert_column(self.main_win.threads_pane.column2,1) self.main_win.threads_pane.threads_tree.insert_column(self.main_win.threads_pane.column3,2) self.main_win.threads_pane.threads_tree.set_expander_column(self.main_win.threads_pane.column2) #update browser launcher if configs["custom_browser"]=="True": self.main_win.article_pane.use_custom_browser=True webbrowser.register("xpn_launcher",None,webbrowser.GenericBrowser(configs["browser_launcher"])) else: self.main_win.article_pane.use_custom_browser=False #udatep headers shown self.main_win.article_pane.repopulate_headers() #update connection for connection in self.main_win.connectionsPool.itervalues(): connection.closeConnection() cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) self.main_win.connectionsPool=dict() for server in cp.sections(): if cp.get(server,"nntp_use_ssl")=="True": self.main_win.connectionsPool[server]=SSLConnection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) else: self.main_win.connectionsPool[server]=Connection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) def update_layout(self,obj,configs=None,layout_number=0): #update_layout layout_methods = {"1":self.main_win.build_layout_type_1, "2":self.main_win.build_layout_type_2, "3":self.main_win.build_layout_type_3, "4":self.main_win.build_layout_type_4 } if configs: r,c=divmod(int(configs["layout"])-1,6) else: r,c=divmod(layout_number-1,6) layout_builder = layout_methods.get(str(r+1), None) if layout_builder: layout_builder(c+1) else: self.main_win.build_layout_type_1(1) # If there is no layout associated to # self.configs["layout"] then build 1 self.main_win.set_sizes() def change_fonts_status(self,obj): status=self.use_system_fonts_checkbutton.get_active() self.font_article_hbox.set_sensitive(not status) self.font_threads_hbox.set_sensitive(not status) self.font_groups_hbox.set_sensitive(not status) def change_mid_status(self,obj): status=self.generate_mid_checkbutton.get_active() self.fqdn_entry.set_sensitive(status) self.fqdn_label.set_sensitive(status) def change_auth_status(self,obj): status=self.server_auth_checkbutton.get_active() self.server_username.set_sensitive(status) self.server_password.set_sensitive(status) self.username_label.set_sensitive(status) self.password_label.set_sensitive(status) def change_ssl_status(self,checkbutton): status=checkbutton.get_active() if status: self.port_entry.set_text("563") else: self.port_entry.set_text("119") def change_mail_auth_status(self,obj): status=self.mail_server_auth_checkbutton.get_active() self.mail_server_username.set_sensitive(status) self.mail_server_password.set_sensitive(status) self.mail_username_label.set_sensitive(status) self.mail_password_label.set_sensitive(status) def change_browser_status(self,obj): status=self.browser_checkbutton.get_active() self.browser_label.set_sensitive(status) self.browser_entry.set_sensitive(status) def change_limit_status(self,obj): status=self.limit_articles_checkbutton.get_active() self.limit_articles_spinbutton.set_sensitive(status) def change_auto_download_status(self,obj): status=self.auto_download_checkbutton.get_active() self.auto_download_spinbutton.set_sensitive(status) def add_tag_line(self,obj): tag_win=Tags_Window() def open_charset_list_win(self,obj): charset_list_win=CharsetList() def open_headers_list_win(self,obj): headers_list_win=HeadersList() def insert_rb(self,name,icon_name,shortname,tooltip,group=None): icon=gtk.Image() icon.set_from_file("pixmaps/"+icon_name) label=gtk.Label(""+name+"") label.set_use_markup(True) radiobutton=gtk.RadioButton(group) radiobutton.set_mode(False) radiobutton.set_relief( gtk.RELIEF_NONE ) b_vbox=gtk.VBox() radiobutton.add(b_vbox) b_vbox.pack_start(icon,True,True,2) b_vbox.pack_start(label,True,True,2) self.left_buttons.pack_start(radiobutton,True,True,2) self.buttons[shortname]=radiobutton radiobutton.connect("released",self.show_config_pages,shortname) def show_config_pages(self,obj,name): current_notebook=self.main_hbox.get_children()[1] self.main_hbox.remove(current_notebook) if name=="server": self.main_hbox.pack_start(self.server_page,True,True,4) if name=="user": self.main_hbox.pack_start(self.user_page,True,True,4) if name=="display": self.main_hbox.pack_start(self.display_page,True,True,4) if name=="groups": self.main_hbox.pack_start(self.groups_page,True,True,4) if name=="misc": self.main_hbox.pack_start(self.misc_page,True,True,4) self.main_hbox.show_all() def refresh_server_list(self): cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) self.server_model.clear() for server in cp.sections():self.server_model.append([server]) def refresh_id_list(self): cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","id.txt")) self.id_model.clear() for id in cp.sections():self.id_model.append([id]) def build_server_page(self): notebook=gtk.Notebook() label_server=gtk.Label(""+_("Servers")+"") label_server.set_use_markup(True) server_profile_vbox=gtk.VBox() server_label=gtk.Label(""+_("NNTP Servers")+"") server_label.set_alignment(0,0.5) server_label.set_use_markup(True) server_vbox=gtk.VBox() server_vbox.set_border_width(4) server_table=gtk.Table(5,2,False) server_table.set_border_width(4) server_vbox.pack_start(server_label,True,True) server_vbox.pack_start(server_table,True,True) def add_edit_server(button): if button==edit_button: model,iter_selected= server_list.get_selection().get_selected() if iter_selected: server= self.server_model.get_value(iter_selected,0) win=NNTPServer_Win(self,server) win.show() else: win=NNTPServer_Win(self) win.show() self.refresh_server_list() def remove_server(button): model,iter_selected= server_list.get_selection().get_selected() if iter_selected: server= self.server_model.get_value(iter_selected,0) cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) cp.remove_section(server) cp.write(file(os.path.join(get_wdir(),"dats","servers.txt"),"w")) self.refresh_server_list() def server_list_row_clicked(*params): add_edit_server(edit_button) add_button=gtk.Button(None,gtk.STOCK_ADD) add_button_tooltip=gtk.Tooltips() add_button_tooltip.set_tip(add_button,_("Add a Server")) add_button.connect("clicked",add_edit_server) add_button.set_border_width(5) edit_button=gtk.Button(None,gtk.STOCK_EDIT) edit_button_tooltip=gtk.Tooltips() edit_button_tooltip.set_tip(edit_button,_("Edit Selected Server")) edit_button.connect("clicked",add_edit_server) edit_button.set_border_width(5) remove_button=gtk.Button(None,gtk.STOCK_REMOVE) remove_button_tooltip=gtk.Tooltips() remove_button_tooltip.set_tip(remove_button,_("Remove Selected Server")) remove_button.connect("clicked",remove_server) remove_button.set_border_width(5) server_scrolledwin=gtk.ScrolledWindow() server_scrolledwin.set_border_width(4) server_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) server_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) server_list=gtk.TreeView() server_list.connect("row_activated",server_list_row_clicked) server_list.set_border_width(4) self.server_model=gtk.ListStore(gobject.TYPE_STRING) server_scrolledwin.add(server_list) server_list.set_model(self.server_model) text_renderer=gtk.CellRendererText() server_column=gtk.TreeViewColumn(_("List"),text_renderer,text=0) server_list.append_column(server_column) server_list.set_rules_hint(True) server_list.set_headers_visible(False) self.refresh_server_list() server_table.attach(server_scrolledwin,0,1,0,3,gtk.EXPAND|gtk.FILL,gtk.FILL,18) server_table.attach(add_button,1,2,0,1,gtk.FILL) server_table.attach(edit_button,1,2,1,2,gtk.FILL) server_table.attach(remove_button,1,2,2,3,gtk.FILL) server_profile_vbox.pack_start(server_vbox,True,True) mail_server_label=gtk.Label(""+_("SMTP Server")+"") mail_server_label.set_alignment(0,0.5) mail_server_label.set_use_markup(True) mail_server_vbox=gtk.VBox() mail_server_vbox.set_border_width(4) mail_server_vbox.pack_start(mail_server_label,False,True) mail_server_table=gtk.Table(4,2,False) mail_server_table.set_border_width(8) self.mail_port_entry=gtk.Entry() self.mail_port_entry.set_size_request(30,-1) self.mail_server_entry=gtk.Entry() mail_server_port_hbox=gtk.HBox() mail_server_port_hbox.pack_start(self.mail_server_entry,True,True) mail_server_port_hbox.pack_start(self.mail_port_entry,False,False,4) self.mail_server_username=gtk.Entry() self.mail_server_password=gtk.Entry() self.mail_server_password.set_visibility(False) self.mail_server_auth_checkbutton=gtk.CheckButton(_("Server requires authentication")) self.mail_server_auth_checkbutton.connect("clicked",self.change_mail_auth_status) mail_server_entry_label=gtk.Label(_("SMTP Server Address | Port Number")) mail_server_entry_label.set_size_request(230,-1) mail_server_entry_label.set_alignment(0,0.5) self.mail_username_label=gtk.Label(_("Username")) self.mail_username_label.set_size_request(230,-1) self.mail_username_label.set_alignment(0,0.5) self.mail_password_label=gtk.Label(_("Password")) self.mail_password_label.set_alignment(0,0.5) mail_auth_label=gtk.Label("") mail_server_table.attach(mail_server_port_hbox,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,18) mail_server_table.attach(self.mail_server_auth_checkbutton,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) mail_server_table.attach(self.mail_server_username,0,1,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,18) mail_server_table.attach(self.mail_server_password,0,1,3,4,gtk.EXPAND|gtk.FILL,gtk.FILL,18) mail_server_table.attach(mail_server_entry_label,1,2,0,1,gtk.EXPAND|gtk.FILL) mail_server_table.attach(mail_auth_label,1,2,1,2,gtk.EXPAND|gtk.FILL) mail_server_table.attach(self.mail_username_label,1,2,2,3,gtk.EXPAND|gtk.FILL) mail_server_table.attach(self.mail_password_label,1,2,3,4,gtk.EXPAND|gtk.FILL) mail_server_vbox.pack_start(mail_server_table,False,False) server_profile_vbox.pack_start(mail_server_vbox,True,True) notebook.append_page(server_profile_vbox,label_server) return notebook def build_user_page(self): notebook=gtk.Notebook() label_user=gtk.Label(""+_("User Profile")+"") label_user.set_use_markup(True) def add_edit_id(button): if button==edit_button: model,iter_selected= id_list.get_selection().get_selected() if iter_selected: id= self.id_model.get_value(iter_selected,0) win=ID_Win(self,id) win.show() else: win=ID_Win(self) win.show() self.refresh_id_list() def remove_id(button): model,iter_selected= id_list.get_selection().get_selected() if iter_selected: id= self.id_model.get_value(iter_selected,0) cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","id.txt")) cp.remove_section(id) cp.write(file(os.path.join(get_wdir(),"dats","id.txt"),"w")) self.refresh_id_list() def id_list_row_clicked(*params): add_edit_id(edit_button) add_button=gtk.Button(None,gtk.STOCK_ADD) add_button_tooltip=gtk.Tooltips() add_button_tooltip.set_tip(add_button,_("Add an Identity")) add_button.connect("clicked",add_edit_id) add_button.set_border_width(5) edit_button=gtk.Button(None,gtk.STOCK_EDIT) edit_button_tooltip=gtk.Tooltips() edit_button_tooltip.set_tip(edit_button,_("Edit Selected Identity")) edit_button.connect("clicked",add_edit_id) edit_button.set_border_width(5) remove_button=gtk.Button(None,gtk.STOCK_REMOVE) remove_button_tooltip=gtk.Tooltips() remove_button_tooltip.set_tip(remove_button,_("Remove Selected Identity")) remove_button.connect("clicked",remove_id) remove_button.set_border_width(5) user_profile_vbox=gtk.VBox() user_profile_vbox.set_border_width(4) personal_table=gtk.Table(4,2,False) personal_table.set_border_width(8) id_scrolledwin=gtk.ScrolledWindow() id_scrolledwin.set_border_width(4) id_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) id_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) id_list=gtk.TreeView() id_list.connect("row_activated",id_list_row_clicked) id_list.set_border_width(4) self.id_model=gtk.ListStore(gobject.TYPE_STRING) id_scrolledwin.add(id_list) id_list.set_model(self.id_model) text_renderer=gtk.CellRendererText() id_column=gtk.TreeViewColumn(_("List"),text_renderer,text=0) id_list.append_column(id_column) id_list.set_rules_hint(True) id_list.set_headers_visible(False) self.refresh_id_list() personal_table.attach(id_scrolledwin,0,1,0,3,gtk.EXPAND|gtk.FILL,gtk.FILL,18) personal_table.attach(add_button,1,2,0,1,gtk.FILL) personal_table.attach(edit_button,1,2,1,2,gtk.FILL) personal_table.attach(remove_button,1,2,2,3,gtk.FILL) user_profile_vbox.pack_start(personal_table,False,False) notebook.append_page(user_profile_vbox,label_user) return notebook def build_display_page(self): notebook=gtk.Notebook() label_display_profile=gtk.Label(""+_("Fonts and Colors")+"") label_display_profile.set_use_markup(True) display_profile_vbox=gtk.VBox() display_profile_vbox_2=gtk.VBox() font_vbox=gtk.VBox() font_label=gtk.Label(""+_("Fonts")+"") font_label.set_alignment(0,0.5) font_label.set_use_markup(True) font_vbox.pack_start(font_label,False,False,4) font_vbox.set_border_width(4) self.font_article_hbox=gtk.HBox() self.font_article_hbox.set_border_width(4) font_article_label=gtk.Label(_("Article")) font_article_label.set_size_request(68,-1) font_article_label.set_alignment(0,0.5) self.font_article_hbox.pack_start(font_article_label,False,False,16) self.font_article_button=gtk.FontButton(None) self.font_article_button.set_use_font(True) self.font_article_button.set_use_size(True) self.font_article_hbox.pack_start(self.font_article_button,True,True,0) self.font_threads_hbox=gtk.HBox() self.font_threads_hbox.set_border_width(4) font_threads_label=gtk.Label(_("Threads")) font_threads_label.set_size_request(68,-1) font_threads_label.set_alignment(0,0.5) self.font_threads_hbox.pack_start(font_threads_label,False,False,16) self.font_threads_button=gtk.FontButton(None) self.font_threads_button.set_use_font(True) self.font_threads_button.set_use_size(True) self.font_threads_hbox.pack_start(self.font_threads_button,True,True,0) self.font_groups_hbox=gtk.HBox() self.font_groups_hbox.set_border_width(4) font_groups_label=gtk.Label(_("Groups")) font_groups_label.set_size_request(68,-1) font_groups_label.set_alignment(0,0.5) self.font_groups_hbox.pack_start(font_groups_label,False,False,16) self.font_groups_button=gtk.FontButton(None) self.font_groups_button.set_use_font(True) self.font_groups_button.set_use_size(True) self.font_groups_hbox.pack_start(self.font_groups_button,True,True,0) use_system_fonts_hbox=gtk.HBox() use_system_fonts_hbox.set_border_width(4) self.use_system_fonts_checkbutton=gtk.CheckButton(_("Use System Fonts")) use_system_fonts_hbox.pack_start(self.use_system_fonts_checkbutton,False,False,16) self.use_system_fonts_checkbutton.connect("clicked",self.change_fonts_status) font_vbox.pack_start(use_system_fonts_hbox,False,False) font_vbox.pack_start(self.font_article_hbox,False,False) font_vbox.pack_start(self.font_threads_hbox,False,False) font_vbox.pack_start(self.font_groups_hbox,False,False) colors_vbox=gtk.VBox() colors_label=gtk.Label(""+_("Colors")+"") colors_label.set_alignment(0,0.5) colors_label.set_use_markup(True) colors_vbox.pack_start(colors_label) colors_vbox.set_border_width(4) colors_table=gtk.Table(5,3,False) colors_table.set_border_width(4) text_color_label=gtk.Label(_("Text")) text_color_label.set_alignment(0,0.5) quote1_color_label=gtk.Label(_("Quote Level 1")) quote1_color_label.set_alignment(0,0.5) quote1_color_label.set_size_request(80,-1) quote2_color_label=gtk.Label(_("Quote Level 2")) quote2_color_label.set_alignment(0,0.5) quote3_color_label=gtk.Label(_("Quote Level 3")) quote3_color_label.set_alignment(0,0.5) sign_color_label=gtk.Label(_("Sign")) sign_color_label.set_alignment(0,0.5) background_color_label=gtk.Label(_("Background")) background_color_label.set_alignment(0,0.5) self.background2_color_label=gtk.Label("") url_color_label=gtk.Label(_("URL")) url_color_label.set_alignment(0,0.5) self.text_color_entry=gtk.Entry() self.text_color_entry.set_editable(False) self.quote1_color_entry=gtk.Entry() self.quote1_color_entry.set_editable(False) self.quote2_color_entry=gtk.Entry() self.quote2_color_entry.set_editable(False) self.quote3_color_entry=gtk.Entry() self.quote3_color_entry.set_editable(False) self.sign_color_entry=gtk.Entry() self.sign_color_entry.set_editable(False) self.url_color_entry=gtk.Entry() self.url_color_entry.set_editable(False) self.text_color_button=gtk.ColorButton(gtk.gdk.Color(0,0,0)) self.text_color_button.set_size_request(100,25) self.text_color_button.set_title(_("Select Text Color")) self.text_color_button.connect("color_set",self.update_text_color_entry) self.quote1_color_button=gtk.ColorButton(gtk.gdk.Color(0,0,0)) self.quote1_color_button.set_size_request(100,25) self.quote1_color_button.set_title(_("Select Quote Level 1 Color")) self.quote1_color_button.connect("color_set",self.update_text_color_entry) self.quote2_color_button=gtk.ColorButton(gtk.gdk.Color(0,0,0)) self.quote2_color_button.set_size_request(100,25) self.quote2_color_button.set_title(_("Select Quote Level 2 Color")) self.quote2_color_button.connect("color_set",self.update_text_color_entry) self.quote3_color_button=gtk.ColorButton(gtk.gdk.Color(0,0,0)) self.quote3_color_button.set_size_request(100,25) self.quote3_color_button.set_title(_("Select Quote Level 3 Color")) self.quote3_color_button.connect("color_set",self.update_text_color_entry) self.sign_color_button=gtk.ColorButton(gtk.gdk.Color(0,0,0)) self.sign_color_button.set_size_request(100,25) self.sign_color_button.set_title(_("Select Sign Color")) self.sign_color_button.connect("color_set",self.update_text_color_entry) self.background_color_button=gtk.ColorButton(gtk.gdk.Color(0,0,0)) self.background_color_button.set_size_request(100,25) self.background_color_button.set_title(_("Select Background Color")) self.background_color_button.connect("color_set",self.update_back_color_entry) self.url_color_button=gtk.ColorButton(gtk.gdk.Color(0,0,0)) self.url_color_button.set_size_request(100,25) self.url_color_button.set_title(_("Select URL Color")) self.url_color_button.connect("color_set",self.update_text_color_entry) colors_table.attach(text_color_label,0,1,0,1,gtk.FILL,gtk.FILL,16) colors_table.attach(quote1_color_label,0,1,1,2,gtk.FILL,gtk.FILL,16) colors_table.attach(quote2_color_label,0,1,2,3,gtk.FILL,gtk.FILL,16) colors_table.attach(quote3_color_label,0,1,3,4,gtk.FILL,gtk.FILL,16) colors_table.attach(sign_color_label,0,1,4,5,gtk.FILL,gtk.FILL,16) colors_table.attach(url_color_label,0,1,5,6,gtk.FILL,gtk.FILL,16) colors_table.attach(background_color_label,0,1,6,7,gtk.FILL,gtk.FILL,16) colors_table.attach(self.text_color_entry,1,2,0,1,gtk.EXPAND|gtk.FILL,gtk.SHRINK,2) colors_table.attach(self.quote1_color_entry,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.SHRINK,2) colors_table.attach(self.quote2_color_entry,1,2,2,3,gtk.EXPAND|gtk.FILL,gtk.SHRINK,2) colors_table.attach(self.quote3_color_entry,1,2,3,4,gtk.EXPAND|gtk.FILL,gtk.SHRINK,2) colors_table.attach(self.sign_color_entry,1,2,4,5,gtk.EXPAND|gtk.FILL,gtk.SHRINK,2) colors_table.attach(self.url_color_entry,1,2,5,6,gtk.EXPAND|gtk.FILL,gtk.SHRINK,2) colors_table.attach(self.background2_color_label,1,2,6,7,gtk.EXPAND|gtk.FILL,gtk.SHRINK,2) colors_table.attach(self.text_color_button,2,3,0,1,gtk.EXPAND|gtk.FILL,gtk.SHRINK) colors_table.attach(self.quote1_color_button,2,3,1,2,gtk.EXPAND|gtk.FILL,gtk.SHRINK) colors_table.attach(self.quote2_color_button,2,3,2,3,gtk.EXPAND|gtk.FILL,gtk.SHRINK) colors_table.attach(self.quote3_color_button,2,3,3,4,gtk.EXPAND|gtk.FILL,gtk.SHRINK) colors_table.attach(self.sign_color_button,2,3,4,5,gtk.EXPAND|gtk.FILL,gtk.SHRINK) colors_table.attach(self.url_color_button,2,3,5,6,gtk.EXPAND|gtk.FILL,gtk.SHRINK) colors_table.attach(self.background_color_button,2,3,6,7,gtk.EXPAND|gtk.FILL,gtk.SHRINK) headers_colors_vbox=gtk.VBox() headers_colors_label=gtk.Label(""+_("Headers Colors")+"") headers_colors_label.set_alignment(0,0.5) headers_colors_label.set_use_markup(True) self.headers2_bg_color_label=gtk.Label() headers_colors_vbox.pack_start(headers_colors_label) headers_colors_vbox.set_border_width(4) headers_colors_table=gtk.Table(5,3,False) headers_colors_table.set_border_width(4) self.headers_bg_color_button=gtk.ColorButton(gtk.gdk.Color(0,0,0)) self.headers_bg_color_button.set_size_request(100,25) self.headers_bg_color_button.set_title(_("Select Headers Background Color")) self.headers_bg_color_button.connect("color_set",self.update_back_color_entry) self.headers_fg_color_button=gtk.ColorButton(gtk.gdk.Color(0,0,0)) self.headers_fg_color_button.set_size_request(100,25) self.headers_fg_color_button.set_title(_("Select Headers Foreground Color")) self.headers_fg_color_button.connect("color_set",self.update_text_color_entry) self.headers_color_entry=gtk.Entry() self.headers_color_entry.set_editable(False) headers_fg_color_label=gtk.Label(_("Color")) headers_fg_color_label.set_alignment(0,0.5) headers_fg_color_label.set_size_request(80,-1) headers_bg_color_label=gtk.Label(_("Background")) headers_bg_color_label.set_alignment(0,0.5) headers_colors_table.attach(headers_fg_color_label,0,1,0,1,gtk.FILL,gtk.FILL,16) headers_colors_table.attach(headers_bg_color_label,0,1,1,2,gtk.FILL,gtk.FILL,16) headers_colors_table.attach(self.headers_color_entry,1,2,0,1,gtk.EXPAND|gtk.FILL,gtk.SHRINK,2) headers_colors_table.attach(self.headers2_bg_color_label,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.SHRINK,2) headers_colors_table.attach(self.headers_fg_color_button,2,3,0,1,gtk.EXPAND|gtk.FILL,gtk.SHRINK) headers_colors_table.attach(self.headers_bg_color_button,2,3,1,2,gtk.EXPAND|gtk.FILL,gtk.SHRINK) colors_vbox.pack_start(colors_table,False,False) headers_colors_vbox.pack_start(headers_colors_table,False,False) label_display_profile_2=gtk.Label(""+_("Layout")+"") label_display_profile_2.set_use_markup(True) layout_label=gtk.Label(""+_("Layout")+"") layout_label.set_alignment(0,0.5) layout_label.set_use_markup(True) layout_main_vbox=gtk.VBox() layout_main_vbox.set_border_width(4) layout_main_vbox.pack_start(layout_label,False,False,4) layout_hbox=gtk.HBox() #layouts_vbox=gtk.VBox() layouts_table=gtk.Table(6,4,False) layout_vbox=gtk.VBox() self.layout_radiobuttons=[] for i in range(24): if i == 0: rbutton=gtk.RadioButton() else: rbutton=gtk.RadioButton(self.layout_radiobuttons[0]) layout_image=gtk.Image() layout_image.set_from_file("pixmaps/layout_"+str(i+1)+".xpm") rbutton.add(layout_image) rbutton.connect("clicked",self.update_layout,None,i+1) self.layout_radiobuttons.append(rbutton) r,c=divmod(i,6) layouts_table.attach(rbutton,r,r+1,c,c+1,gtk.FILL,gtk.FILL,12,4) layout_hbox.pack_start(layouts_table,True,False,2) layout_label=gtk.Label(_("G: Groups Pane\n\nH: Headers Pane\n\nA: Article Pane")) layout_hbox.pack_start(layout_label,True,False,4) layout_vbox.pack_start(layout_hbox,True,True,4) layout_main_vbox.pack_start(layout_vbox,False,False,16) art_pane_vbox=gtk.VBox() art_pane_vbox.set_border_width(4) art_pane_label=gtk.Label(""+_("Article Pane")+"") art_pane_label.set_alignment(0,0.5) art_pane_label.set_use_markup(True) art_pane_table=gtk.Table(1,1,False) art_pane_table.set_border_width(4) art_pane_vbox.pack_start(art_pane_label,False,False,4) self.headers_checkbutton=gtk.CheckButton(_("Display Headers in the Article Pane")) self.headers_conf_button=gtk.Button(_("Headers List")) headers_conf_button_tooltip=gtk.Tooltips() headers_conf_button_tooltip.set_tip(self.headers_conf_button,_("XPN will show these headers on the top of the Article Pane")) headers_conf_label=gtk.Label(_("Headers Shown on the Article Pane")) self.headers_conf_button.connect("clicked",self.open_headers_list_win) art_pane_table.attach(self.headers_checkbutton,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) art_pane_table.attach(self.headers_conf_button,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) art_pane_table.attach(headers_conf_label,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL) art_pane_vbox.pack_start(art_pane_table,False,False) thread_pane_vbox=gtk.VBox() thread_pane_vbox.set_border_width(4) thread_pane_label=gtk.Label(""+_("Threads Pane")+"") thread_pane_label.set_alignment(0,0.5) thread_pane_label.set_use_markup(True) thread_pane_table=gtk.Table(1,1,False) thread_pane_table.set_border_width(4) thread_pane_vbox.pack_start(thread_pane_label,False,False,4) thread_pane_label2=gtk.Label(_("Threads expander position")) self.thread_exp_radiobutton1=gtk.RadioButton(None,_("Subject Column")) self.thread_exp_radiobutton2=gtk.RadioButton(self.thread_exp_radiobutton1,_("From Column")) thread_pane_table.attach(self.thread_exp_radiobutton1,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) thread_pane_table.attach(self.thread_exp_radiobutton2,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) thread_pane_table.attach(thread_pane_label2,1,2,0,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) thread_pane_vbox.pack_start(thread_pane_table,False,False) display_profile_vbox.pack_start(font_vbox,False,True) display_profile_vbox.pack_start(colors_vbox,False,True) display_profile_vbox.pack_start(headers_colors_vbox,False,True) display_profile_vbox_2.pack_start(layout_main_vbox,False,False) display_profile_vbox_2.pack_start(art_pane_vbox,False,False) display_profile_vbox_2.pack_start(thread_pane_vbox,False,False) notebook.append_page(display_profile_vbox,label_display_profile) notebook.append_page(display_profile_vbox_2,label_display_profile_2) return notebook def build_groups_page(self): notebook=gtk.Notebook() label_groups_download=gtk.Label(""+_("Download")+"") label_groups_download.set_use_markup(True) label_groups_view=gtk.Label(""+_("Visualization")+"") label_groups_view.set_use_markup(True) label_groups_nav=gtk.Label(""+_("Navigation")+"") label_groups_nav.set_use_markup(True) groups_download_vbox=gtk.VBox() groups_view_vbox=gtk.VBox() groups_nav_vbox=gtk.VBox() purge_main_vbox=gtk.VBox() purge_main_vbox.set_border_width(4) purge_main_label=gtk.Label(""+_("Purge Options")+"") purge_main_label.set_alignment(0,0.5) purge_main_label.set_use_markup(True) purge_main_vbox.pack_start(purge_main_label,False,False,4) purge_table=gtk.Table(2,2,False) purge_table.set_border_width(4) self.purge_read_spinbutton=gtk.SpinButton(gtk.Adjustment(value=5,lower=0,upper=1000,step_incr=1,page_incr=10)) purge_read_tooltip=gtk.Tooltips() purge_read_tooltip.set_tip(self.purge_read_spinbutton,_("Number of days. '0' means never purge read articles")) purge_read_label=gtk.Label(_("Purge read articles after (days)")) purge_read_label.set_alignment(0,0.5) self.purge_unread_spinbutton=gtk.SpinButton(gtk.Adjustment(value=10,lower=0,upper=1000,step_incr=1,page_incr=10)) purge_unread_tooltip=gtk.Tooltips() purge_unread_tooltip.set_tip(self.purge_unread_spinbutton,_("Number of days. '0' means never purge unread articles")) purge_unread_label=gtk.Label(_("Purge unread articles after (days)")) purge_unread_label.set_alignment(0,0.5) purge_table.attach(self.purge_read_spinbutton,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) purge_table.attach(purge_read_label,1,2,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,2) purge_table.attach(self.purge_unread_spinbutton,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) purge_table.attach(purge_unread_label,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,2) purge_main_vbox.pack_start(purge_table,False,False,4) groups_download_vbox.pack_start(purge_main_vbox,False,True,2) articles_vbox=gtk.VBox() articles_vbox.set_border_width(4) articles_label=gtk.Label(""+_("Articles")+"") articles_label.set_alignment(0,0.5) articles_label.set_use_markup(True) articles_vbox.pack_start(articles_label,False,False,4) articles_table=gtk.Table(1,1,False) self.download_bodies_checkbutton=gtk.CheckButton(_("Retrieve Bodies for all new articles")) self.limit_articles_checkbutton=gtk.CheckButton(_("Limit the number of articles to download")) self.limit_articles_spinbutton=gtk.SpinButton(gtk.Adjustment(value=500,lower=1,upper=100000,step_incr=1,page_incr=10)) limit_articles_label=gtk.Label(_("Max number of articles to download")) self.limit_articles_checkbutton.connect("clicked",self.change_limit_status) articles_table.attach(self.download_bodies_checkbutton,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) articles_table.attach(self.limit_articles_checkbutton,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) articles_table.attach(self.limit_articles_spinbutton,0,1,2,3,gtk.FILL,gtk.FILL,16,2) articles_table.attach(limit_articles_label,1,2,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL) articles_vbox.pack_start(articles_table,False,False) groups_download_vbox.pack_start(articles_vbox,False,True,4) auto_download_vbox=gtk.VBox() auto_download_vbox.set_border_width(4) auto_download_label=gtk.Label(""+_("Automatic Header Download")+"") auto_download_label.set_alignment(0,0.5) auto_download_label.set_use_markup(True) auto_download_vbox.pack_start(auto_download_label,False,False,4) auto_download_table=gtk.Table(1,1,False) self.auto_download_checkbutton=gtk.CheckButton(_("Download Headers automatically")) self.auto_download_spinbutton=gtk.SpinButton(gtk.Adjustment(value=30,lower=5,upper=100000,step_incr=1,page_incr=10)) timeout_label=gtk.Label(_("Minutes Between Downloads")) self.auto_download_checkbutton.connect("clicked",self.change_auto_download_status) auto_download_table.attach(self.auto_download_checkbutton,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) auto_download_table.attach(self.auto_download_spinbutton,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) auto_download_table.attach(timeout_label,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL) auto_download_vbox.pack_start(auto_download_table,False,False) groups_download_vbox.pack_start(auto_download_vbox,False,False,4) sort_main_vbox=gtk.VBox() sort_main_vbox.set_border_width(4) sort_main_label=gtk.Label(""+_("Sorting Options")+"") sort_main_label.set_alignment(0,0.5) sort_main_label.set_use_markup(True) sort_main_vbox.pack_start(sort_main_label,False,False,4) sort_table=gtk.Table(2,2,False) sort_table.set_border_width(4) self.sort_order_checkbutton=gtk.CheckButton(_("Ascending Order")) sort_label=gtk.Label(_("Sorting Column")) sort_label.set_alignment(0,0.5) self.sort_combo=gtk.combo_box_entry_new_text() self.sort_combo.child.set_editable(False) self.sort_combo.set_size_request(130,-1) sort_columns=[_("Subject"),_("From"),_("Date"),_("Score")] for column in sort_columns: self.sort_combo.append_text(column) sort_table.attach(self.sort_order_checkbutton,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) sort_table.attach(self.sort_combo,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) sort_table.attach(sort_label,1,2,1,2,gtk.EXPAND|gtk.FILL,2) sort_main_vbox.pack_start(sort_table,False,False) groups_view_vbox.pack_start(sort_main_vbox,False,True) charset_vbox=gtk.VBox() charset_vbox.set_border_width(4) charset_label=gtk.Label(""+_("Charsets")+"") charset_label.set_alignment(0,0.5) charset_label.set_use_markup(True) charset_vbox.pack_start(charset_label,False,False,4) charset_table=gtk.Table(2,2,False) charset_table.set_border_width(4) fallback_charset_label=gtk.Label(_("Fallback Charset (Reading)")) fallback_charset_label.set_alignment(0,0.5) self.fallback_charset_combo=gtk.combo_box_entry_new_text() self.fallback_charset_combo.set_size_request(130,-1) for encoding in encodings_list: self.fallback_charset_combo.append_text(encoding) fallback_charset_tooltip=gtk.Tooltips() fallback_charset_tooltip.set_tip(self.fallback_charset_combo.child,encodings_tip) self.fallback_charset_combo.child.set_editable(False) self.charset_list_button=gtk.Button(_("Charsets List")) self.charset_list_button.connect("clicked",self.open_charset_list_win) self.charset_list_button.set_size_request(130,-1) charset_list_tooltip=gtk.Tooltips() charset_list_tooltip.set_tip(self.charset_list_button,_("XPN will try to use the charsets in this order")) charset_list_label=gtk.Label(_("Ordered List (Writing)")) charset_list_label.set_alignment(0,0.5) charset_table.attach(self.fallback_charset_combo,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) charset_table.attach(fallback_charset_label,1,2,0,1,gtk.EXPAND|gtk.FILL,2) charset_table.attach(self.charset_list_button,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) charset_table.attach(charset_list_label,1,2,1,2,gtk.EXPAND|gtk.FILL,2) charset_vbox.pack_start(charset_table,True,False,4) groups_view_vbox.pack_start(charset_vbox,False,True,2) threading_vbox=gtk.VBox() threading_vbox.set_border_width(4) threading_label=gtk.Label(""+_("Threading Method")+"") threading_label.set_alignment(0,0.5) threading_label.set_use_markup(True) threading_vbox.pack_start(threading_label,False,False,4) threading_table=gtk.Table(1,1,False) threading_table.set_border_width(4) self.threading_method_radiobutton1=gtk.RadioButton(None,_("Fast (but imprecise) old Algorithm")) self.threading_method_radiobutton2=gtk.RadioButton(self.threading_method_radiobutton1,_("Slow (but precise) new Algorithm")) threading_table.attach(self.threading_method_radiobutton1,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) threading_table.attach(self.threading_method_radiobutton2,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) threading_vbox.pack_start(threading_table,True,False,4) groups_view_vbox.pack_start(threading_vbox,False,True,2) main_nav_vbox=gtk.VBox() main_nav_vbox.set_border_width(4) misc_main_label=gtk.Label(""+_("Miscellaneous")+"") misc_main_label.set_alignment(0,0.5) misc_main_label.set_use_markup(True) main_nav_vbox.pack_start(misc_main_label,False,False,4) misc_table=gtk.Table(5,2,False) misc_table.set_border_width(4) self.advance_on_mark_checkbutton=gtk.CheckButton(_("Advance to the Next Article on Mark")) self.oneclick_checkbutton=gtk.CheckButton(_("One Click Enter Group")) self.oneclick_article_checkbutton=gtk.CheckButton(_("One Click Enter Article")) self.expand_groups_checkbutton=gtk.CheckButton(_("Expand Group on Entering")) one_key_label=gtk.Label(_("Scroll Text (% of page)")) one_key_label.set_size_request(200,-1) one_key_label.set_alignment(0,0.5) self.one_key_spin=gtk.SpinButton(gtk.Adjustment(value=50,lower=1,upper=100,step_incr=1,page_incr=10)) misc_table.attach(self.advance_on_mark_checkbutton,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) misc_table.attach(self.oneclick_checkbutton,0,1,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) misc_table.attach(self.oneclick_article_checkbutton,0,1,3,4,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) misc_table.attach(self.expand_groups_checkbutton,0,1,4,5,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) misc_table.attach(self.one_key_spin,0,1,5,6,gtk.FILL,gtk.FILL,16,2) misc_table.attach(one_key_label,1,2,5,6,gtk.EXPAND|gtk.FILL,gtk.FILL,2) main_nav_vbox.pack_start(misc_table,False,False) groups_nav_vbox.pack_start(main_nav_vbox,False,True,2) notebook.append_page(groups_download_vbox,label_groups_download) notebook.append_page(groups_view_vbox,label_groups_view) notebook.append_page(groups_nav_vbox,label_groups_nav) return notebook def build_misc_page(self): notebook=gtk.Notebook() label_misc=gtk.Label(""+_("External Apps")+"") label_misc.set_use_markup(True) label_misc_2=gtk.Label(""+_("Miscellaneous")+"") label_misc_2.set_use_markup(True) miscellaneous_vbox=gtk.VBox() miscellaneous_vbox_2=gtk.VBox() browser_table=gtk.Table() browser_table.set_border_width(4) browser_main_vbox=gtk.VBox() browser_main_vbox.set_border_width(4) browser_main_label=gtk.Label(""+_("Web Browser")+"") browser_main_label.set_alignment(0,0.5) browser_main_label.set_use_markup(True) browser_main_vbox.pack_start(browser_main_label,False,False,4) self.browser_checkbutton=gtk.CheckButton(_("Use Custom Web Browser Launcher")) self.browser_checkbutton.connect("clicked",self.change_browser_status) self.browser_entry=gtk.Entry() browser_tooltip=gtk.Tooltips() browser_tooltip.set_tip(self.browser_entry,_("Type your custom command, %s represents the url.\nExamples:\n\nmozilla %s &\nxterm -e links %s")) self.browser_label=gtk.Label(_("Web Browser Launcher")) self.browser_label.set_alignment(0,0.5) browser_table.attach(self.browser_checkbutton,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) browser_table.attach(self.browser_entry,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) browser_table.attach(self.browser_label,1,2,1,2,gtk.EXPAND|gtk.FILL,2) browser_main_vbox.pack_start(browser_table,False,False) editor_table=gtk.Table() editor_table.set_border_width(4) editor_main_vbox=gtk.VBox() editor_main_vbox.set_border_width(4) editor_main_label=gtk.Label(""+_("External Editor")+"") editor_main_label.set_alignment(0,0.5) editor_main_label.set_use_markup(True) editor_main_vbox.pack_start(editor_main_label,False,False,4) self.editor_checkbutton=gtk.CheckButton(_("Always Use External Editor")) self.editor_entry=gtk.Entry() editor_tooltip=gtk.Tooltips() editor_tooltip.set_tip(self.editor_entry,_("""Type the editor launcher, %s represents the filename.\nExamples:\n\nxterm -e vim %s\ngvim -f %s\nnotepad.exe %s\n"C:\Program Files\Notepad++\Notepad++.exe" %s -nosession\n\nNOTE: This feature works only with *Nix and Windows systems""")) editor_label=gtk.Label(_("External Editor Command")) editor_label.set_alignment(0,0.5) editor_table.attach(self.editor_checkbutton,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) editor_table.attach(self.editor_entry,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,2) editor_table.attach(editor_label,1,2,1,2,gtk.EXPAND|gtk.FILL,2) editor_main_vbox.pack_start(editor_table,False,False) lang_vbox=gtk.VBox() lang_vbox.set_border_width(4) lang_vbox_label=gtk.Label(""+_("Language")+"") lang_vbox_label.set_alignment(0,0.5) lang_vbox_label.set_use_markup(True) lang_vbox.pack_start(lang_vbox_label,False,False,4) lang_hbox=gtk.HBox() langs_vbox=gtk.VBox() self.lang_en_radiobutton=gtk.RadioButton() lang_en_hbox=gtk.HBox() lang_en_label=gtk.Label(_("English")) lang_en_image=gtk.Image() lang_en_image.set_from_file("pixmaps/en.xpm") lang_en_hbox.pack_start(lang_en_image,True,True,2) lang_en_hbox.pack_start(lang_en_label,True,True,4) self.lang_en_radiobutton.add(lang_en_hbox) self.lang_it_radiobutton=gtk.RadioButton(self.lang_en_radiobutton) lang_it_hbox=gtk.HBox() lang_it_label=gtk.Label(_("Italian")) lang_it_image=gtk.Image() lang_it_image.set_from_file("pixmaps/it.xpm") lang_it_hbox.pack_start(lang_it_image,True,True,2) lang_it_hbox.pack_start(lang_it_label,True,True,4) self.lang_it_radiobutton.add(lang_it_hbox) self.lang_fr_radiobutton=gtk.RadioButton(self.lang_en_radiobutton) lang_fr_hbox=gtk.HBox() lang_fr_label=gtk.Label(_("French")) lang_fr_image=gtk.Image() lang_fr_image.set_from_file("pixmaps/fr.xpm") lang_fr_hbox.pack_start(lang_fr_image,True,True,2) lang_fr_hbox.pack_start(lang_fr_label,True,True,4) self.lang_fr_radiobutton.add(lang_fr_hbox) self.lang_de_radiobutton=gtk.RadioButton(self.lang_en_radiobutton) lang_de_hbox=gtk.HBox() lang_de_label=gtk.Label(_("German")) lang_de_image=gtk.Image() lang_de_image.set_from_file("pixmaps/de.xpm") lang_de_hbox.pack_start(lang_de_image,True,True,2) lang_de_hbox.pack_start(lang_de_label,True,True,4) self.lang_de_radiobutton.add(lang_de_hbox) langs_vbox.pack_start(self.lang_en_radiobutton,True,True,2) langs_vbox.pack_start(self.lang_it_radiobutton,True,True,2) langs_vbox.pack_start(self.lang_fr_radiobutton,True,True,2) langs_vbox.pack_start(self.lang_de_radiobutton,True,True,2) lang_hbox.pack_start(langs_vbox,True,False,2) lang_label=gtk.Label(_("You must restart XPN in order\n to get the translation active")) lang_hbox.pack_start(lang_label,True,False,4) lang_vbox.pack_start(lang_hbox,False,False) miscellaneous_vbox.pack_start(browser_main_vbox,False,True,2) miscellaneous_vbox.pack_start(editor_main_vbox,False,True,2) miscellaneous_vbox_2.pack_start(lang_vbox,False,True,2) notebook.append_page(miscellaneous_vbox,label_misc) notebook.append_page(miscellaneous_vbox_2,label_misc_2) return notebook def __init__(self,conf,main_win): self.configs=conf.get_configs() self.main_win=main_win self.win=gtk.Window(gtk.WINDOW_TOPLEVEL) self.win.connect("delete_event",self.delete_event) self.win.set_title(_("XPN Preferences")) self.win.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/conf.xpm")) self.win.set_default_size(470,400) self.win.set_position(gtk.WIN_POS_CENTER) self.tips=gtk.Tooltips() #main_vbox self.main_vbox=gtk.VBox() self.win.add(self.main_vbox) #main_hbox self.main_hbox=gtk.HBox() self.evbox=gtk.EventBox() self.left_buttons=gtk.VButtonBox() self.left_buttons.set_layout(gtk.BUTTONBOX_EDGE) self.evbox.add(self.left_buttons) style = self.evbox.get_style() bgcolor = gtk.gdk.Color( 65535, 65535, 65535 ) self.evbox.modify_bg( gtk.STATE_NORMAL, bgcolor ) self.buttons={} self.insert_rb(_("Server"),"config-servers.png","server",_("Configure Server Profiles")) self.insert_rb(_("User"),"config-users.png","user",_("Configure User Profile"),self.buttons["server"]) self.insert_rb(_("Display"),"config-display.png","display",_("Configure Display Profile"),self.buttons["server"]) #self.insert_rb(_("Posting"),"config-posting.png","posting",_("Configure Posting Profile"),self.buttons["server"]) self.insert_rb(_("Groups"),"config-groups.png","groups",_("Configure Group Properties"),self.buttons["server"]) self.insert_rb(_("Misc"),"config-misc.png","misc",_("Configure Miscellaneous Properties"),self.buttons["server"]) self.main_hbox.pack_start(self.evbox,False,False,4) self.main_vbox.pack_start(self.main_hbox,True,True,4) self.server_page=self.build_server_page() self.user_page=self.build_user_page() self.display_page=self.build_display_page() # self.posting_page=self.build_posting_page() self.groups_page=self.build_groups_page() self.misc_page=self.build_misc_page() self.main_hbox.pack_start(self.server_page,False,False) #self.show_config_pages(None,"Server") #buttons hbox self.buttons_hbox=gtk.HBox() self.main_vbox.pack_start(self.buttons_hbox,False,False,0) #cancel_button self.cancel_button=gtk.Button(None,gtk.STOCK_CANCEL) self.cancel_button_tooltip=gtk.Tooltips() self.cancel_button_tooltip.set_tip(self.cancel_button,_("Close window. Discard changes")) self.cancel_button.connect("clicked",self.destroy) self.buttons_hbox.pack_start(self.cancel_button,True,True,0) #ok_button self.ok_button=gtk.Button(None,gtk.STOCK_OK) self.ok_button.connect("clicked",self.save_configs,conf) self.ok_button_tooltip=gtk.Tooltips() self.ok_button_tooltip.set_tip(self.ok_button,_("Close window and save settings")) self.buttons_hbox.pack_start(self.ok_button,True,True,0) self.ok_button.set_border_width(5) self.cancel_button.set_border_width(5) self.update_all(self.configs) xpn-1.2.6/xpn_src/Server_Win.py0000644000175000017500000001523211141275756014600 0ustar antantimport gtk import ConfigParser import os from xpn_src.UserDir import get_wdir from xpn_src.Dialogs import Dialog_OK class NNTPServer_Win: def show(self): self.win.show_all() def delete_event(self,widget,event,data=None): return False def destroy(self,obj): self.win.destroy() def change_auth_status(self,obj): status=self.server_auth_checkbutton.get_active() self.server_username.set_sensitive(status) self.server_password.set_sensitive(status) self.username_label.set_sensitive(status) self.password_label.set_sensitive(status) def change_ssl_status(self,checkbutton): status=checkbutton.get_active() if status: self.port_entry.set_text("563") else: self.port_entry.set_text("119") def save_configs(self,button): cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) server_name=self.server_entry.get_text() if server_name!="": try: cp.add_section(server_name) except: pass cp.set(server_name,"server",server_name) cp.set(server_name,"port",self.port_entry.get_text()) cp.set(server_name,"nntp_use_ssl",str(self.server_use_ssl_checkbutton.get_active())) if self.server_auth_checkbutton.get_active(): cp.set(server_name,"auth","True") cp.set(server_name,"username",self.server_username.get_text()) cp.set(server_name,"password",self.server_password.get_text()) else: cp.set(server_name,"auth","False") cp.set(server_name,"username","") cp.set(server_name,"password","") cp.write(file(os.path.join(get_wdir(),"dats","servers.txt"),"w")) self.win.destroy() self.config_win.refresh_server_list() else: d=Dialog_OK(_("Please set the Server Name")) def load_configs(self,server_to_load): cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) self.server_entry.set_text(cp.get(server_to_load,"server")) self.port_entry.set_text(cp.get(server_to_load,"port")) if cp.get(server_to_load,"nntp_use_ssl")=="True": self.server_use_ssl_checkbutton.set_active(True) else: self.server_use_ssl_checkbutton.set_active(False) if cp.get(server_to_load,"auth")=="True": self.server_auth_checkbutton.set_active(True) else: self.server_auth_checkbutton.set_active(False) self.server_username.set_sensitive(False) self.server_password.set_sensitive(False) self.username_label.set_sensitive(False) self.password_label.set_sensitive(False) self.server_username.set_text(cp.get(server_to_load,"username")) self.server_password.set_text(cp.get(server_to_load,"password")) def __init__(self,config_win,server_to_load=None): self.config_win=config_win self.win=gtk.Window(gtk.WINDOW_TOPLEVEL) self.win.connect("delete_event",self.delete_event) self.win.set_title(_("Server Settings")) self.win.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/conf.xpm")) self.win.set_position(gtk.WIN_POS_CENTER) server_label=gtk.Label(""+_("NNTP Server")+"") server_label.set_alignment(0,0.5) server_label.set_use_markup(True) server_vbox=gtk.VBox() server_vbox.set_border_width(4) server_vbox.pack_start(server_label,False,True,4) server_table=gtk.Table(4,2,False) server_table.set_border_width(8) self.server_entry=gtk.Entry() self.port_entry=gtk.Entry() self.port_entry.set_text("119") self.server_username=gtk.Entry() self.server_password=gtk.Entry() self.server_password.set_visibility(False) self.server_auth_checkbutton=gtk.CheckButton(_("Server requires authentication")) self.server_auth_checkbutton.connect("clicked",self.change_auth_status) self.server_use_ssl_checkbutton=gtk.CheckButton(_("Use SSL (Secure Socket Layer)")) self.server_use_ssl_checkbutton.connect("clicked",self.change_ssl_status) try: from socket import ssl except: self.server_use_ssl_checkbutton.set_sensitive(False) address_label=gtk.Label(_("NNTP Server Address")) port_label=gtk.Label(_("Port Number")) address_label.set_alignment(0,0.5) port_label.set_alignment(0,0.5) self.username_label=gtk.Label(_("Username")) self.username_label.set_alignment(0,0.5) self.password_label=gtk.Label(_("Password")) self.password_label.set_alignment(0,0.5) server_table.attach(address_label,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,18) server_table.attach(port_label,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,18) server_table.attach(self.username_label,0,1,4,5,gtk.EXPAND|gtk.FILL,gtk.FILL,18) server_table.attach(self.password_label,0,1,5,6,gtk.EXPAND|gtk.FILL,gtk.FILL,18) server_table.attach(self.server_entry,1,2,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL) server_table.attach(self.port_entry,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL) server_table.attach(self.server_use_ssl_checkbutton,1,2,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL) server_table.attach(self.server_auth_checkbutton,1,2,3,4,gtk.EXPAND|gtk.FILL,gtk.FILL) server_table.attach(self.server_username,1,2,4,5,gtk.EXPAND|gtk.FILL,gtk.FILL) server_table.attach(self.server_password,1,2,5,6,gtk.EXPAND|gtk.FILL,gtk.FILL) self.change_auth_status(None) #buttons hbox buttons_hbox=gtk.HBox() #cancel_button self.cancel_button=gtk.Button(None,gtk.STOCK_CANCEL) self.cancel_button_tooltip=gtk.Tooltips() self.cancel_button_tooltip.set_tip(self.cancel_button,_("Close window. Discard changes")) self.cancel_button.connect("clicked",self.destroy) buttons_hbox.pack_start(self.cancel_button,True,True,0) #ok_button self.ok_button=gtk.Button(None,gtk.STOCK_OK) self.ok_button.connect("clicked",self.save_configs) self.ok_button_tooltip=gtk.Tooltips() self.ok_button_tooltip.set_tip(self.ok_button,_("Close window and save settings")) buttons_hbox.pack_start(self.ok_button,True,True,0) self.ok_button.set_border_width(5) self.cancel_button.set_border_width(5) server_vbox.pack_start(server_table,False,False) server_vbox.pack_start(buttons_hbox,False,False,0) self.win.add(server_vbox) if server_to_load: self.load_configs(server_to_load) xpn-1.2.6/xpn_src/Find_Win.py0000700000175000017500000005667211141275756014220 0ustar antantimport gtk import re from xpn_src.Article import Article import cPickle import os import glob from xpn_src.UserDir import get_wdir from xpn_src.Articles_DB import Articles_DB class Find_Win: def delete_event(self,widget,event,data=None): return False def destroy(self,widget): self.window.destroy() def show(self): self.window.show_all() def is_match(self,non_empty,article,rule,match_rule,from_string,subj_string,msgid_string,ref_string,body_string): found_vet=[] if 0 in non_empty: if match_rule(article.from_name,from_string): found_vet.append(True) else: found_vet.append(False) if 1 in non_empty: if match_rule(article.subj,subj_string): found_vet.append(True) else: found_vet.append(False) if 2 in non_empty: if match_rule(article.msgid,msgid_string): found_vet.append(True) else: found_vet.append(False) if 3 in non_empty: if match_rule(article.ref,ref_string): found_vet.append(True) else: found_vet.append(False) if 4 in non_empty: body=article.get_body() if body!=None: body=" ".join(body) if match_rule(body,body_string): found_vet.append(True) else: found_vet.append(False) else: found_vet.append(False) if rule=="And": found=reduce(lambda x,y: x and y, found_vet,True) else: found=reduce(lambda x,y: x or y, found_vet,False) return found def next_match(self,obj): non_empty=[] from_string=self.entry_from.get_text().decode("utf-8") if from_string!="": non_empty.append(0) subj_string=self.entry_subject.get_text().decode("utf-8") if subj_string!="": non_empty.append(1) msgid_string=self.entry_msgid.get_text().decode("utf-8") if msgid_string!="": non_empty.append(2) ref_string=self.entry_ref.get_text().decode("utf-8") if ref_string!="": non_empty.append(3) body_string=self.entry_body.get_text().decode("utf-8") if body_string!="": non_empty.append(4) rule=["And","Or"][self.opt_menu.get_active()] case_insensitive=self.checkbutton_case.get_active() use_regex=self.checkbutton_regex.get_active() start_beginning=self.checkbutton_start.get_active() def match_re_case_ins(field,regex): try: match_rule=re.compile(regex,re.UNICODE|re.IGNORECASE).findall(field) except: match_rule=False return match_rule def match_re_case_sens(field,regex): try: match_rule=re.compile(regex,re.UNICODE).findall(field) except: match_rule=False return match_rule #select the correct function if use_regex: if case_insensitive: match_rule=lambda field,regex: match_re_case_ins(field,regex) else: match_rule=lambda field,regex: match_re_case_sens(field,regex) else: if case_insensitive: match_rule=lambda field,word: field.lower().find(word.lower())+1 else: match_rule=lambda field,word: field.find(word)+1 #select the iter treesel=self.main_win.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() column=self.main_win.threads_pane.threads_tree.get_column(0) found=False if iter_selected==None or start_beginning: iter_selected=model.get_iter_first() if iter_selected!=None: article=self.main_win.threads_pane.get_article(model,iter_selected) found=self.is_match(non_empty,article,rule,match_rule,from_string,subj_string,msgid_string,ref_string,body_string) #begin the loop while (not found) and (iter_selected!=None): iter_selected=self.main_win.threads_pane.find_next_row(model,iter_selected) if iter_selected!=None: article=self.main_win.threads_pane.get_article(model,iter_selected) found=self.is_match(non_empty,article,rule,match_rule,from_string,subj_string,msgid_string,ref_string,body_string) else: found=False if found: path=model.get_path(iter_selected) root_path=[] root_path.append(path[0]) root_path=tuple(root_path) self.main_win.threads_pane.threads_tree.expand_row(root_path,True) self.main_win.threads_pane.threads_tree.grab_focus() self.main_win.threads_pane.threads_tree.scroll_to_cell(path,None,True,0.4,0.0) self.main_win.threads_pane.threads_tree.set_cursor(path,None,False) self.main_win.threads_pane.threads_tree.row_activated(path,column) self.checkbutton_start.set_active(False) def __init__(self,main_win): self.main_win=main_win self.window=gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event",self.delete_event) self.window.connect("destroy",self.destroy) self.window.set_title(_("Find Article")) self.window.set_position(gtk.WIN_POS_CENTER) self.window.set_default_size(350,300) self.window.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/find.xpm")) vbox=gtk.VBox() vbox.set_border_width(8) label_from=gtk.Label(_("From")) label_from.set_use_markup(True) label_from.set_alignment(0,0.5) label_subject=gtk.Label(_("Subject")) label_subject.set_use_markup(True) label_subject.set_alignment(0,0.5) label_msgid=gtk.Label(_("Message-ID")) label_msgid.set_use_markup(True) label_msgid.set_alignment(0,0.5) label_ref=gtk.Label(_("References")) label_ref.set_use_markup(True) label_ref.set_alignment(0,0.5) label_body=gtk.Label(_("Body")) label_body.set_use_markup(True) label_body.set_alignment(0,0.5) self.entry_from=gtk.Entry() self.entry_subject=gtk.Entry() self.entry_msgid=gtk.Entry() self.entry_ref=gtk.Entry() self.entry_body=gtk.Entry() fields_label=gtk.Label(""+_("Fields")+"") fields_label.set_alignment(0,0.5) fields_label.set_use_markup(True) fields_vbox=gtk.VBox() fields_vbox.set_border_width(4) fields_vbox.pack_start(fields_label,False,False,4) find_table=gtk.Table(6,2,False) find_table.set_border_width(4) find_table.attach(label_from,0,1,0,1,gtk.FILL,gtk.FILL,16,4) find_table.attach(label_subject,0,1,1,2,gtk.FILL,gtk.FILL,16,4) find_table.attach(label_msgid,0,1,2,3,gtk.FILL,gtk.FILL,16,4) find_table.attach(label_ref,0,1,4,5,gtk.FILL,gtk.FILL,16,4) find_table.attach(label_body,0,1,5,6,gtk.FILL,gtk.FILL,16,4) find_table.attach(self.entry_from,1,2,0,1,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,4) find_table.attach(self.entry_subject,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,4) find_table.attach(self.entry_msgid,1,2,2,3,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,4) find_table.attach(self.entry_ref,1,2,4,5,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,4) find_table.attach(self.entry_body,1,2,5,6,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,4) fields_vbox.pack_start(find_table,True,True,4) vbox.pack_start(fields_vbox,True,False,2) rule_table=gtk.Table(4,1,False) rule_table.set_border_width(4) hbox=gtk.HBox() self.checkbutton_start=gtk.CheckButton(_("Start from the Beginning")) self.checkbutton_regex=gtk.CheckButton(_("Use Regular Expression")) self.checkbutton_case=gtk.CheckButton(_("Case Insensitive")) label=gtk.Label(_("Rule used to combine search results")) self.opt_menu=gtk.combo_box_new_text() self.opt_menu.append_text(_("AND")) self.opt_menu.append_text(_("OR")) self.opt_menu.set_active(0) rule_table.attach(self.checkbutton_start,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,4) rule_table.attach(self.checkbutton_regex,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,4) rule_table.attach(self.checkbutton_case,0,1,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,16,4) hbox.pack_start(self.opt_menu,False,True,2) hbox.pack_start(label,False,True) rule_table.attach(hbox,0,1,3,4,gtk.EXPAND|gtk.FILL,gtk.FILL,16,4) rule_label=gtk.Label(""+_("Rules")+"") rule_label.set_alignment(0,0.5) rule_label.set_use_markup(True) rule_vbox=gtk.VBox() rule_vbox.pack_start(rule_label,False,False,4) rule_vbox.set_border_width(4) rule_vbox.pack_start(rule_table,True,True,4) vbox.add(rule_vbox) hbox_buttons=gtk.HBox() hbox_buttons.set_border_width(8) self.button_close=gtk.Button(None,gtk.STOCK_CLOSE) self.button_close.connect("clicked",self.destroy) self.button_next=gtk.Button(None,gtk.STOCK_GO_FORWARD) self.button_next.connect("clicked",self.next_match) hbox_buttons.pack_start(self.button_close,True,True,2) hbox_buttons.pack_start(self.button_next,True,True,2) vbox.pack_start(hbox_buttons,True,False,6) self.window.add(vbox) class Search_Win: def delete_event(self,widget,event,data=None): return False def destroy(self,widget): self.window.destroy() def show(self): self.window.show_all() def next_match(self,obj): text=self.entry_text.get_text().decode("utf-8") case_insensitive=self.checkbutton_case.get_active() use_regex=self.checkbutton_regex.get_active() start_beginning=self.checkbutton_start.get_active() def match_re_case_ins(field,regex): try: match_rule=re.compile(regex,re.UNICODE|re.IGNORECASE).search(field) except: match_rule=False return match_rule def match_re_case_sens(field,regex): try: match_rule=re.compile(regex,re.UNICODE).search(field) except: match_rule=False return match_rule if use_regex: if case_insensitive: #match_rule=lambda field,regex: re.compile(regex,re.UNICODE|re.IGNORECASE).search(field) match_rule=lambda field,regex: match_re_case_ins(field,regex) else: #match_rule=lambda field,regex: re.compile(regex,re.UNICODE).search(field) match_rule=lambda field,regex: match_re_case_sens(field,regex) else: if case_insensitive: match_rule=lambda field,word: field.lower().find(word.lower())+1 else: match_rule=lambda field,word: field.find(word)+1 if text!="": start,end=self.main_win.article_pane.buffer.get_bounds() sel_bounds=self.main_win.article_pane.buffer.get_selection_bounds() line_number=0 char_offset=0 if sel_bounds: #There is selected text, let's start after it start=sel_bounds[1] line_number=start.get_line() char_offset=start.get_line_offset() if start_beginning: start,end=self.main_win.article_pane.buffer.get_bounds() line_number=0 char_offset=0 body=self.main_win.article_pane.buffer.get_text(start,end,True).decode("utf-8").split("\n") success=False for line in body: pos=match_rule(line,text) if pos: if use_regex: start=pos.start() end=pos.end() else: start=pos-1 end=pos+len(text)-1 iter_start=self.main_win.article_pane.buffer.get_start_iter() iter_start.set_line(line_number) iter_stop=iter_start.copy() iter_start.set_line_offset(start+char_offset) iter_stop.set_line_offset(end+char_offset) match=self.main_win.article_pane.buffer.get_text(iter_start,iter_stop,True) success=True break line_number=line_number+1 char_offset=0 if success: self.main_win.article_pane.buffer.move_mark_by_name("insert",iter_start) self.main_win.article_pane.buffer.move_mark_by_name("selection_bound",iter_stop) self.checkbutton_start.set_active(False) self.main_win.article_pane.textview.scroll_to_iter(iter_start,0.3) def __init__(self,main_win): self.main_win=main_win self.window=gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event",self.delete_event) self.window.connect("destroy",self.destroy) self.window.set_title(_("Search in the Body")) self.window.set_position(gtk.WIN_POS_CENTER) self.window.set_default_size(350,150) self.window.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/search.xpm")) vbox=gtk.VBox() vbox.set_border_width(8) text_label=gtk.Label(_("Text or Regular Expression")) self.entry_text=gtk.Entry() vbox.pack_start(text_label,True,False,2) vbox.pack_start(self.entry_text,True,False,2) self.checkbutton_start=gtk.CheckButton(_("Start from the Beginning")) self.checkbutton_regex=gtk.CheckButton(_("Use Regular Expression")) self.checkbutton_case=gtk.CheckButton(_("Case Insensitive")) vbox.pack_start(self.checkbutton_start,True,False,4) vbox.pack_start(self.checkbutton_regex,True,False,4) vbox.pack_start(self.checkbutton_case,True,False,4) hbox_buttons=gtk.HBox() hbox_buttons.set_border_width(8) self.button_close=gtk.Button(None,gtk.STOCK_CLOSE) self.button_close.connect("clicked",self.destroy) self.button_next=gtk.Button(None,gtk.STOCK_GO_FORWARD) self.button_next.connect("clicked",self.next_match) hbox_buttons.pack_start(self.button_close,True,True,2) hbox_buttons.pack_start(self.button_next,True,True,2) vbox.pack_start(hbox_buttons,True,False,6) self.window.add(vbox) class GlobalSearch: def delete_event(self,widget,event,data=None): return False def destroy(self,widget): self.window.destroy() def show(self): self.window.show_all() def is_match(self,non_empty,article,rule,match_rule,from_string,subj_string,msgid_string,ref_string,body_string): found_vet=[] if 0 in non_empty: if match_rule(article.from_name,from_string): found_vet.append(True) else: found_vet.append(False) if 1 in non_empty: if match_rule(article.subj,subj_string): found_vet.append(True) else: found_vet.append(False) if 2 in non_empty: if match_rule(article.msgid,msgid_string): found_vet.append(True) else: found_vet.append(False) if 3 in non_empty: if match_rule(article.ref,ref_string): found_vet.append(True) else: found_vet.append(False) if 4 in non_empty: body=article.get_body() if body!=None: body=" ".join(body) if match_rule(body,body_string): found_vet.append(True) else: found_vet.append(False) else: found_vet.append(False) if rule=="And": found=reduce(lambda x,y: x and y, found_vet,True) else: found=reduce(lambda x,y: x or y, found_vet,False) return found def next_match(self,obj): non_empty=[] from_string=self.entry_from.get_text().decode("utf-8") if from_string!="": non_empty.append(0) subj_string=self.entry_subject.get_text().decode("utf-8") if subj_string!="": non_empty.append(1) msgid_string=self.entry_msgid.get_text().decode("utf-8") if msgid_string!="": non_empty.append(2) ref_string=self.entry_ref.get_text().decode("utf-8") if ref_string!="": non_empty.append(3) body_string=self.entry_body.get_text().decode("utf-8") if body_string!="": non_empty.append(4) rule=["And","Or"][self.opt_menu.get_active()] case_insensitive=self.checkbutton_case.get_active() use_regex=self.checkbutton_regex.get_active() def match_re_case_ins(field,regex): try: match_rule=re.compile(regex,re.UNICODE|re.IGNORECASE).findall(field) except: match_rule=False return match_rule def match_re_case_sens(field,regex): try: match_rule=re.compile(regex,re.UNICODE).findall(field) except: match_rule=False return match_rule #select the correct function if use_regex: if case_insensitive: match_rule=lambda field,regex: match_re_case_ins(field,regex) else: match_rule=lambda field,regex: match_re_case_sens(field,regex) else: if case_insensitive: match_rule=lambda field,word: field.lower().find(word.lower())+1 else: match_rule=lambda field,word: field.find(word)+1 #select the iter treesel=self.main_win.threads_pane.threads_tree.get_selection() model,iter=treesel.get_selected() column=self.main_win.threads_pane.threads_tree.get_column(0) subscribed=self.art_db.getSubscribed() name="global.search.results."+str(len(glob.glob(os.path.join(self.wdir,"groups_info","global.search.results*")))+1) if not os.path.isdir(os.path.join(self.wdir,"groups_info",name)): os.makedirs(os.path.join(self.wdir,"groups_info",name)) self.art_db.createGroup(name) unread_number=0 for group in subscribed: for article in self.art_db.getArticles(group[0]): found=self.is_match(non_empty,article,rule,match_rule,from_string,subj_string,msgid_string,ref_string,body_string) if found: self.art_db.insertArticle(name,article) if not article.is_read: unread_number=unread_number+1 total,unread_number=self.art_db.getArticlesNumbers(name) #self.main_win.groups_pane.show_list([("global.search.results",str(unread_number)+" ("+str(total)+")"),],True) self.main_win.groups_pane.model.append((name,str(unread_number)+" ("+str(total)+")",False)) self.main_win.threads_pane.clear() self.main_win.article_pane.clear() def __init__(self,main_win): self.wdir=get_wdir() self.art_db=main_win.art_db self.main_win=main_win self.window=gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event",self.delete_event) self.window.connect("destroy",self.destroy) self.window.set_title(_("Global Search")) self.window.set_position(gtk.WIN_POS_CENTER) self.window.set_default_size(350,300) self.window.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/global_search.xpm")) vbox=gtk.VBox() vbox.set_border_width(8) label_from=gtk.Label(_("From")) label_from.set_use_markup(True) label_from.set_alignment(0,0.5) label_subject=gtk.Label(_("Subject")) label_subject.set_use_markup(True) label_subject.set_alignment(0,0.5) label_msgid=gtk.Label(_("Message-ID")) label_msgid.set_use_markup(True) label_msgid.set_alignment(0,0.5) label_ref=gtk.Label(_("References")) label_ref.set_use_markup(True) label_ref.set_alignment(0,0.5) label_body=gtk.Label(_("Body")) label_body.set_use_markup(True) label_body.set_alignment(0,0.5) self.entry_from=gtk.Entry() self.entry_subject=gtk.Entry() self.entry_msgid=gtk.Entry() self.entry_ref=gtk.Entry() self.entry_body=gtk.Entry() fields_label=gtk.Label(""+_("Fields")+"") fields_label.set_alignment(0,0.5) fields_label.set_use_markup(True) fields_vbox=gtk.VBox() fields_vbox.set_border_width(4) fields_vbox.pack_start(fields_label,False,False,4) find_table=gtk.Table(6,2,False) find_table.set_border_width(4) find_table.attach(label_from,0,1,0,1,gtk.FILL,gtk.FILL,16,4) find_table.attach(label_subject,0,1,1,2,gtk.FILL,gtk.FILL,16,4) find_table.attach(label_msgid,0,1,2,3,gtk.FILL,gtk.FILL,16,4) find_table.attach(label_ref,0,1,4,5,gtk.FILL,gtk.FILL,16,4) find_table.attach(label_body,0,1,5,6,gtk.FILL,gtk.FILL,16,4) find_table.attach(self.entry_from,1,2,0,1,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,4) find_table.attach(self.entry_subject,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,4) find_table.attach(self.entry_msgid,1,2,2,3,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,4) find_table.attach(self.entry_ref,1,2,4,5,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,4) find_table.attach(self.entry_body,1,2,5,6,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,4) fields_vbox.pack_start(find_table,True,True,4) vbox.pack_start(fields_vbox,True,False,2) rule_table=gtk.Table(3,1,False) rule_table.set_border_width(4) hbox=gtk.HBox() self.checkbutton_regex=gtk.CheckButton(_("Use Regular Expression")) self.checkbutton_case=gtk.CheckButton(_("Case Insensitive")) label=gtk.Label(_("Rule used to combine search results")) self.opt_menu=gtk.combo_box_new_text() self.opt_menu.append_text(_("AND")) self.opt_menu.append_text(_("OR")) self.opt_menu.set_active(0) rule_table.attach(self.checkbutton_regex,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16,4) rule_table.attach(self.checkbutton_case,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16,4) hbox.pack_start(self.opt_menu,False,True,2) hbox.pack_start(label,False,True) rule_table.attach(hbox,0,1,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,16,4) rule_label=gtk.Label(""+_("Rules")+"") rule_label.set_alignment(0,0.5) rule_label.set_use_markup(True) rule_vbox=gtk.VBox() rule_vbox.pack_start(rule_label,False,False,4) rule_vbox.set_border_width(4) rule_vbox.pack_start(rule_table,True,True,4) vbox.pack_start(rule_vbox,True,True,4) hbox_buttons=gtk.HBox() hbox_buttons.set_border_width(8) self.button_close=gtk.Button(None,gtk.STOCK_CLOSE) self.button_close.connect("clicked",self.destroy) self.button_next=gtk.Button(None,gtk.STOCK_FIND) self.button_next.connect("clicked",self.next_match) hbox_buttons.pack_start(self.button_close,True,True,2) hbox_buttons.pack_start(self.button_next,True,True,2) vbox.pack_start(hbox_buttons,True,False,6) self.window.add(vbox) xpn-1.2.6/xpn_src/KeyBindings.py0000700000175000017500000005074311141275756014722 0ustar antantimport gtk import gobject import cPickle import os from xpn_src.UserDir import get_wdir from xpn_src.Dialogs import Shortcut_Dialog, Shortcut_Error_Warning_Dialog, Dialog_OK def escape(data): """Escape &, <, and > in a string of data. """ # must do ampersand first data = data.replace("&", "&") data = data.replace(">", ">") data = data.replace("<", "<") return data def load_actions(): main_actions=[ ("File",_("File")), ("groups",_("Groups List..."),None), ("rules",_("Scoring and Action Rules..."),None), ("logs",_("Server Logs..."),None), ("exp_newsrc",_("Export Newsrc..."),None), ("imp_newsrc",_("Import Newsrc..."),None), ("accelerator",_("Modify Keyboard Shortcuts..."),None), ("conf",_("Preferences..."),None), ("exit",_("Exit"),"E"), ("Search",_("Search")), ("find",_("Find Article..."),"F"), ("filter",_("Filter Articles..."),"KP_Divide"), ("global",_("Global Search ..."),"G"), ("search",_("Search in the Body..."),"S"), ("View",_("View")), ("view_articles_opts",_("Articles View Options")), ("raw",_("View Raw Article"),"H"), ("spoiler",_("Show Spoilered Text"),"L"), ("show_quote",_("Show Quoted Text"),"Q"), ("show_sign",_("Show Signatures"),"S"), ("fixed",_("Fixed Pitch Font"),"F"), ("show_hide_headers",_("Show/Hide Headers"),"H"), ("rot13",_("ROT13 Selected Text"),"R"), ("view_group_opts",_("Groups View Options")), ("show_threads",_("Show Threads"),None), ("show_all_read_threads",_("Show All Read Threads"),None), ("show_threads_without_watched",_("Show Threads Without Watched Articles"),None), ("show_read_articles",_("Show Read Articles"),None), ("show_unread_articles",_("Show UnRead Articles"),None), ("show_kept_articles",_("Show Kept Articles"),None), ("show_unkept_articles",_("Show UnKept Articles"),None), ("show_watched_articles",_("Show Watched Articles"),None), ("show_ignored_articles",_("Show Ignored Articles"),None), ("show_unwatchedignored_articles",_("Show UnWatched/UnIgnored Articles"),None), ("show_score_neg_articles",_("Show Articles with Score<0"),None), ("show_score_zero_articles",_("Show Articles with Score=0"),None), ("show_score_pos_articles",_("Show Articles with Score>0"),None), ("Navigate",_("Navigate")), ("group",_("View Next Group"),"G"), ("previous",_("Read Previous Article"),"B"), ("next",_("Read Next Article"),"N"), ("next_unread",_("Read Next Unread Article"),"N"), ("parent",_("Read Parent Article"),"U"), ("one_key",_("One-Key Reading"),"space"), ("move_up",_("One-Key Scroll Up"),"space"), ("focus_article",_("Focus to Article Pane"),"3"), ("focus_groups",_("Focus to groups Pane"),"1"), ("focus_threads",_("Focus to Threads Pane"),"2"), ("zoom_article",_("Zoom Article Pane"),"3"), ("zoom_groups",_("Zoom groups Pane"),"1"), ("zoom_threads",_("Zoom Threads Pane"),"2"), ("Subscribed",_("Subscribed Groups")), ("gethdrs",_("Get New Headers in Subscribed Groups"),"H"), ("gethdrssel",_("Get New Headers in Selected Groups"),"H"), ("getbodies",_("Get Marked Article Bodies in Subscribed Groups"),"B"), ("getbodiessel",_("Get Marked Article Bodies in Selected Groups"),"B"), ("expand",_("Expand All Threads"),None), ("collapse",_("Collapse All Threads"),None), ("expand_row",_("Expand Selected SubThread"),None), ("collapse_row",_("Collapse Selected SubThread"),None), ("mark_group",_("Mark Group ...")), ("mark",_("Mark Selected Groups as Read"),None), ("mark_unread_group",_("Mark Selected Groups as Unread"),None), ("mark_download_group",_("Mark Group for Retrieving"),None), ("keepall",_("Keep Articles in Selected Groups"),None), ("markall",_("Mark All Groups as Read"),None), ("markall_unread",_("Mark All Groups as Unread"),None), ("apply_score",_("Apply Scoring and Action Rules"),None), ("groups_vs_id",_("Assign Identities to Groups"),None), ("Articles",_("Articles")), ("post",_("Post New Article..."),"P"), ("followup",_("Follow-Up To Newsgroup..."),"F"), ("reply",_("Reply By Mail..."),"M"), ("outbox_manager",_("Open Outbox Manager"),None), ("cancel",_("Cancel Article..."),None), ("supersede",_("Supersede Article..."),None), ("flags",_("Flags & Score")), ("mark_read",_("Mark Article as Read"),"R"), ("mark_unread",_("Mark Article as UnRead"),"U"), ("mark_download",_("Mark Article for Retrieving"),"M"), ("keep",_("Keep Article"),"K"), ("delete",_("Delete Article"),"D"), ("mark_unread_sub",_("Mark SubThread as UnRead"),None), ("mark_read_sub",_("Mark SubThread as Read"),None), ("mark_download_sub",_("Mark SubThread for Retrieving"),None), ("keep_sub",_("Keep SubThread"),None), ("watch",_("Watch SubThread"),"W"), ("ignore",_("Ignore SubThread"),"I"), ("raise_score",_("Raise Author Score"),None), ("lower_score",_("Lower Author Score"),None), ("set_score",_("Set Author Score"),None), ("Help",_("Help")), ("about",_("About..."),None)] edit_actions=[ ("Article",_("Article")), ("send",_("Send Article"),"S"), ("send_later",_("Send Article Later"),"S"), ("save_draft",_("Save Article as Draft"),"D"), ("discard",_("Discard Article"),"D"), ("rot13",_("ROT13 Selected Text"),"R"), ("editor",_("Launch External Editor"),"E"), ("spoiler",_("Insert Spoiler Char"),"L")] outbox_actions=[ ("Outbox",_("Outbox")), ("send_article",_("Send Queued Articles"),"S"), ("send_mail",_("Send Queued Mails"),"S"), ("edit",_("Edit Article/Mail"),"E"), ("delete",_("Delete Article/Mail"),"Delete"), ("exit",_("Exit"),"E")] return main_actions,edit_actions,outbox_actions def load_shortcuts(win): main_actions,edit_actions,outbox_actions=load_actions() main_shortcuts=dict() edit_shortcuts=dict() outbox_shortcuts=dict() try: f=open(os.path.join(get_wdir(),"dats/shortcuts.dat"),"rb") except IOError: file_found=False else: file_found=True shortcuts=cPickle.load(f) f.close() if not shortcuts: file_found=False if win=="main": for action in main_actions: if len(action)>2: if file_found: try: main_shortcuts[action[0]]=shortcuts["main"][action[0]] except: main_shortcuts[action[0]]=action[2] else: main_shortcuts[action[0]]=action[2] return main_shortcuts if win=="edit": for action in edit_actions: if len(action)>2: if file_found: try: edit_shortcuts[action[0]]=shortcuts["edit"][action[0]] except: edit_shortcuts[action[0]]=action[2] else: edit_shortcuts[action[0]]=action[2] return edit_shortcuts if win=="outbox": for action in outbox_actions: if len(action)>2: if file_found: try: outbox_shortcuts[action[0]]=shortcuts["outbox"][action[0]] except: edit_shortcuts[action[0]]=action[2] else: outbox_shortcuts[action[0]]=action[2] return outbox_shortcuts else: return dict() class KeyBindings: def delete_event(self,widget,event,data=None): return False def destroy(self,widget): self.window.destroy() if __name__=="__main__": gtk.main_quit() def close_ok(self,obj): self.dump_tree() #self.main_win.create_ui() self.destroy(None) def close_cancel(self,obj): self.destroy(None) def get_shortcuts_from_tree(self): #0:Short Name 1:Long Name 2:Accelerator 3:Dump model=self.treeview.get_model() iter_current=model.get_iter_first() shortcuts=dict() shortcuts["main"]=dict() shortcuts["edit"]=dict() shortcuts["outbox"]=dict() while iter_current: sname=model.get_value(iter_current,0) accel=model.get_value(iter_current,2) to_dump=model.get_value(iter_current,3) if to_dump: parent_path=tuple([model.get_path(iter_current)[0],]) parent_iter=model.get_iter(parent_path) win=model.get_value(parent_iter,0) shortcuts[win][sname]=accel #let's cycle the tree if model.iter_has_child(iter_current): iter_current=model.iter_children(iter_current) else: iter_next=model.iter_next(iter_current) while not iter_next: prev_iter=model.iter_parent(iter_current) iter_current=prev_iter if not prev_iter: break iter_next=model.iter_next(iter_current) iter_current=iter_next return shortcuts def dump_tree(self): shortcuts=self.get_shortcuts_from_tree() f=open(os.path.join(get_wdir(),"dats/shortcuts.dat"),"wb") cPickle.dump(shortcuts,f,1) f.close() def change_shortcut(self,obj): model,iter_selected=self.treeview.get_selection().get_selected() if iter_selected: to_dump=model.get_value(iter_selected,3) if to_dump: dialog=Shortcut_Dialog() if dialog.resp==gtk.RESPONSE_OK: model.set_value(iter_selected,2,dialog.shortcut) def check_duplicates_warnings(self,obj): shortcuts=self.get_shortcuts_from_tree() main_values=shortcuts["main"].values() edit_values=shortcuts["edit"].values() outbox_values=shortcuts["outbox"].values() main_actions,edit_actions,outbox_actions=load_actions() def get_desc(value_to_find,win): dic=shortcuts[win] if win=="main": actions=main_actions elif win=="edit": actions=edit_actions else: actions=outbox_actions for key,value in dic.iteritems(): if value_to_find==value: for action in actions: if action[0]==key: return action[1] return "" warnings=[] main_actions,edit_actions,outbox_actions=load_actions() for value in edit_values: if value in main_values: warnings.append([_("Edit Window"),value,get_desc(value,"edit")]) warnings.append([_("Main Window"),value,get_desc(value,"main")]) warnings.append(["","",""]) for value in edit_values: if value in outbox_values: warnings.append([_("Edit Window"),value,get_desc(value,"edit")]) warnings.append([_("Outbox Window"),value,get_desc(value,"outbox")]) warnings.append(["","",""]) for value in outbox_values: if value in main_values: warnings.append([_("Outbox Window"),value,get_desc(value,"outbox")]) warnings.append([_("Main Window"),value,get_desc(value,"main")]) warnings.append(["","",""]) if len(warnings)>0: self.dialog3=Shortcut_Error_Warning_Dialog(True,warnings,""+_("Found duplicated shortcuts on different windows")+"\n"+_("That's not a problem, the shortcut will work only on the active window ")) else: self.dialog3=Dialog_OK(_("No Errors")) def check_duplicates_errors(self,obj): shortcuts=self.get_shortcuts_from_tree() main_values=[value.lower() for value in shortcuts["main"].values() if value] edit_values=[value.lower() for value in shortcuts["edit"].values() if value] outbox_values=[value.lower() for value in shortcuts["outbox"].values() if value] main_actions,edit_actions,outbox_actions=load_actions() def get_desc(value_to_find,win): dic=shortcuts[win] if win=="main": actions=main_actions elif win=="edit": actions=edit_actions else: actions=outbox_actions for key,value in dic.iteritems(): if value: if value_to_find.lower()==value.lower(): for action in actions: if action[0]==key: dic.pop(action[0]) return action[1] return "" errors=[] main_actions,edit_actions,outbox_actions=load_actions() main_values_shown=[] edit_values_shown=[] outbox_values_shown=[] for value in main_values: count=main_values.count(value) if count>1: if value and not (value in main_values_shown): main_values_shown.append(value) for i in range(count): errors.append([_("Main Window"),value,get_desc(value,"main")]) for value in edit_values: count=edit_values.count(value) if count>1: if value and not (value in edit_values_shown): edit_values_shown.append(value) for i in range(count): errors.append([_("Edit Window"),value,get_desc(value,"edit")]) for value in outbox_values: count=outbox_values.count(value) if count>1: if value and not (value in outbox_values_shown): outbox_values_shown.append(value) for i in range(count): errors.append([_("Outbox Window"),value,get_desc(value,"outbox")]) if len(errors)>0: self.dialog3=Shortcut_Error_Warning_Dialog(False,errors,""+_("Found duplicated shortcuts on the same windows")+"") else: self.dialog3=Dialog_OK(_("No Errors")) def load_list(self): self.model.clear() main_actions,edit_actions,outbox_actions=load_actions() main_shortcuts=load_shortcuts("main") edit_shortcuts=load_shortcuts("edit") outbox_shortcuts=load_shortcuts("outbox") #0:Short Name 1:Long Name 2:Accelerator 3:Dump iter_root_mainwin=self.model.append(None,["main",_("Main Window"),"",False]) for action in main_actions: if len(action) == 2: iter_root_menu=self.model.append(iter_root_mainwin,[action[0],action[1],"",False]) else: self.model.append(iter_root_menu,[action[0],action[1],main_shortcuts[action[0]],True]) iter_root_editwin=self.model.append(None,["edit",_("Edit Window"),"",False]) for action in edit_actions: if len(action) == 2: iter_root_menu=self.model.append(iter_root_editwin,[action[0],action[1],"",False]) else: self.model.append(iter_root_menu,[action[0],action[1],edit_shortcuts[action[0]],True]) iter_root_outboxwin=self.model.append(None,["outbox",_("Outbox Window"),"",False]) for action in outbox_actions: if len(action) == 2: iter_root_menu=self.model.append(iter_root_outboxwin,[action[0],action[1],"",False]) else: self.model.append(iter_root_menu,[action[0],action[1],outbox_shortcuts[action[0]],True]) def reset_defaults(self,obj): try: os.remove(os.path.join(get_wdir(),"dats/shortcuts.dat")) except: pass self.load_list() def clear_shortcuts(self,obj): iter_current=self.model.get_iter_first() while iter_current: to_dump=self.model.get_value(iter_current,3) if to_dump: self.model.set_value(iter_current,2,"") #let's cycle the tree if self.model.iter_has_child(iter_current): iter_current=self.model.iter_children(iter_current) else: iter_next=self.model.iter_next(iter_current) while not iter_next: prev_iter=self.model.iter_parent(iter_current) iter_current=prev_iter if not prev_iter: break iter_next=self.model.iter_next(iter_current) iter_current=iter_next def __init__(self,main_win): self.main_win=main_win self.window=gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event",self.delete_event) self.window.connect("destroy",self.destroy) self.window.set_title(_("Keyboard Shortcuts")) self.window.set_position(gtk.WIN_POS_CENTER) vbox=gtk.VBox() vbox.set_border_width(4) self.window.set_size_request(500,400) scrolledwin=gtk.ScrolledWindow() scrolledwin.set_border_width(4) scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.treeview=gtk.TreeView() self.treeview.set_border_width(4) #0:Short Name 1:Long Name 2:Accelerator 3:Dump self.model=gtk.TreeStore(gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_BOOLEAN) scrolledwin.add(self.treeview) self.treeview.set_model(self.model) text_renderer=gtk.CellRendererText() column1=gtk.TreeViewColumn(_("Action"),text_renderer,text=1) column2=gtk.TreeViewColumn(_("Shortcut"),text_renderer,text=2) self.treeview.append_column(column1) self.treeview.append_column(column2) self.treeview.set_rules_hint(True) self.button_change=gtk.Button(_("Change Shortcut")) self.button_change.connect("clicked",self.change_shortcut) self.button_default=gtk.Button(_("Default Shortcuts")) self.button_default.connect("clicked",self.reset_defaults) self.button_clear_shortcuts=gtk.Button(_("Clear Shortcuts")) self.button_clear_shortcuts.connect("clicked",self.clear_shortcuts) self.button_duplicates_warnings=gtk.Button(_("Duplicates Warnings")) self.button_duplicates_warnings.connect("clicked",self.check_duplicates_warnings) self.button_duplicates_errors=gtk.Button(_("Duplicates Errors")) self.button_duplicates_errors.connect("clicked",self.check_duplicates_errors) button_table=gtk.Table(4,2,False) vbox.pack_start(scrolledwin,True,True,4) sep=gtk.HSeparator() button_table.attach(self.button_change,0,2,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,4,4) button_table.attach(self.button_clear_shortcuts,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,4,4) button_table.attach(self.button_default,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,4,4) button_table.attach(self.button_duplicates_warnings,0,1,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,4,4) button_table.attach(self.button_duplicates_errors,1,2,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,4,4) button_table.attach(sep,0,2,3,4,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,4,4) vbox.pack_start(button_table,False,True,4) hbox=gtk.HBox() self.ok_button=gtk.Button(None,gtk.STOCK_OK) self.ok_button.connect("clicked",self.close_ok) self.cancel_button=gtk.Button(None,gtk.STOCK_CANCEL) self.cancel_button.connect("clicked",self.close_cancel) hbox.pack_start(self.cancel_button,True,True,2) hbox.pack_start(self.ok_button,True,True,2) vbox.pack_start(hbox,False,True,6) self.load_list() self.window.add(vbox) self.window.show_all() xpn-1.2.6/xpn_src/Headers_List.py0000644000175000017500000002260611141275756015066 0ustar antantimport gtk import gobject import cPickle import os from xpn_src.UserDir import get_wdir default_list=["From","Date","Subject"] headers_list=["From","Date","Subject","Newsgroups","Reply-To","Sender","Organization","Followup-To","Mail-Copies-To", "Archive","Supersedes","Approved","Content-Type","Content-Transfer-Encoding","User-Agent","Xref","Bytes", "Lines","Message-ID","References"] def load_headers_list(): try: f=open(os.path.join(get_wdir(),"dats/headers_list.dat"),"rb") except IOError: list=default_list else: list=cPickle.load(f) f.close() if not list: list=headers_list return list class HeadersList: def delete_event(self,widget,event,data=None): return False def destroy(self,widget): self.window.destroy() if __name__=="__main__": gtk.main_quit() def close_ok(self,obj): self.dump_tree(self.right_list) self.destroy(None) def close_cancel(self,obj): self.destroy(None) def fill_lists(self): for header in headers_list: self.left_model.append([header]) list=load_headers_list() for header in list: self.right_model.append([header]) def get_headers_list(self,treeview): model=treeview.get_model() iter=model.get_iter_first() list=[] while iter: list.append(model.get_value(iter,0)) iter=model.iter_next(iter) return list def dump_tree(self,treeview): list=self.get_headers_list(self.right_list) f=open(os.path.join(get_wdir(),"dats/headers_list.dat"),"wb") cPickle.dump(list,f,1) f.close() def set_default_list(self,obj): self.right_model.clear() for header in default_list: self.right_model.append([header]) def add_manually(self,obj): header=self.add_manually_entry.get_text() if header and not (header in self.get_headers_list(self.right_list)): self.right_model.append([header]) def add_ordered(self,obj): model_left,path_left_list=self.left_list.get_selection().get_selected_rows() for path in path_left_list: iter_left=model_left.get_iter(path) header=model_left.get_value(iter_left,0) if not (header in self.get_headers_list(self.right_list)): self.right_model.append([header]) def remove_ordered(self,obj): model_right,path_right_list=self.right_list.get_selection().get_selected_rows() for i in range(len(path_right_list)): path=path_right_list[i] if i!=0: path=list(path) path[0]=path[0]-i path=tuple(path) iter_right=model_right.get_iter(path) self.right_model.remove(iter_right) def move_up(self,obj): model,path_list=self.right_list.get_selection().get_selected_rows() for path in path_list: iter_to_move=model.get_iter(path) new_path=list(path) if new_path[0]>0: new_path[0]=new_path[0]-1 new_path=tuple(new_path) iter_previous=model.get_iter(new_path) model.swap(iter_to_move,iter_previous) def move_down(self,obj): model,path_list=self.right_list.get_selection().get_selected_rows() path_list.reverse() for path in path_list: iter_to_move=model.get_iter(path) iter_next=model.iter_next(iter_to_move) if iter_next!=None: model.swap(iter_to_move,iter_next) def __init__(self): self.window=gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event",self.delete_event) self.window.connect("destroy",self.destroy) self.window.set_title("Headers List") self.window.set_position(gtk.WIN_POS_CENTER) self.window.set_size_request(500,400) self.table=gtk.Table(3,2,False) self.table.set_border_width(4) label_left=gtk.Label(""+_("Standard Headers")+"") label_left.set_use_markup(True) label_right=gtk.Label(""+_("Shown Headers")+"") label_right.set_use_markup(True) self.left_scrolledwin=gtk.ScrolledWindow() self.left_scrolledwin.set_border_width(4) self.left_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.left_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.left_scrolledwin.set_size_request(200,-1) self.left_list=gtk.TreeView() self.left_list.set_border_width(4) self.left_model=gtk.ListStore(gobject.TYPE_STRING) self.left_scrolledwin.add(self.left_list) self.left_list.set_model(self.left_model) text_renderer=gtk.CellRendererText() self.left_column=gtk.TreeViewColumn(_("List"),text_renderer,text=0) self.left_list.append_column(self.left_column) self.left_list.set_rules_hint(True) self.left_list.set_headers_visible(False) self.left_list.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.right_scrolledwin=gtk.ScrolledWindow() self.right_scrolledwin.set_border_width(4) self.right_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.right_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.right_scrolledwin.set_size_request(200,-1) self.right_list=gtk.TreeView() self.right_list.set_border_width(4) self.right_model=gtk.ListStore(gobject.TYPE_STRING) self.right_scrolledwin.add(self.right_list) self.right_list.set_model(self.right_model) text_renderer=gtk.CellRendererText() self.right_column=gtk.TreeViewColumn(_("List"),text_renderer,text=0) self.right_list.append_column(self.right_column) self.right_list.set_rules_hint(True) self.right_list.set_headers_visible(False) self.right_list_tooltip=gtk.Tooltips() self.right_list_tooltip.set_tip(self.right_list,_("XPN will show these headers on the top of the Article Pane")) self.right_list.set_reorderable(True) self.right_list.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.to_right_button=gtk.Button() to_right_button_image=gtk.Image() to_right_button_image.set_from_stock(gtk.STOCK_GO_FORWARD,gtk.ICON_SIZE_MENU) self.to_right_button.add(to_right_button_image) self.to_right_button.connect("clicked",self.add_ordered) self.to_left_button=gtk.Button() to_left_button_image=gtk.Image() to_left_button_image.set_from_stock(gtk.STOCK_GO_BACK,gtk.ICON_SIZE_MENU) self.to_left_button.add(to_left_button_image) self.to_left_button.connect("clicked",self.remove_ordered) vbox_buttons=gtk.VBox() vbox_buttons.pack_start(self.to_right_button,False,True,10) vbox_buttons.pack_start(self.to_left_button,False,True,10) up_button_image=gtk.Image() up_button_image.set_from_stock(gtk.STOCK_GO_UP,gtk.ICON_SIZE_MENU) self.up_button=gtk.Button() self.up_button.add(up_button_image) self.up_button.connect("clicked",self.move_up) down_button_image=gtk.Image() down_button_image.set_from_stock(gtk.STOCK_GO_DOWN,gtk.ICON_SIZE_MENU) self.down_button=gtk.Button() self.down_button.add(down_button_image) self.down_button.connect("clicked",self.move_down) vbox_buttons2=gtk.VBox() vbox_buttons2.pack_start(self.up_button,False,False,10) vbox_buttons2.pack_start(self.down_button,False,False,10) self.add_manually_entry=gtk.Entry() self.add_manually_button=gtk.Button(_("Add Manually")) add_manually_hbox=gtk.HBox() add_manually_hbox.add(self.add_manually_entry) add_manually_hbox.add(self.add_manually_button) self.add_manually_button.connect("clicked",self.add_manually) self.default_button=gtk.Button(_("Set Default List")) self.default_button.connect("clicked",self.set_default_list) self.table.attach(label_left,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL) self.table.attach(vbox_buttons,1,2,1,2,gtk.EXPAND|gtk.FILL,gtk.EXPAND) self.table.attach(label_right,2,3,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL) self.table.attach(self.left_scrolledwin,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL) self.table.attach(self.right_scrolledwin,2,3,1,2,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL) self.table.attach(vbox_buttons2,3,4,1,2,gtk.FILL,gtk.EXPAND) self.table.attach(add_manually_hbox,2,3,2,3,gtk.FILL|gtk.EXPAND,gtk.FILL) self.table.attach(self.default_button,2,3,3,4,gtk.FILL|gtk.EXPAND,gtk.FILL) vbox=gtk.VBox() hbox=gtk.HBox() self.ok_button=gtk.Button(None,gtk.STOCK_OK) self.ok_button.connect("clicked",self.close_ok) self.cancel_button=gtk.Button(None,gtk.STOCK_CANCEL) self.cancel_button.connect("clicked",self.close_cancel) hbox.pack_start(self.cancel_button,True,True,2) hbox.pack_start(self.ok_button,True,True,2) vbox.pack_start(self.table,True,True,4) vbox.pack_start(hbox,False,True,2) self.window.add(vbox) self.fill_lists() self.window.show_all() if __name__=="__main__": ch_list=HeadersList() gtk.main() xpn-1.2.6/xpn_src/Edit_Mail_Win.py0000644000175000017500000010631511141275756015164 0ustar antantimport gtk import pango import sys import time import smtplib import cPickle import os import re import ConfigParser from email.Utils import formatdate, parseaddr from random import randint,seed from locale import getdefaultlocale from xpn_src.Article import Mail_To_Send from xpn_src.Dialogs import Dialog_YES_NO, Dialog_OK from xpn_src.Charset_List import encodings_list, guess_list, encodings_tip, load_ordered_list from xpn_src.Connections_Handler import SMTPConnection from xpn_src.UserDir import get_wdir from xpn_src.KeyBindings import load_shortcuts ui_string=""" """ class Edit_Mail_Win: def show(self): self.win.show_all() #setting the focus self.textview.grab_focus() def delete_event(self,widget,event,data=None): self.editwin_width,self.editwin_height=self.win.get_size() self.save_sizes() return False def destroy(self,obj): self.buffer.disconnect(self.mark_set_handler) self.save_sizes() self.win.destroy() if self.outboxManager: self.outboxManager.populateFolderTree() def guess_encoding(self,text): for best_enc in guess_list: try: unicode(text,best_enc,"strict") except: pass else: break return best_enc def external_editor(self,obj,command): body="" bounds=self.buffer.get_bounds() if bounds: start,stop=bounds body=self.buffer.get_text(start,stop,True).decode("utf-8") self.buffer.delete(start,stop) try: system_enc=getdefaultlocale()[1] body=body.encode(system_enc,"replace") except: body=body.encode(self.fallback_charset,"replace") filename=(os.path.join(self.wdir,"temp_article.txt")) f=open(filename,"w") f.write(body) f.close() command=command.replace("%s",filename) result=os.system(command) if result==0: f=open(filename,"r") body=f.read().split("\n") f.close() os.remove(filename) best_enc=self.guess_encoding("".join(body)) body=[unicode(line,best_enc,"strict") for line in body] self.show_article(body) else: self.statusbar.push(1,_("Error while opening external editor")) def update_to_name_entry(self,value): to_name=value self.to_name_entry.set_text(to_name.encode("utf-8")) def update_subject_entry(self,subj): if subj[0:3].lower()!="re:": subj="Re: "+subj self.subj_entry.set_text(subj.encode("utf-8")) def update_references(self,article_references): mom=article_references.split() article_references=" ".join(mom) #in this way I removed FWSP tabs if len(mom)>21: #The number of References is greater than 21 for i in range(0,len(mom)-21): mom.remove(mom[1]) refs="" for i in range(len(mom)): refs=refs+mom[i]+" " article_references=refs.strip() refs_len=len(article_references) if refs_len>980: #References plus "References: " excedes 998 octets mom=article_references.split() while refs_len>980: mom_len=len(mom[1]) mom.remove(mom[1]) refs_len=refs_len-mom_len refs="" for i in range(len(mom)): refs=refs+mom[i]+" " article_references=refs.strip() article_references=article_references.strip() return article_references def wrap_line(self,string_to_wrap,wrap=73): split_string=string_to_wrap.split() new_line="" lines=[] for word in split_string: if len(new_line)+len(word)+10: if line[0]!=">": quoted_body.append("> "+line) else: quoted_body.append(">"+line) else: quoted_body.append(">"+line) self.show_article(quoted_body) def tag_line(self): try: f=open(os.path.join(self.wdir,"tags.txt"),"r") except IOError: return _("tags.txt not found") else: list=f.readlines() f.close() seed() if len(list)>0: tag=list[randint(0,len(list)-1)] best_enc=self.guess_encoding(tag) tag=unicode(tag,best_enc) tag_wrapped=self.wrap_line(tag) tag="" for line in tag_wrapped: tag=tag+line+"\n" return tag else: return "XPN :: http://xpn.altervista.org" def add_sign(self): sign=[] delimiter=False if self.cp_id.get(self.id_name,"sign")!="": try: sign_file=open(os.path.join(self.wdir,self.cp_id.get(self.id_name,"sign")),"r") except IOError: sign=_("Signature file not found") best_enc="utf-8" else: sign=sign_file.readlines() best_enc=self.guess_encoding("".join(sign)) sign_file.close() self.insert_with_tags("\n-- \n","sign") delimiter=True use_tags=self.cp_id.get(self.id_name,"use_tags") if use_tags=="True": tag=self.tag_line()#unicode(self.tag_line(),"iso8859-1","replace") if delimiter==False: self.insert_with_tags("\n-- \n","sign") self.insert_with_tags(tag,"sign") for i in range(len(sign)): #self.insert_with_tags(unicode(sign[i],"iso8859-1","replace"),"sign") self.insert_with_tags(sign[i].decode(best_enc),"sign") def show_article(self,article): is_sign=False is_quote=False def quote_depth(line): count=0 for char in line: if char==">": count=count+1 else: break if count>3: count=3 return str(count) for line in article: line=line.replace("\r","") #this is needed for some strange articles if len(line)>0: if line[0]==">": is_quote=True elif (len(line)==2 and line[0:2]=="--") or (len(line)==3 and line[0:3]=="-- "): is_sign=True is_quote=False else: is_quote=False if is_quote and not is_sign: quote_level=quote_depth(line) self.insert_with_tags(line,"quote"+quote_level) elif is_sign: self.insert_with_tags(line,"sign") else: self.insert_with_tags(line,"text") self.insert("\n") def set_text_color(self,color): text_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.text_tag: self.text_tag=gtk.TextTag("text") self.tag_table.add(self.text_tag) self.text_tag.set_property("foreground-gdk",text_color) def set_quote_color(self,color,level): if level==1: quote1_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.quote1_tag: self.quote1_tag=gtk.TextTag("quote1") self.tag_table.add(self.quote1_tag) self.quote1_tag.set_property("foreground-gdk",quote1_color) elif level==2: quote2_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.quote2_tag: self.quote2_tag=gtk.TextTag("quote2") self.tag_table.add(self.quote2_tag) self.quote2_tag.set_property("foreground-gdk",quote2_color) else: quote3_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.quote3_tag: self.quote3_tag=gtk.TextTag("quote3") self.tag_table.add(self.quote3_tag) self.quote3_tag.set_property("foreground-gdk",quote3_color) def set_sign_color(self,color): sign_color=gtk.gdk.color_parse(color) self.tag_table=self.buffer.get_tag_table() if not self.sign_tag: self.sign_tag=gtk.TextTag("sign") self.tag_table.add(self.sign_tag) self.sign_tag.set_property("foreground-gdk",sign_color) def set_background(self,configs): color=configs["background_color"] color=gtk.gdk.color_parse(color) self.textview.modify_base(gtk.STATE_NORMAL,color) def set_foreground(self,configs): color=configs["text_color"] color=gtk.gdk.color_parse(color) self.textview.modify_text(gtk.STATE_NORMAL,color) def insert(self,string): mark=self.buffer.get_insert() iter=self.buffer.get_iter_at_mark(mark) self.buffer.insert(iter,string.encode("utf-8")) def insert_with_tags(self,string,tag): self.buffer.insert_with_tags_by_name(self.buffer.get_end_iter(),string.encode("utf-8"),tag) def rot13(self,text): "Rot13 the string passed" string_coded = "" dic={'a':'n','b':'o','c':'p','d':'q','e':'r','f':'s','g':'t', 'h':'u','i':'v','j':'w','k':'x','l':'y','m':'z', 'n':'a','o':'b','p':'c','q':'d','r':'e','s':'f','t':'g', 'u':'h','v':'i','w':'j','x':'k','y':'l','z':'m', 'A':'N','B':'O','C':'P','D':'Q','E':'R','F':'S','G':'T', 'H':'U','I':'V','J':'W','K':'X','L':'Y','M':'Z', 'N':'A','O':'B','P':'C','Q':'D','R':'E','S':'F','T':'G', 'U':'H','V':'I','W':'J','X':'K','Y':'L','Z':'M'} for c in text: char=dic.get(c,c) string_coded=string_coded+char return string_coded def apply_rot13(self,obj): bounds=self.buffer.get_selection_bounds() if bounds: start=bounds[0] stop=bounds[1] text=self.buffer.get_text(start,stop,True).decode("utf-8") text_rotted=self.rot13(text) self.buffer.delete_selection(False,False) self.insert(text_rotted) def check_article(self,to_name,from_name,subject): """Checks if the article is wellformed. Performs checks on from_name, to_name, subject header fields and on the body. Returns two strings, errors, warnings """ def check_from(from_name): nick,mail=parseaddr(from_name) if not nick and not mail: return _("* From field appears to be invalid\n") elif "@" not in mail: return _("* From field appears to be invalid\n") else: return "" def check_to(to_name): nick,mail=parseaddr(to_name) if not nick and not mail: return _("* To field appears to be invalid\n") elif "@" not in mail: return _("* To field appears to be invalid\n") else: return "" def check_body(body): quoted=0 text=0 total=len(body) if self.mode=="Normal": for attr_line in self.attr_line_splitted: if attr_line in body :body.remove(attr_line) for line in body: if line=="--" or line=="-- ": break elif line.startswith(">"): quoted=quoted+1 elif line.strip()!="": text=text+1 else: continue if text+quoted==0: return _("* Article seems to be empty\n"),"" elif text==0: return _("* Article doesn't contain new text\n"),"" elif quoted*100/float(quoted+text)>95: return "",_("* Article contains more than 95% of quoted text\n") else: return "","" errors="" warnings="" if not subject: errors=errors+_("* Subject field is empty\n") if not from_name: errors=warnings+_("* From field is empty\n") else: errors=errors+check_from(from_name) if not to_name: errors=warnings+_("* To field is empty\n") else: errors=errors+check_to(to_name) bounds=self.buffer.get_bounds() if bounds: start,stop=bounds text=self.buffer.get_text(start,stop,True).decode("utf-8") body=text.split("\n") else: body=[] body_errors,body_warnings=check_body(body) errors=errors+body_errors warnings=warnings+body_warnings return errors,warnings def send_article(self,obj,configs,send_later=False,isDraft=False): to_name=self.to_name_entry.get_text().decode("utf-8") from_name=self.from_entry.get_text().decode("utf-8") subject=self.subj_entry.get_text().decode("utf-8") date=formatdate(localtime=True) if not isDraft: errors,warnings=self.check_article(to_name,from_name,subject) else: errors,warnings=None,None if errors: message=""+_("Errors:")+"\n\n"+errors if warnings: message=message+"\n\n"+_("Warnings:")+"\n\n"+warnings dialog=Dialog_OK(message) do_send=False elif warnings: message=""+_("Warnings:")+"\n\n"+warnings+_("\n\nDo you want to send the Article?") dialog=Dialog_YES_NO(message) do_send=dialog.resp else: do_send=True if do_send: references=self.references user_agent=self.VERSION output_charset=self.charset_combo.child.get_text() bounds=self.buffer.get_bounds() if bounds: start,stop=bounds text=self.buffer.get_text(start,stop,True).decode("utf-8") body=text.split("\n") else: body=[] mail_to_send=Mail_To_Send(to_name,from_name,date,subject,references,user_agent,output_charset,self.ordered_list,body) mail=mail_to_send.get_article() article_backup=dict() # this is needed for outbox/sent storing id_name=self.id_name for item in ["to_name","from_name","subject","references","user_agent","output_charset","body","date","id_name"]: article_backup[item]=eval(item) def _store_article(dirName,article_backup): try: out_files=os.listdir(dirName) except: self.statusbar.push(1,_("Problems while opening : ")+dirName) else: num=len(out_files) numbers=map(int,out_files) if not numbers:numbers=[-1] number=max((max(numbers),num)) f=open(os.path.join(dirName,str(number+1)),"wb") cPickle.dump(article_backup,f,1) f.close() if self.pathToArticle and not self.isSent: try: os.remove(os.path.join(self.wdir,self.pathToArticle)) except: pass self.destroy(None) if send_later: if isDraft: outDir="draft" else: outDir="outbox" _store_article(os.path.join(self.wdir,outDir,"mail"),article_backup) else: self.mailConnection=SMTPConnection(configs["smtp_server"],int(configs["smtp_port"]),configs["smtp_auth"],configs["smtp_username"],configs["smtp_password"]) message,mailSent=self.mailConnection.sendMail(from_name,to_name,mail) if not mailSent: self.statusbar.push(1,message) self.mailConnection.closeConnection() else: self.mailConnection.closeConnection() _store_article(os.path.join(self.wdir,"sent","mail"),article_backup) def update_position_and_cset(self,arg1=None,arg2=None,arg4=None): #getting the position pos_mark=self.buffer.get_insert() pos=self.buffer.get_iter_at_mark(pos_mark) line_number=pos.get_line() chars=pos.get_line_offset() #getting the encoding bounds=self.buffer.get_bounds() start,stop=bounds text=self.buffer.get_text(start,stop,True).decode("utf-8") for best_enc in self.ordered_list: try: text.encode(best_enc,"strict") except: pass else: break self.row_col_label.set_text(_("row:%d, col:%d") % (int(line_number),int(chars))) self.best_charset_label.set_text(best_enc) self.charset_combo.child.set_text(best_enc) def wrap_on_change(self,obj): def get_line_from_buffer(iter_start,buffer): chars_in_line=iter_start.get_chars_in_line()-1 if chars_in_line<0: chars_in_line=0 iter_end=iter_start.copy() iter_end.set_line_offset(chars_in_line) line=buffer.get_text(iter_start,iter_end,True).decode("utf-8") return line,iter_end,chars_in_line wrap=int(self.cp_id.get(self.id_name,"wrap")) pos_mark=self.buffer.get_insert() start=self.buffer.get_start_iter() #pos is cursor position pos=self.buffer.get_iter_at_mark(pos_mark) line_number=pos.get_line() #start is the beginning of the line edited start.set_line(line_number) line,end_line,line_length=get_line_from_buffer(start,self.buffer) if (line_length>wrap) and (" " in line) and (not line.startswith(">")): pos_start=start.copy() #pos_start is equal to end_line-1 pos_start.set_line_offset(wrap) char=self.buffer.get_text(pos_start,end_line,True).decode("utf-8") offset_before_wrap=self.buffer.get_iter_at_mark(self.buffer.get_insert()).get_offset() if char!=" ": success=False i=0 pos_end=pos_start.copy() while not success and i"): new_lines.append(new_line) end_line=new_line_end_iter else: break line_number=line_number+1 if new_lines: new_lines[0]=word+" "+new_lines[0] new_text=" ".join([line for line in new_lines]) new_text_wrapped="\n".join(self.wrap_line(new_text,wrap)) self.buffer.delete(pos_start,end_line) self.buffer.insert(pos_start,"\n"+new_text_wrapped.encode("utf-8")) iter_insert=self.buffer.get_iter_at_mark(self.buffer.get_insert()) iter_insert.set_offset(offset_before_wrap) self.buffer.place_cursor(iter_insert) else: self.buffer.delete(pos_start,end_line) self.buffer.insert(pos_start,"\n"+word.encode("utf-8")) else: i=i+1 else: self.buffer.delete(pos_start,end_line) self.buffer.insert(pos_start,"\n") self.update_position_and_cset() def insert_spoiler_char(self,obj): pos_mark=self.buffer.get_insert() pos=self.buffer.get_iter_at_mark(pos_mark) self.buffer.insert(pos,chr(12)) def clear_pane(self): start,end=self.buffer.get_bounds() self.buffer.delete(start,end) def save_sizes(self): try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"rb") except IOError: sizes={} else: sizes=cPickle.load(f) if not self.editwin_width: sizes["editwin_width"],sizes["editwin_height"]=self.win.get_size() else: sizes["editwin_width"]=self.editwin_width sizes["editwin_height"]=self.editwin_height sizes["editwin_pos_x"],sizes["editwin_pos_y"]=self.win.get_position() try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"wb") except IOError: pass else: cPickle.dump(sizes,f,1) f.close() def set_sizes(self): try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"rb") except IOError: self.win.maximize() else: sizes=cPickle.load(f) f.close() editwin_width=sizes.get("editwin_width",None) editwin_height=sizes.get("editwin_height",None) if editwin_width and editwin_height: self.win.resize(int(editwin_width),int(editwin_height)) else: self.win.maximize() editwin_pos_x=sizes.get("editwin_pos_x",None) editwin_pos_y=sizes.get("editwin_pos_y",None) if editwin_pos_x and editwin_pos_y: self.win.move(int(editwin_pos_x),int(editwin_pos_y)) def create_ui(self,configs): self.ui = gtk.UIManager() accelgroup = self.ui.get_accel_group() actiongroup= gtk.ActionGroup("EditMailWindowActions") self.win.add_accel_group(accelgroup) ecuts=load_shortcuts("edit") actions=[("Article",None,_("_Article")), ("send","xpn_send",_("_Send Article"),ecuts["send"],_("Send Article"),self.send_article,configs), ("send_later","xpn_send_queue",_("Send Article _Later"),ecuts["send_later"],_("Send Article Later"),self.send_article,configs,True), ("save_draft",gtk.STOCK_SAVE,_("Save Article as Draft"),ecuts["save_draft"],_("Save Article as Draft"),self.send_article,configs,True,True), ("discard","xpn_discard",_("_Discard Article"),ecuts["discard"],_("Discard Article"),self.destroy), ("rot13","xpn_rot13",_("_ROT13 Selected Text"),ecuts["rot13"],_("ROT13 Selected Text"),self.apply_rot13), ("editor","xpn_editor",_("Launch External _Editor"),ecuts["editor"],_("Launch External Editor"),self.external_editor,configs["editor_launcher"]), ("spoiler","xpn_spoiler_char",_("_Insert Spoiler Char"),ecuts["spoiler"],_("Insert Spoiler Char"),self.insert_spoiler_char)] for action in actions: if len(action)<7: actiongroup.add_actions([action]) else: actiongroup.add_actions([action[0:6]],action[6:]) self.ui.insert_action_group(actiongroup,0) merge_id = self.ui.add_ui_from_string(ui_string) def load_id(self): nick=self.cp_id.get(self.id_name,"nick").encode("utf-8") email=self.cp_id.get(self.id_name,"email").encode("utf-8") if self.cp_id.get(self.id_name,"use_mail_from")=="True": nick=self.cp_id.get(self.id_name,"mail_nick").encode("utf-8") if not nick: nick=self.cp_id.get(self.id_name,"nick").encode("utf-8") email=self.cp_id.get(self.id_name,"mail_email").encode("utf-8") if not email: email=self.cp_id.get(self.id_name,"email").encode("utf-8") else: nick=self.cp_id.get(self.id_name,"nick").encode("utf-8") email=self.cp_id.get(self.id_name,"email").encode("utf-8") nick=nick+" <"+email+">" self.from_entry.set_text(nick) def id_changed(self,obj,art): self.id_name=self.id_combo.get_active_text() self.load_id() start,end=self.buffer.get_bounds() body=self.buffer.get_text(start,end,True).decode("utf-8").split("\n") found=False #removing old sign i=0 for line in reversed(body): i=i+1 if line=="-- ": found=True break for x in range(i): body.pop() if not found: body=self.buffer.get_text(start,end,True).decode("utf-8").split("\n") #removing old sign found= False i=0 #removing old attribution line old_body=body[:] for line in body: if line==self.attr_line_splitted[-1]: found=True i=i+1 break i=i+1 for x in range(i): body.pop(0) if body[0]=="": body.pop(0) if not found: body=old_body start,end=self.buffer.get_bounds() self.buffer.delete(start,end) self.add_attribution_line(art) self.show_article(body) self.add_sign() def __init__(self,configs,to_name,article,selected_text,mode="Normal",draft_article=None,pathToArticle="",outboxManager=None,isSent=False,id_name=""): self.pathToArticle=pathToArticle self.mode=mode self.outboxManager=outboxManager self.isSent=isSent self.id_name=id_name.encode("utf-8") self.wdir=get_wdir() self.fallback_charset=configs["fallback_charset"] self.win=gtk.Window(gtk.WINDOW_TOPLEVEL) self.win.connect("delete_event",self.delete_event) self.win.set_title(_("Edit Mail")) self.win.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/reply.xpm")) #main_vbox main_vbox=gtk.VBox() self.win.add(main_vbox) self.create_ui(configs) menubar=self.ui.get_widget("/EditMenuBar") main_vbox.pack_start(menubar,False,True,0) menubar.show() toolbar=self.ui.get_widget("/EditToolBar") main_vbox.pack_start(toolbar,False,True,0) toolbar.show() #toolbar.set_icon_size(gtk.ICON_SIZE_LARGE_TOOLBAR) toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) toolbar.set_style(gtk.TOOLBAR_ICONS) toolbar.set_style(gtk.SHADOW_NONE) id_label=gtk.Label(""+_("Identity")+"") id_label.set_alignment(0,0.5) id_label.set_use_markup(True) id_hbox=gtk.HBox() self.id_combo=gtk.combo_box_new_text() self.cp_id=ConfigParser.ConfigParser() self.cp_id.read(os.path.join(get_wdir(),"dats","id.txt")) positions=dict() i=0 for id in self.cp_id.sections(): self.id_combo.append_text(id) positions[id]=i i=i+1 if self.id_name: self.id_combo.set_active(positions[self.id_name]) else: self.id_combo.set_active(0) self.id_name=self.id_combo.get_active_text() id_sep=gtk.VSeparator() id_hbox.pack_start(id_label,False,True,4) id_hbox.pack_start(self.id_combo,False,True,4) id_hbox.pack_start(id_sep,False,False,4) main_vbox.pack_start(id_hbox,False,True,2) self.headers_table=gtk.Table(3,2,False) self.headers_table.set_border_width(2) self.to_name_label=gtk.Label(""+_("To : ")+"") self.to_name_label.set_use_markup(True) self.to_name_label.set_alignment(1,0.5) self.from_label=gtk.Label(""+_("From : ")+"") self.from_label.set_use_markup(True) self.from_label.set_alignment(1,0.5) self.subj_label=gtk.Label(""+_("Subject : ")+"") self.subj_label.set_use_markup(True) self.subj_label.set_alignment(1,0.5) self.charset_label=gtk.Label(""+_("Charset : ")+"") self.charset_label.set_use_markup(True) self.charset_label.set_alignment(1,0.5) self.to_name_entry=gtk.Entry() self.from_entry=gtk.Entry() self.subj_entry=gtk.Entry() self.charset_combo=gtk.combo_box_entry_new_text() for encoding in encodings_list: self.charset_combo.append_text(encoding) self.charset_tooltip=gtk.Tooltips() self.charset_tooltip.set_tip(self.charset_combo.child,encodings_tip) self.charset_combo.child.set_editable(False) self.headers_table.attach(self.to_name_label,0,1,0,1,gtk.FILL,gtk.FILL) self.headers_table.attach(self.from_label,0,1,1,2,gtk.FILL,gtk.FILL) self.headers_table.attach(self.subj_label,0,1,2,3,gtk.FILL,gtk.FILL) self.headers_table.attach(self.to_name_entry,1,2,0,1) self.headers_table.attach(self.from_entry,1,2,1,2) self.headers_table.attach(self.subj_entry,1,2,2,3) self.headers_table.attach(self.charset_label,0,1,3,4,gtk.FILL,gtk.FILL) self.headers_table.attach(self.charset_combo,1,2,3,4) #buffer self.buffer=gtk.TextBuffer() self.quote1_tag=None self.quote2_tag=None self.quote3_tag=None self.sign_tag=None self.text_tag=None color=configs["text_color"] self.set_text_color(color) color=configs["quote1_color"] self.set_quote_color(color,1) color=configs["quote2_color"] self.set_quote_color(color,2) color=configs["quote3_color"] self.set_quote_color(color,3) color=configs["sign_color"] self.set_sign_color(color) #TextView text_scrolledwin=gtk.ScrolledWindow() text_scrolledwin.set_border_width(2) text_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) text_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.textview=gtk.TextView(self.buffer) self.textview.set_wrap_mode(gtk.WRAP_WORD) self.textview.set_indent(4) text_scrolledwin.add(self.textview) self.text_vbox=gtk.VBox() self.text_vbox.pack_start(self.headers_table,False,False) self.text_vbox.pack_start(text_scrolledwin,True,True) main_vbox.pack_start(self.text_vbox,True,True,0) #statusbar statusbar_hbox=gtk.HBox() statusbar_hbox.set_border_width(2) self.row_col_label=gtk.Label() vsep=gtk.VSeparator() vsep2=gtk.VSeparator() self.best_charset_label=gtk.Label() self.statusbar=gtk.Statusbar() statusbar_hbox.pack_start(self.row_col_label,False,True,2) statusbar_hbox.pack_start(vsep,False,False,2) statusbar_hbox.pack_start(self.best_charset_label,False,True,2) statusbar_hbox.pack_start(vsep2,False,False,2) statusbar_hbox.pack_start(self.statusbar,True,True,2) main_vbox.pack_start(statusbar_hbox,False,False,0) #some updates self.ordered_list=load_ordered_list() self.references="" self.update_to_name_entry(to_name) self.mark_set_handler=self.buffer.connect("mark_set",self.update_position_and_cset) if mode=="Normal": self.update_subject_entry(article.subj) self.references=self.update_references(article.ref+" "+article.msgid) self.add_attribution_line(article) self.update_body(article,selected_text) start,insert_point=self.buffer.get_bounds() self.buffer.create_mark("insert_point_after_text",insert_point,True) self.add_sign() self.buffer.connect("changed",self.wrap_on_change) if selected_text==None: insert_pos=self.buffer.get_iter_at_mark(self.buffer.get_mark("insert_point")) else: insert_pos=self.buffer.get_iter_at_mark(self.buffer.get_mark("insert_point_after_text")) self.buffer.place_cursor(insert_pos) if mode=="Draft": self.from_entry.set_text(draft_article.get("from_name","").encode("utf-8")) self.subj_entry.set_text(draft_article.get("subject","").encode("utf-8")) self.clear_pane() self.show_article([line.encode("utf-8") for line in draft_article.get("body","")]) self.references=self.update_references(draft_article.get("references","")) self.set_background(configs) self.set_foreground(configs) self.update_position_and_cset() if configs["external_editor"]=="True": self.external_editor(None,configs["editor_launcher"]) self.set_sizes() self.editwin_width=None self.editwin_height=None self.textview.modify_font(pango.FontDescription(configs["font_name"])) self.load_id() self.id_combo.connect("changed",self.id_changed,article) xpn-1.2.6/xpn_src/Connections_Handler.py0000644000175000017500000006041511141275756016437 0ustar antantimport nntplib import xpn_src.nntplib_ssl as nntplib_ssl import smtplib import sys import time import StringIO import os from urllib import quote as url_quote from xpn_src.UserDir import get_wdir def my_xover(self,start,end): """Process an XOVER command (optional server extension) Arguments: - start: start of range - end: end of range Returns: - resp: server response if successful - list: list of (art-nr, subject, poster, date, id, references, size, lines,xref)""" resp, lines = self.longcmd('XOVER ' + start + '-' + end) xover_lines = [] for line in lines: elem = line.split("\t") try: xover_lines.append((elem[0], elem[1], elem[2], elem[3], elem[4], elem[5], elem[6], elem[7], elem[8])) except IndexError: raise nntplib.NNTPDataError(line) return resp,xover_lines class Connection: '''This class wraps an nntp connection. It has two types of methods, user-level methods and class-level methodos. The user is intended to use only user-level methods that astract nntp operation at a higher lever. Class-level methods are used internally also to implement user-level methods. User-level methods are: closeConnection, getBody, getHeaders, getXHDRHeaders, sendArticle Class-level methods are:__init__, _isUp, _tryConnection, _addLog, _enterGroup Attributes: serverConnection : it is None or an nntplib.NNTP instance representing the connection with the server serverAddress : server address serverPort : port number requireAuthentication: True if server requires authentication username : username for the server password : password for the server groupEntered : the group we sent the command GROUP for ''' def __init__(self,serverAddress,serverPort=119,requireAuthentication=False,username="",password=""): '''Class constructor''' self.serverConnection = None # when there is no connection with the server this attribute # should be None self.serverAddress = serverAddress self.serverPort = int(serverPort) self.requireAuthentication = requireAuthentication self.username = username self.password = password self.groupEntered= "" nntplib.NNTP.my_xover=my_xover def reInit(self,serverAddress,serverPort=119,requireAuthentication=False,username="",password=""): '''Reset the class attributes. It is useful when you change some attributes like server name and don't want to create a new object ''' self.closeConnection() self.__init__(serverAddress,serverPort,requireAuthentication,username,password) def _isUp(self): '''Return the state of the connection.''' return self.serverConnection!=None def closeConnection(self): ''' Close connection and add a log of the operation.''' if self._isUp(): self._addLog("QUIT",True) try: message=self.serverConnection.quit() except : message=str(sys.exc_info()[0])+","+str(sys.exc_info()[1]) self.serverConnection=None self._addLog(message,False) def _addLog(self,message,is_command): ''' Adds an entry in server_logs.dat. Arguments: message : is the entry to add is_command : if it is True we are adding a message sent to the server, else we are adding a message received from the server ''' try: f=open(os.path.join(get_wdir(),"server_logs.dat"),"a") except IOError: pass else: if is_command: f.write(time.ctime(time.time())+" :: >> "+message+"\n") else: f.write(time.ctime(time.time())+" :: << "+message+"\n") f.close() def _tryConnection(self): '''Tries to estabilish a connection with the server or check if it is still up. If self.serverConnection is None must set-up a new connection, else the connection could be still up, test it, and if it is down try to estabilish a new connection. Return: message : you can use it to interact with the user. isUp : a boolean indicating the state of the connection ''' if self.serverConnection==None: #we must set-up a new connection self.groupEntered="" try: if self.requireAuthentication=="True": self._addLog("AUTHINFO USER "+self.username,True) self._addLog("AUTHINFO PASS "+"".join(["*" for i in self.password]),True) self._addLog("MODE READER",True) self.serverConnection=nntplib.NNTP(self.serverAddress,port=self.serverPort,user=self.username,password=self.password,readermode=True) except : message=_("No connection with server : %s. Configure NNTP Server Address or try later.") % (self.serverAddress,) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) self.serverConnection=None else: message=_("Connection estabilished with server: %s") % (self.serverAddress,) self._addLog(self.serverConnection.getwelcome(),False) return message, self._isUp() else: #the connection probably is still up, let's test it try: # I use stat only to test if the connection is still up #self.serverConnection.stat("<>") # this stat seems to cause some problems to Hamster. #self.serverConnection.stat("") self.serverConnection.date() #devo vedere come risponde dopo il timeout except nntplib.NNTPPermanentError: # the connection is broken, I try to estabilish a new connection self.serverConnection=None message,isUp=self._tryConnection() return message,isUp #except nntplib.NNTPTemporaryError: # This exception is raised because the article <> doesn't exist # I haven't to do anything # return "",True except : #This is another type of exception, however we have problems with server message=_("No connection with server : %s. Configure NNTP Server Address or try later.") % (self.serverAddress,) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) self.serverConnection=None message,isUp=self._tryConnection() return message,isUp else: #the connection is active return "",True def _enterGroup(self,group,force=False): ''' Send GROUP command if it is needed. Arguments: group : the group to enter force : if force is True GROUP command is always sent Return: message : it can be used to interact with the user first : first article in group last : last article in group ''' message,connectionIsUp=self._tryConnection() first=0 last=0 if connectionIsUp: if group!=self.groupEntered or force: #we have to send group command try: self._addLog("GROUP "+group,True) resp,count,first,last,name=self.serverConnection.group(group) except : message=_("Server error: %s") % (str(sys.exc_info()[1]),) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) else: message=_("%s response : %s") % (self.serverAddress,resp) self._addLog(resp,False) self.groupEntered=group return message,first,last def getArticleNumber(self,group,msgid): '''Return the article number using the message-id to query the server''' number=-1 header_list=[] message,first,last=self._enterGroup(group) if self._isUp(): try: resp,number,msgid,header_list=self.serverConnection.head(msgid) except : message=_("Server error: %s") % (str(sys.exc_info()[1]),) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) else: message=_("%s response : %s") % (self.serverAddress,resp) self._addLog(resp,False) if int(number)==0: #some servers send a 0 when called with the message-id for header in header_list: if header.lower().startswith("xref:"): try: number=int(header.split(group+":")[1].split()[0].strip()) except : number= -1 return message,int(number) def getBody(self,number,msgid,group): '''Retrieve the body of the article. First need to enter the group, then retrieve with an HEAD the command the headers list and then retrieve the body. Arguments: number : article number msgid : article message-id group : the group the article is in Return: message : it can be used to interact with the user headerList : the headers list, XPN uses it with xpn_src.Article.parse_header_list rawBody : the body retrieved (or phantom article). XPN uses it with xpn_src.Article.set_body (not in the case it is the phantom article) bodyRetrieved : True if the bosy has been successfully retrieved from the server (so rawBody isn't [] or phantom article) ''' bodyRetrieved=False headerList=[] rawBody=[] message,first,last=self._enterGroup(group) if self._isUp(): try: self._addLog("ARTICLE "+number,True) resp,number,id,rawBody=self.serverConnection.article(number) except nntplib.NNTPTemporaryError: message=_("Server error: %s") % (str(sys.exc_info()[1]),) if str(sys.exc_info()[1])[:1]=="4": #article is not on the server, we use a phantom article link=r"http://groups.google.com/groups?selm="+url_quote(msgid[1:-1]) rawBody=(_("Server Error: ")+str(sys.exc_info()[1]),"",_("You can try on Google:"),"",link) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) except : #every other type of errors message=_("Server error: %s") % (str(sys.exc_info()[1]),) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) else: self._addLog(resp,False) message=_("%s response : %s") % (self.serverAddress,resp) ind=rawBody.index("") headerList=rawBody[:ind] rawBody=rawBody[ind+1:] bodyRetrieved=True return message,headerList,rawBody,bodyRetrieved def getHeaders(self,group,first,last=None,count=None): '''Retrieve Headers in a given range. Arguments: group : the group to download the headers for first : the first article to consider last : tha last article to consider, if it is None last will be the last article on group count : the number of article to headers, the 'count' newest headers will be downloaded. If you are subscribing the group, first=0 and then it is ignored. If you also pass the 'last' argument 'count' will be ignored Return: message : it can be used to interact with the user headersList : a list of lists, every element is a list containing the headers of an article lastOnServer : last number on server ''' headersList=[] lastOnServer=-1 message,group_first,group_last=self._enterGroup(group,True) argumentLast=last if not last: last=group_last if count and not argumentLast: first,last=max(int(group_last)-count+1,first),group_last if first<0: first=0 if int(first)<=int(last): if self._isUp(): try: self._addLog("XOVER "+str(first)+"-"+str(last),True) resp,headersList=self.serverConnection.my_xover(str(first),str(last)) except : message=_("Server error: %s") % (str(sys.exc_info()[1]),) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) else: lastOnServer=int(group_last) message=_("%s response : %s") % (self.serverAddress,resp) self._addLog(resp,False) return message,headersList,lastOnServer def getXHDRHeaders(self,group,headerName,first,last=None,count=None): '''Retrieve a given Header in a given range. Arguments: group : the group to download the headers for headerName: the header to download first : the first article to consider last : tha last article to consider, if it is None last will be the last article on group count : the number of article to headers, the 'count' newest headers will be downloaded, 'first' is ignored in this case. If you also pass the 'last' argument 'count' will be ignored Return: message : it can be used to interact with the user headerList : a list of the header values ''' headerList=[] lastOnServer=-1 message,group_first,group_last=self._enterGroup(group,True) argumentLast=last if not last: last=group_last if count and not argumentLast: first,last=int(group_last)-count+1,group_last if first<0: first=0 if int(first)<=int(last): if self._isUp(): try: self._addLog("XHDR "+headerName+" "+str(first)+"-"+str(last),True) resp,headerList=self.serverConnection.xhdr(headerName,str(first)+"-"+str(last)) except : message=_("Server error: %s") % (str(sys.exc_info()[1]),) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) else: lastOnServer=int(group_last) message=_("%s response : %s") % (self.serverAddress,resp) self._addLog(resp,False) return message,headerList def sendArticle(self,article): '''Send an article to the Server. Arguments: article : a string representing a well-formed usenet article Returns: message : it can be used to interact with the user articlePosted : True if the article was correctly sent ''' message,connectionIsUp=self._tryConnection() articlePosted=False if connectionIsUp: fileArticle=StringIO.StringIO(article) try: self._addLog("POST", True) resp=self.serverConnection.post(fileArticle) except : message=_("Server error: %s") % (str(sys.exc_info()[1]),) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) fileArticle.close() else: fileArticle.close() self._addLog(resp,False) message=_("%s response : %s") % (self.serverAddress,resp) articlePosted=True return message,articlePosted class SSLConnection(Connection): def __init__(self,serverAddress,serverPort=563,requireAuthentication=False,username="",password=""): '''Class constructor''' self.serverConnection = None # when there is no connection with the server this attribute # should be None self.serverAddress = serverAddress self.serverPort = int(serverPort) self.requireAuthentication = requireAuthentication self.username = username self.password = password self.groupEntered= "" nntplib_ssl.NNTP_SSL.my_xover=my_xover def reInit(self,serverAddress,serverPort=563,requireAuthentication=False,username="",password=""): '''Reset the class attributes. It is useful when you change some attributes like server name and don't want to create a new object ''' self.closeConnection() self.__init__(serverAddress,serverPort,requireAuthentication,username,password) def _tryConnection(self): '''Tries to estabilish a connection with the server or check if it is still up. If self.serverConnection is None must set-up a new connection, else the connection could be still up, test it, and if it is down try to estabilish a new connection. Return: message : you can use it to interact with the user. isUp : a boolean indicating the state of the connection ''' if self.serverConnection==None: #we must set-up a new connection self.groupEntered="" try: if self.requireAuthentication=="True": self._addLog("AUTHINFO USER "+self.username,True) self._addLog("AUTHINFO PASS "+"".join(["*" for i in self.password]),True) self._addLog("MODE READER",True) self.serverConnection=nntplib_ssl.NNTP_SSL(self.serverAddress,port=self.serverPort,user=self.username,password=self.password,readermode=True) except : message=_("No connection with server : %s. Configure NNTP Server Address or try later.") % (self.serverAddress,) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) self.serverConnection=None else: message=_("Connection estabilished with server: %s") % (self.serverAddress,) self._addLog(self.serverConnection.getwelcome(),False) return message, self._isUp() else: #the connection probably is still up, let's test it try: # I use stat only to test if the connection is still up #self.serverConnection.stat("<>") # this stat seems to cause some problems to Hamster. self.serverConnection.stat("") except nntplib.NNTPPermanentError: # the connection is broken, I try to estabilish a new connection self.serverConnection=None message,isUp=self._tryConnection() return message,isUp except nntplib.NNTPTemporaryError: # This exception is raised because the article <> doesn't exist # I haven't to do anything return "",True except : #This is another type of exception, however we have problems with server message=_("No connection with server : %s. Configure NNTP Server Address or try later.") % (self.serverAddress,) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) self.serverConnection=None message,isUp=self._tryConnection() return message,isUp else: #This is only a fallback this leaf shouldn't never be reached return "",True class SMTPConnection: '''This class wraps an SMTP Connection''' def __init__(self,serverAddress,serverPort=25,requireAuthentication=False,username="",password=""): self.serverConnection = None # when there is no connection with the server this attribute # should be None self.serverAddress = serverAddress self.serverPort = int(serverPort) self.requireAuthentication = requireAuthentication self.username = username self.password = password def reInit(self,serverAddress,serverPort=25,requireAuthentication=False,username="",password=""): '''Reset the class attributes. It is useful when you change some attributes like server name and don't want to create a new object ''' self.closeConnection() self.__init__(serverAddress,serverPort,requireAuthentication,username,password) def _isUp(self): '''Return the state of the connection.''' return self.serverConnection!=None def closeConnection(self): ''' Close connection and add a log of the operation.''' if self._isUp(): self._addLog("QUIT",True) try: self.serverConnection.quit() except : message=str(sys.exc_info()[0])+","+str(sys.exc_info()[1]) else: message=_("Connection closed") self.serverConnection=None self._addLog(message,False) def _addLog(self,message,is_command): ''' Adds an entry in server_logs.dat. Arguments: message : is the entry to add is_command : if it is True we are adding a message sent to the server, else we are adding a message received from the server ''' try: f=open(os.path.join(get_wdir(),"server_logs.dat"),"a") except IOError: pass else: if is_command: f.write(time.ctime(time.time())+" ::[SMTP] >> "+message+"\n") else: f.write(time.ctime(time.time())+" ::[SMTP] << "+message+"\n") f.close() def _tryConnection(self): '''Tries to estabilish a connection with the server or check if it is still up. If self.serverConnection is None must set-up a new connection, else the connection could be still up, test it, and if it is down try to estabilish a new connection. Return: message : you can use it to interact with the user. isUp : a boolean indicating the state of the connection''' message="" if self.serverConnection==None: try: self.serverConnection = smtplib.SMTP(self.serverAddress,self.serverPort) if self.requireAuthentication=="True": self._addLog("LOGIN "+self.username+" "+"".join(["*" for i in self.password]),True) self.serverConnection.login(self.username,self.password) except: message=_("No connection with server : %s. Configure SMTP Server Address or try later.") % (self.serverAddress,) self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) self.serverConnection=None else: message=_("Connection estabilished with: %s") % (self.serverAddress,) self._addLog(message,False) return message,self._isUp() def sendMail(self,from_name,to_name,mail): ''' Send a well formed Email. Arguments: from_name: sender address to_name : destination address mail : a well formed e-mail Return: message : you can use it to interact with the user. mailSent : True if the mail was correctly sent''' message,connectionIsUp=self._tryConnection() mailSent=False if connectionIsUp: try: self._addLog("SENDMAIL",True) self.serverConnection.sendmail(from_name,to_name,mail) except: message=_("Unable to send the message. Control Server Logs.") self._addLog(str(sys.exc_info()[0])+","+str(sys.exc_info()[1]),False) else: message=_("Email Sent") self._addLog(message,False) mailSent=True return message,mailSent xpn-1.2.6/xpn_src/nntplib_ssl.py0000755000175000017500000001242111141275756015044 0ustar antantimport nntplib import re import socket NNTP_SSL_PORT = 563 CRLF = '\r\n' class NNTP_SSL(nntplib.NNTP): """NNTP client class over SSL connection Instantiate with: NNTP_SSL(hostname, port=NNTP_SSL_PORT, user=None, password=None, readermode=None, usenetrc=True, keyfile=None, certfile=None) - host: hostname to connect to - port: port to connect to (default the standard NNTP port) - user: username to authenticate with - password: password to use with username - readermode: if true, send 'mode reader' command after connecting. - keyfile: PEM formatted file that contains your private key - certfile: PEM formatted certificate chain file See the methods of the parent class NNTP for more documentation. """ def __init__(self, host, port = NNTP_SSL_PORT, user=None, password=None, readermode=None, usenetrc=True, keyfile = None, certfile = None): self.host = host self.port = port self.keyfile = keyfile self.certfile = certfile self.buffer = "" msg = "getaddrinfo returns an empty list" self.sock = None for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM): af, socktype, proto, canonname, sa = res try: self.sock = socket.socket(af, socktype, proto) self.sock.connect(sa) except socket.error, msg: if self.sock: self.sock.close() self.sock = None continue break if not self.sock: raise socket.error, msg self.file = self.sock.makefile('rb') try: socket.ssl except AttributeError: self.sslobj=None else: self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile) self.debugging = 0 self.welcome = self.getresp() # 'mode reader' is sometimes necessary to enable 'reader' mode. # However, the order in which 'mode reader' and 'authinfo' need to # arrive differs between some NNTP servers. Try to send # 'mode reader', and if it fails with an authorization failed # error, try again after sending authinfo. readermode_afterauth = 0 if readermode: try: self.welcome = self.shortcmd('mode reader') except NNTPPermanentError: # error 500, probably 'not implemented' pass except NNTPTemporaryError, e: if user and e.response[:3] == '480': # Need authorization before 'mode reader' readermode_afterauth = 1 else: raise # If no login/password was specified, try to get them from ~/.netrc # Presume that if .netc has an entry, NNRP authentication is required. try: if usenetrc and not user: import netrc credentials = netrc.netrc() auth = credentials.authenticators(host) if auth: user = auth[0] password = auth[2] except IOError: pass # Perform NNRP authentication if needed. if user: resp = self.shortcmd('authinfo user '+user) if resp[:3] == '381': if not password: raise NNTPReplyError(resp) else: resp = self.shortcmd( 'authinfo pass '+password) if resp[:3] != '281': raise NNTPPermanentError(resp) if readermode_afterauth: try: self.welcome = self.shortcmd('mode reader') except NNTPPermanentError: # error 500, probably 'not implemented' pass def _fillBuffer(self): localbuf = self.sslobj.read() if len(localbuf) == 0: raise error_proto('-ERR EOF') self.buffer += localbuf def getline(self): line = "" renewline = re.compile(r'.*?\n') match = renewline.match(self.buffer) while not match: self._fillBuffer() match = renewline.match(self.buffer) line = match.group(0) self.buffer = renewline.sub('' ,self.buffer, 1) if self.debugging > 1: print '*get*', repr(line) if not line: raise EOFError if line[-2:] == CRLF: line = line[:-2] elif line[-1:] in CRLF: line = line[:-1] return line def putline(self, line): if self.debugging > 1: print '*put*', repr(line) line += CRLF bytes = len(line) while bytes > 0: sent = self.sslobj.write(line) if sent == bytes: break # avoid copy line = line[sent:] bytes = bytes - sent def quit(self): """Process a QUIT command and close the socket. Returns: - resp: server response if successful""" try: resp = self.shortcmd('QUIT') except error_proto, val: resp = val self.sock.close() del self.sslobj, self.sock return resp xpn-1.2.6/xpn_src/Threads_Pane.py0000644000175000017500000003404711141275756015057 0ustar antantimport gtk import gobject import pango import cPickle import os from xpn_src.UserDir import get_wdir class Threads_Pane: def get_widget(self): return self.scrolledwin def unparent(self): self.scrolledwin.unparent() def show(self): self.scrolledwin.show_all() def hide(self): self.scrolledwin.hide_all() def clear(self): model=self.threads_tree.get_model() model.clear() def set_background(self,color): color=gtk.gdk.color_parse(color) self.threads_tree.modify_base(gtk.STATE_NORMAL,color) def set_foreground(self,color): color=gtk.gdk.color_parse(color) self.threads_tree.modify_text(gtk.STATE_NORMAL,color) self.threads_tree.modify_fg(gtk.STATE_NORMAL,color) def delete_row(self,model,iter): model.remove(iter) def insert(self,model,iter_parent,iter_sibling,values): iter=model.insert_before(iter_parent,iter_sibling) if values[5]: values[5]=pango.WEIGHT_BOLD else :values[5]= pango.WEIGHT_NORMAL if len(values)==19: #quando cerco l'articolo padre non passo tutte le info if values[18]: values[18]=pango.UNDERLINE_SINGLE else :values[18]= pango.UNDERLINE_NONE for i in range(len(values)): if i==1 or i==2 or i==3: value=values[i].encode("utf-8") else: value=values[i] model.set_value(iter,i,value) return iter def get_subject(self,model,article_iter): return model.get_value(article_iter,1) def get_article(self,model,article_iter): return model.get_value(article_iter,4) def set_article(self,model,article_iter,article): model.set_value(article_iter,4,article) def get_unread_in_thread(self,model,article_iter): return model.get_value(article_iter,12) def get_watched_in_thread(self,model,article_iter): return model.get_value(article_iter,19) def get_watched_unread_in_thread(self,model,article_iter): return model.get_value(article_iter,20) def set_unread_in_thread(self,model,article_iter,unread_in_thread): model.set_value(article_iter,12,unread_in_thread) def set_watched_in_thread(self,model,article_iter,watched_in_thread): model.set_value(article_iter,19,watched_in_thread) def set_watched_unread_in_thread(self,model,article_iter,watched_unread_in_thread): model.set_value(article_iter,20,watched_unread_in_thread) model.set_value(article_iter,18,watched_unread_in_thread!=0) def set_unread_in_thread_visible(self,model,article_iter,unread_in_thread_visible): model.set_value(article_iter,13,unread_in_thread_visible) def update_unread_in_thread(self,is_read,show_threads,insert): if show_threads and ((is_read and insert) or (not is_read and not insert)): model,iter_selected=self.threads_tree.get_selection().get_selected() parent_path=tuple([model.get_path(iter_selected)[0],]) parent_iter=model.get_iter(parent_path) unread_in_thread=self.get_unread_in_thread(model,parent_iter) if insert: unread_in_thread=unread_in_thread+1 else: unread_in_thread=unread_in_thread-1 self.set_unread_in_thread(model,parent_iter,unread_in_thread) self.set_unread_in_thread_visible(model,parent_iter,unread_in_thread!=0) def update_watched_in_thread(self,is_watched,show_threads,insert): if show_threads and ((is_watched and insert) or (not is_watched and not insert)): model,iter_selected=self.threads_tree.get_selection().get_selected() parent_path=tuple([model.get_path(iter_selected)[0],]) parent_iter=model.get_iter(parent_path) watched_in_thread=self.get_watched_in_thread(model,parent_iter) if insert: watched_in_thread=watched_in_thread+1 else: watched_in_thread=watched_in_thread-1 self.set_watched_in_thread(model,parent_iter,watched_in_thread) def update_watched_unread_in_thread(self,is_read,is_watched,show_threads,insert_in_unreads,insert_in_watched,updating_unreads): print is_read,is_watched,show_threads,insert_in_unreads,insert_in_watched,updating_unreads inserting=((is_read and insert_in_unreads) and is_watched) or ((is_watched and insert_in_watched) and not is_read and not updating_unreads) removing=((not is_read and not insert_in_unreads) and is_watched) or ((not is_watched and not insert_in_watched) and not is_read and not updating_unreads) if show_threads and (inserting or removing): model,iter_selected=self.threads_tree.get_selection().get_selected() parent_path=tuple([model.get_path(iter_selected)[0],]) parent_iter=model.get_iter(parent_path) watched_unread_in_thread=self.get_watched_unread_in_thread(model,parent_iter) print "BEFORE:",watched_unread_in_thread if inserting: watched_unread_in_thread=watched_unread_in_thread+1 else: watched_unread_in_thread=watched_unread_in_thread-1 print "AFTER:",watched_unread_in_thread self.set_watched_unread_in_thread(model,parent_iter,watched_unread_in_thread) def get_is_unread(self,model,article_iter): return model.get_value(article_iter,5)==pango.WEIGHT_BOLD def set_is_unread(self,model,article_iter,is_unread): if is_unread: weight=pango.WEIGHT_BOLD else: weight=pango.WEIGHT_NORMAL model.set_value(article_iter,5,weight) def new_model(self): #MODEL: 0 Icon, 1 Subject, 2 From, 3 Date, 4 XPN_article, 5 Use_Bold, 6 Seconds, 7 Score, 8 Score_Foreground, # 9 Score_Visible, 10 Icon2, 11 Icon3, 12 Unread_In_Thread, 13 Unread_Visible, 14 Article_FG_Set, 15 Article_FG # 16 Article_BG_Set,17 Article_BG, 18 Use_Underline, 19 Watched_In_Thread, Watched_Unread_in_Thread model=gtk.TreeStore(gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT,gobject.TYPE_INT,gobject.TYPE_INT,gobject.TYPE_INT,gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gtk.gdk.Pixbuf, gtk.gdk.Pixbuf,gobject.TYPE_INT,gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_STRING,gobject.TYPE_BOOLEAN,gobject.TYPE_INT,gobject.TYPE_INT) return model def set_model(self,model): self.threads_tree.set_model(model) def find_next_row(self,model,current_iter): if model.iter_has_child(current_iter): next_iter = model.iter_children(current_iter) else: next_iter=model.iter_next(current_iter) while not next_iter: prev_iter=model.iter_parent(current_iter) current_iter=prev_iter if not prev_iter: break next_iter=model.iter_next(current_iter) return next_iter def find_previous_row(self,model,current_iter): path=model.get_path(current_iter) new_path=[path[i] for i in xrange(len(path)-1)] if path[len(path)-1]>0: new_path.append(path[len(path)-1]-1) new_path=tuple(new_path) if new_path: prev_iter = model.get_iter(new_path) return prev_iter else: return current_iter def update_article_icon(self,name,iter_row=None): model,iter_selected=self.threads_tree.get_selection().get_selected() if iter_row: iter_selected=iter_row current_icon=model.get_value(iter_selected,0) current_icon2=model.get_value(iter_selected,10) current_icon3=model.get_value(iter_selected,11) icon=current_icon icon2=current_icon2 icon3=current_icon3 if name=="read": if current_icon!=self.art_fup: icon=self.art_read else: icon=self.art_fup elif name=="fup": icon=self.art_fup elif name=="unread": icon=self.art_unread elif name=="download": icon=self.art_mark elif name=="body": icon=self.art_body elif name=="keep": icon2=self.art_keep elif name=="unkeep": icon2=self.art_unkeep elif name=="watch": icon3=self.art_watch elif name=="unwatchignore": icon3=self.art_unwatchignore elif name=="ignore": icon3=self.art_ignore model.set_value(iter_selected,0,icon) model.set_value(iter_selected,10,icon2) model.set_value(iter_selected,11,icon3) def get_subthread(self,iter_parent,model,iter_list): '''Return the list of iters in the subthread without the father''' if model.iter_has_child(iter_parent): number=model.iter_n_children(iter_parent) for i in xrange(number): iter_child=model.iter_nth_child(iter_parent,i) self.get_subthread(iter_child,model,iter_list) iter_list.append(iter_child) return iter_list def __init__(self,configs): self.art_unread=gtk.gdk.pixbuf_new_from_file("pixmaps/art_unread.xpm") self.art_read=gtk.gdk.pixbuf_new_from_file("pixmaps/art_read.xpm") self.art_fup=gtk.gdk.pixbuf_new_from_file("pixmaps/art_fup.xpm") self.art_mark=gtk.gdk.pixbuf_new_from_file("pixmaps/art_mark.xpm") self.art_body=gtk.gdk.pixbuf_new_from_file("pixmaps/art_body.xpm") self.art_keep=gtk.gdk.pixbuf_new_from_file("pixmaps/art_keep.xpm") self.art_unkeep=gtk.gdk.pixbuf_new_from_file("pixmaps/art_unkeep.xpm") self.art_watch=gtk.gdk.pixbuf_new_from_file("pixmaps/art_watch.xpm") self.art_unwatchignore=gtk.gdk.pixbuf_new_from_file("pixmaps/art_unwatchignore.xpm") self.art_ignore=gtk.gdk.pixbuf_new_from_file("pixmaps/art_ignore.xpm") #ThreadsScrolledWin self.scrolledwin=gtk.ScrolledWindow() self.scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) try: f=open(os.path.join(get_wdir(),"dats/sizes.dat"),"rb") except IOError: column1_width=41 column2_width=415 column3_width=201 column4_width=95 column5_width=60 else: sizes=cPickle.load(f) f.close() column1_width=sizes.get("threads_col_status",41) column2_width=sizes.get("threads_col_subject",415) column3_width=sizes.get("threads_col_from",201) column4_width=sizes.get("threads_col_date",95) column5_width=sizes.get("threads_col_score",60) #ThreadsTree self.threads_tree=gtk.TreeView() model=self.new_model() self.set_model(model) pix_renderer=gtk.CellRendererPixbuf() pix_renderer2=gtk.CellRendererPixbuf() pix_renderer3=gtk.CellRendererPixbuf() text_renderer=gtk.CellRendererText() text_renderer_unread=gtk.CellRendererText() text_renderer_unread.set_property("xalign",1) #text_renderer.set_property("weight",1000) text_renderer_score=gtk.CellRendererText() text_renderer_score.set_property("xalign",.5) self.column1=gtk.TreeViewColumn("Status") self.column1.pack_start(pix_renderer,False) self.column1.pack_start(pix_renderer2,False) self.column1.pack_start(pix_renderer3,False) self.column1.pack_start(text_renderer_unread,False) self.column1.set_attributes(pix_renderer,pixbuf=0) self.column1.set_attributes(pix_renderer2,pixbuf=10) self.column1.set_attributes(pix_renderer3,pixbuf=11) self.column1.set_attributes(text_renderer_unread,text=12,visible=13) self.column2=gtk.TreeViewColumn(_("Subject"),text_renderer,text=1,weight=5,foreground_set=14,foreground=15,background_set=16,background=17,underline=18) self.column3=gtk.TreeViewColumn(_("From"),text_renderer,text=2,weight=5,foreground_set=14,foreground=15,background_set=16,background=17) self.column4=gtk.TreeViewColumn(_("Date"),text_renderer,text=3,weight=5,foreground_set=14,foreground=15,background_set=16,background=17) self.column5=gtk.TreeViewColumn(_("Score"),text_renderer_score,text=7,foreground=8,visible=9) self.column2.set_resizable(True) self.column2.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.column2.set_fixed_width(column2_width) self.column2.set_sort_column_id(1) self.column3.set_resizable(True) self.column3.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.column3.set_fixed_width(column3_width) self.column3.set_sort_column_id(2) self.column4.set_resizable(True) self.column4.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.column4.set_fixed_width(column4_width) self.column4.set_sort_column_id(6) self.column5.set_sort_column_id(7) self.threads_tree.append_column(self.column1) if configs["exp_column"]=="From": self.threads_tree.append_column(self.column3) self.threads_tree.append_column(self.column2) self.threads_tree.set_expander_column(self.column3) else: self.threads_tree.append_column(self.column2) self.threads_tree.append_column(self.column3) self.threads_tree.set_expander_column(self.column2) self.threads_tree.append_column(self.column4) self.threads_tree.append_column(self.column5) try: self.threads_tree.set_enable_tree_lines(True) except: pass self.scrolledwin.add(self.threads_tree) color=configs["background_color"] self.set_background(color) color=configs["text_color"] self.set_foreground(color) if configs["use_system_fonts"]=="True": self.threads_tree.modify_font(pango.FontDescription("")) else: self.threads_tree.modify_font(pango.FontDescription(configs["font_threads_name"])) xpn-1.2.6/xpn_src/Dialogs.py0000644000175000017500000002257111141275756014103 0ustar antantimport gtk import gobject import ConfigParser import os from xpn_src.UserDir import get_wdir class About_Dialog: def delete_event(self,widget,event,data=None): return False def destroy(self,widget,event): self.dialog.destroy() def show(self): self.dialog.show_all() def __init__(self,NUMBER): self.dialog=gtk.Dialog(_("About"),None,0,(gtk.STOCK_OK,gtk.RESPONSE_OK)) self.dialog.set_default_size(300,280) self.dialog.connect("delete_event",self.delete_event) self.dialog.connect("response",self.destroy) self.dialog.set_has_separator(True) self.dialog.set_position(gtk.WIN_POS_CENTER) self.image=gtk.Image() self.image.set_from_file("pixmaps/xpn-logo-small.png") self.dialog.vbox.pack_start(self.image,True,True) string="X Python Newsreader %s\nItalian Style\n\nWritten by Antonio 'Nemesis' Caputo\nxpn@altervista.org\n\nhttp://xpn.altervista.org" % (NUMBER,) self.label=gtk.Label(string) self.label.set_use_markup(True) self.label.set_justify(gtk.JUSTIFY_CENTER) self.dialog.vbox.pack_start(self.label,True,True,8) class Dialog_YES_NO: def delete_event(self,widget,event,data=None): return False def __init__(self,message): self.resp="" self.dialog=gtk.MessageDialog(None,0,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO,message) self.dialog.connect("delete_event",self.delete_event) self.dialog.set_position(gtk.WIN_POS_CENTER) self.dialog.label.set_use_markup(True) resp=self.dialog.run() if resp==gtk.RESPONSE_YES: self.resp=True else: self.resp=False self.dialog.destroy() class Dialog_OK: def delete_event(self,widget,event,data=None): return False def __init__(self,message): self.resp="" self.dialog=gtk.MessageDialog(None,0,gtk.MESSAGE_INFO,gtk.BUTTONS_OK,message) self.dialog.connect("delete_event",self.delete_event) self.dialog.set_position(gtk.WIN_POS_CENTER) self.dialog.label.set_use_markup(True) self.resp=self.dialog.run() self.dialog.destroy() class Dialog_Import_Newsrc(gtk.Dialog): def __init__(self,message,server_name): gtk.Dialog.__init__(self,_("Choose the Server"),None,0,(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OK,gtk.RESPONSE_OK)) self.label=gtk.Label(message) self.label.set_use_markup(True) self.set_position(gtk.WIN_POS_CENTER) self.server_combo=gtk.combo_box_new_text() cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) positions=dict() i=0 for server in cp.sections(): self.server_combo.append_text(cp.get(server,"server")) positions[server]=i i=i+1 if server_name: self.server_combo.set_active(positions.get(server_name,0)) else: self.server_combo.set_active(0) self.vbox.pack_start(self.label,True,True,8) self.vbox.pack_start(self.server_combo,False,False,8) self.server_combo.show() self.label.show() self.label.set_line_wrap(True) if len(positions)== 0: Dialog_OK(_("First you have to configure at least one Server")) self.resp=gtk.RESPONSE_CLOSE self.destroy() else: self.resp=self.run() self.server_name=self.server_combo.get_active_text() self.destroy() class Error_Dialog(gtk.Dialog): def __init__(self,string,log): gtk.Dialog.__init__(self,_("Error Dialog"),None,0,(gtk.STOCK_OK,gtk.RESPONSE_OK)) self.set_default_size(350,350) self.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/dialog-error.xpm")) self.set_has_separator(True) self.set_position(gtk.WIN_POS_CENTER) self.buffer=gtk.TextBuffer() self.buffer.set_text(string) self.view=gtk.TextView(self.buffer) self.view.set_wrap_mode(gtk.WRAP_WORD) self.view.set_cursor_visible(False) self.view.set_border_width(5) self.view.set_editable(False) self.scrolled_win=gtk.ScrolledWindow() self.scrolled_win.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.scrolled_win.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.scrolled_win.add(self.view) self.buffer_log=gtk.TextBuffer() self.buffer_log.set_text(log) self.view_log=gtk.TextView(self.buffer_log) self.view_log.set_wrap_mode(gtk.WRAP_WORD) self.view_log.set_cursor_visible(False) self.view_log.set_border_width(5) self.view_log.set_editable(False) self.scrolled_win_log=gtk.ScrolledWindow() self.scrolled_win_log.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.scrolled_win_log.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.scrolled_win_log.add(self.view_log) self.notebook=gtk.Notebook() self.label_error=gtk.Label(""+_("Last Error")+"") self.label_error.set_use_markup(True) self.label_error_log=gtk.Label(""+_("Errors Log")+"") self.label_error_log.set_use_markup(True) self.notebook.append_page(self.scrolled_win,self.label_error) self.notebook.append_page(self.scrolled_win_log,self.label_error_log) self.notebook.show_all() self.vbox.pack_start(self.notebook,True,True,0) class MidDialog(gtk.Dialog): def __init__(self,mid): gtk.Dialog.__init__(self,_("Message-ID Search Dialog"),None,0,(gtk.STOCK_CLOSE,gtk.RESPONSE_CLOSE,gtk.STOCK_OK,gtk.RESPONSE_OK)) self.label=gtk.Label(""+_("Message-ID to search")+"") self.label.set_use_markup(True) self.entry=gtk.Entry() self.entry.set_text(mid) self.entry.show() self.label.show() self.vbox.pack_start(self.label,True,True) self.vbox.pack_start(self.entry,True,True) self.r1=gtk.RadioButton(None,_("Search in current group")) self.r2=gtk.RadioButton(self.r1,_("Search in subscribed groups")) self.r3=gtk.RadioButton(self.r1,_("Search on Google")) self.r1.show() self.r2.show() self.r3.show() self.vbox.pack_start(self.r1,True,True) self.vbox.pack_start(self.r2,True,True) self.vbox.pack_start(self.r3,True,True) self.set_size_request(350,200) self.resp=self.run() self.sel=self.r1.get_active(),self.r2.get_active(),self.r3.get_active() self.destroy() class Shortcut_Dialog(gtk.Dialog): def grab_shortcut(self,obj,event): comb="" name=gtk.gdk.keyval_name(event.keyval) string_name=event.string if event.state & gtk.gdk.CONTROL_MASK: comb=comb+"" if event.state & gtk.gdk.MOD1_MASK: comb=comb+"" if event.state & gtk.gdk.SHIFT_MASK: comb=comb+"" comb=comb+name admitted=["delete",]+["f"+str(i) for i in range(1,13)] if string_name or comb.lower() in admitted: self.entry.set_text(comb) self.shortcut=comb else: self.entry.set_text("") self.shortcut="" def __init__(self): gtk.Dialog.__init__(self,_("Shortcut Dialog"),None,0,(gtk.STOCK_OK,gtk.RESPONSE_OK,gtk.STOCK_CLOSE,gtk.RESPONSE_CLOSE)) self.label1=gtk.Label(""+_("Type your Shortcut")+"") self.label1.set_use_markup(True) self.label2=gtk.Label(""+_("Press OK to confirm it")+"") self.label2.set_use_markup(True) self.entry=gtk.Entry() self.entry.set_sensitive(False) self.entry.show() self.label1.show() self.label2.show() self.vbox.pack_start(self.label1,True,True,4) self.vbox.pack_start(self.label2,True,True,4) self.vbox.pack_start(self.entry,True,True,4) self.shortcut="" self.connect("key-press-event",self.grab_shortcut) self.resp=self.run() self.destroy() class Shortcut_Error_Warning_Dialog(gtk.MessageDialog): def __init__(self,warning,list,message): if warning: type=gtk.MESSAGE_WARNING else: type=gtk.MESSAGE_ERROR gtk.MessageDialog.__init__(self,None,0,type,gtk.BUTTONS_OK,message) self.set_size_request(500,400) self.set_resizable(True) self.label.set_use_markup(True) scrolledwin=gtk.ScrolledWindow() self.treeview=gtk.TreeView() self.treeview.set_border_width(4) scrolledwin.add(self.treeview) self.model=gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING) self.treeview.set_model(self.model) text_renderer=gtk.CellRendererText() column1=gtk.TreeViewColumn(_("Window"),text_renderer,text=0) column1.set_resizable(True) column2=gtk.TreeViewColumn(_("Shortcut"),text_renderer,text=1) column2.set_resizable(True) column3=gtk.TreeViewColumn(_("Action"),text_renderer,text=2) self.treeview.append_column(column1) self.treeview.append_column(column2) self.treeview.append_column(column3) self.treeview.set_rules_hint(True) for line in list: self.model.append(line) self.vbox.add(scrolledwin) self.vbox.show_all() self.resp=self.run() self.destroy() xpn-1.2.6/xpn_src/ListThread.py0000644000175000017500000000306611141275756014562 0ustar antantimport threading, Queue, sys, cPickle, socket, time, os from xpn_src.UserDir import get_wdir class ListThread(threading.Thread): def __init__(self, server,server_name): threading.Thread.__init__(self) self.server = server self.server_name=server_name self.groups_found = 0 self.lock = threading.Lock() self.queue = Queue.Queue() def add_log(self,message,is_command): try: f=open(os.path.join(get_wdir(),"server_logs.dat"),"a") except IOError: pass else: if is_command: f.write(time.ctime(time.time())+" :: >> "+message+"\n") else: f.write(time.ctime(time.time())+" :: << "+message+"\n") f.close() def run(self): try: self.add_log("LIST",True) resp, list = self.server.list() self.queue.put(["Connected",resp]) except socket.error, e: self.queue.put(["Server error","Server error: "+str(e), str(e)]) except: self.queue.put(["Server error","Server error: "+str(sys.exc_info()[1]), str(sys.exc_info()[0])+","+str(sys.exc_info()[1])+"\n" \ +self.server.quit() ]) else: list = [[unicode(list[i][0],"iso-8859-1","replace").encode("us-ascii","replace"),list[i][3],self.server_name] for i in xrange(len(list))] self.queue.put(["Finished Listing"]) self.queue.put(list) pass xpn-1.2.6/xpn_src/Custom_Search_Entry.py0000700000175000017500000000375611141275756016436 0ustar antantimport gtk,gobject class Custom_Search_Entry(gtk.HBox): __gsignals__ = { 'do_search':(gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,gobject.TYPE_STRING)), 'search_focus_in':(gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)), 'search_focus_out':(gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)) } def __init__(self): gtk.HBox.__init__(self) self.entry=gtk.Entry() self.entry.set_size_request(80,-1) self.entry.connect("focus-in-event",self.entry_focus_in) self.entry.connect("focus-out-event",self.entry_focus_out) bar=gtk.MenuBar() self.search=gtk.MenuItem("search") button=gtk.Button("",gtk.STOCK_FIND) menu=gtk.Menu() item=None for name in ("Subject","From","Body"): item=gtk.RadioMenuItem(item,name) item.connect("toggled",self.change_search_type,name) menu.append(item) if name=="Subject": item.set_active(True) self.search.set_submenu(menu) bar.append(self.search) #self.pack_start(gtk.VSeparator(),False,False,2) self.pack_start(bar,False,False,0) self.pack_start(self.entry,False,False,0) self.pack_start(button,False,False,0) #self.pack_start(gtk.VSeparator(),False,False,2) button.connect("clicked",self.on_search_clicked) self.search_type="Subject" def grab_focus(self): self.entry.grab_focus() def on_search_clicked(self,obj): self.emit("do_search",self.search_type,self.entry.get_text().decode("utf-8")) def change_search_type(self,obj,name): self.search_type=name self.search.get_child().set_label(name) def entry_focus_in(self,obj,event): self.emit("search_focus_in","focus_in") def entry_focus_out(self,obj,event): self.emit("search_focus_out","focus_out") xpn-1.2.6/xpn_src/Newsrc.py0000700000175000017500000002523511141275756013753 0ustar antantimport cPickle import socket import time import gtk import sys import os import ConfigParser from xpn_src.Article import Article from xpn_src.Score import Score_Rules from xpn_src.Connections_Handler import Connection, SSLConnection from xpn_src.UserDir import get_wdir from xpn_src.Dialogs import Dialog_OK from xpn_src.Articles_DB import Articles_DB,Groups_DB try: set() except: from sets import Set as set class ExportNewsrc: def open_groups_list(self): "returns the newsgroups lists, divided on a per server base" file_list=os.listdir(os.path.join(self.wdir,"groups_info")) groups=[] for file_name in file_list: if file_name.endswith(".groups.sqlitedb"): groups_list=self.groups_list_db.getList(file_name) groups.append(groups_list) return groups def open_subscribed_list(self): "returns subscribed_list and the read_articles lists" subscribed=self.art_db.getSubscribed() name_list=[] read_list={} first_list={} for group in subscribed: name_list.append([group[0],group[2]]) last=group[1] sorted=[] for article in self.art_db.getArticles(group[0],[],True): sorted.append(article) if sorted: first=int(sorted[0].number) read_articles=range(first,int(last)+1) for article in sorted: if not article.is_read: read_articles.remove(int(article.number)) read_list[group[0]]=read_articles first_list[group[0]]=first else: read_list[group[0]]=range(int(last),int(last)+1) first_list[group[0]]=int(last) return name_list,read_list,first_list def build_clist(self,read_articles,first): if not read_articles: clist="" else: clist=self.format_intervals(self.compact_list(read_articles)) if first in read_articles: splitted=clist.split(",") if "-" in splitted[0]: first_block=splitted[0].split("-") first_block[0]="1" splitted[0]="-".join(first_block) else: splitted[0]="1-"+str(first) clist=",".join(splitted) else: if first >1: clist="1-"+str(first-1)+","+clist if clist.endswith(","): clist=clist[:-1] return clist def compact_list(self,L): intervals = [[L[0]] * 2] for item in L: if item == 1+intervals[-1][-1]: intervals[-1][-1] = item else: intervals.append([item]*2) intervals.pop(0) return intervals def format_intervals(self,intervals): string="" for interval in intervals: if interval[0]==interval[1]: string=string+str(interval[0])+"," else: string=string+str(interval[0])+"-"+str(interval[1])+"," return string[0:-1] def build_line(self,group,subscribed_list,read_list,first_list): if subscribed_list!=None: if group in subscribed_list: clist=self.build_clist(read_list[group[0]],first_list[group[0]]) return (group[0]+": "+clist).strip() else: return group[0]+"!" else: return group[0]+"!" def build_newsrc(self): subscribed_list,read_list,first_list=self.open_subscribed_list() groups_lists=self.open_groups_list() def build_file(groups_list,server): newsrc=[] for group in groups_list: line=self.build_line([group[0],group[2]],subscribed_list,read_list,first_list)+"\n" newsrc.append(line) newsrc="".join(newsrc) return newsrc if not groups_lists: return None else: newsrc_files=dict() for groups_list in groups_lists: server=groups_list[0][2] newsrc_file=build_file(groups_list,server) newsrc_files[server]=newsrc_file return newsrc_files def save_newsrc(self,where): if self.newsrc: for server,newsrc_file in self.newsrc.iteritems(): try: f=open(os.path.join(where,server+".newsrc"),"wb") except IOError: pass else: f.write(self.newsrc[server]) f.close() def __init__(self,art_db): self.wdir=get_wdir() self.art_db=art_db self.groups_list_db=Groups_DB() self.message="" self.newsrc="" self.newsrc=self.build_newsrc() if self.newsrc==None: self.message="You have to download the newsgroups list first" else: self.message=_("Newsrc successful exported") class ImportNewsrc: def extract_ranges(self,L): list=[] if L!="": intervals=L.split(",") for interval in intervals: if "-" in interval: #this is a range start,stop=int(interval.split("-")[0]),int(interval.split("-")[1]) #list.extend(range(start,stop+1)) else: #this is a single number list.append(int(interval)) return list def find_first_unread(self,L): first_interval=L.split(",")[0] if "-" in first_interval: if first_interval.split("-")[0]=="1": first_unread=int(first_interval.split("-")[1])+1 else: first_unread=1 else: if first_interval=="1": first_unread=2 else: first_unread=1 return first_unread def subscribe_groups(self,newsrc,server_name): cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","id.txt")) try: id_name=cp.sections()[0] except IndexError: Dialog_OK(_("First you have to create at least one Identity")) else: for group in newsrc: if group.find(":")!=-1: #this is a subscribed group group_info=group.split(":") group_name=group_info[0].strip() group_read_ranges=group_info[1].strip() if group_read_ranges.find("/")!=-1: #Xnews extension for kept articles group_read_ranges,group_kept_ranges=group_read_ranges.split("/") #group_read_list=self.extract_ranges(group_read_ranges) group_first_unread=self.find_first_unread(group_read_ranges) self.subscribe_group(group_name,group_first_unread,group_read_ranges,server_name,id_name) def retrieve_body(self,article_to_read,group,server_name=None): if not server_name: server_name=self.current_server body=article_to_read.get_body() if not body: message,headerList,body,bodyRetrieved=self.connectionsPool[server_name].getBody(article_to_read.number,article_to_read.msgid,group) if headerList: article_to_read.parse_header_list(headerList) if bodyRetrieved: article_to_read.set_body('\n'.join(headerList+['']+body)) body=article_to_read.get_body() article_to_read.marked_for_download=False return body def download_headers(self,group,first_unread,read_list,server_name): last_number=str(first_unread) #Here I deleted the controls I made on first_unread before I changed #the nntplib, it works with leafnode, I must test with other servers. first=int(first_unread) #Downloading headers self.main_win.progressbar.set_text(_("Fetching Headers")) self.main_win.progressbar.set_fraction(1/float(2)) while gtk.events_pending(): gtk.main_iteration(False) message,total_headers,last=self.connectionsPool[server_name].getHeaders(group,first) if last!=-1: last_number=str(last) self.main_win.statusbar.push(1,message) if total_headers: self.main_win.progressbar.set_text(_("Building Articles")) else: self.main_win.progressbar.set_text(_("No New Headers")) self.main_win.progressbar.set_fraction(2/float(2)) while gtk.events_pending(): gtk.main_iteration(False) self.art_db.createGroup(group) self.art_db.addHeaders(group,total_headers,server_name,self.connectionsPool,read_list) self.main_win.statusbar.push(1,_("Group subscribed")) self.main_win.progressbar.set_fraction(0) self.main_win.progressbar.set_text("") return last_number def subscribe_group(self,group_to_subscribe,first_unread,read_list,server_name,id_name): last=self.download_headers(group_to_subscribe,int(first_unread),read_list,server_name) self.art_db.removeSubscribed(group_to_subscribe) self.art_db.addSubscribed(group_to_subscribe,last,server_name,id_name) def delete_files(self): subscribed=self.art_db.getSubscribed() for group in subscribed_list: try: os.remove(os.path.join(self.wdir,"groups_info/",group[0])) except: pass try: os.remove(os.path.join(self.wdir,"groups_info/subscribed.sqlitedb")) except: pass def __init__(self,newsrc,main_win,configs,server_name): self.main_win=main_win self.configs=configs self.wdir=get_wdir() self.art_db=main_win.art_db #cleaning files #self.delete_files() #opening connection with server cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) self.connectionsPool=dict() for server in cp.sections(): if cp.get(server,"nntp_use_ssl")=="True": self.connectionsPool[server]=SSLConnection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) else: self.connectionsPool[server]=Connection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) #subscribing groups self.subscribe_groups(newsrc,server_name) #closing connection with server for connection in self.connectionsPool.itervalues(): connection.closeConnection() xpn-1.2.6/xpn_src/Article.py0000700000175000017500000005243611141275756014100 0ustar antantfrom email.Utils import parsedate,parsedate_tz,mktime_tz,parseaddr,make_msgid, formataddr from time import ctime,time import gtk import email import email.Header from StringIO import * from string import find,replace import base64 def old_parse_from(from_name): left=from_name.rfind("<") if left!=-1: # It is like "nick" or nick if from_name[0]=="\"": #It is like "nick" nick=from_name[1:left-2].strip() else: #it is like nick nick=from_name[0:left].strip() email=from_name[left+1:-1] else: left=from_name.rfind("(") if left!=-1: #it is like email (nick) right=from_name.rfind(")") nick=from_name[left+1:right].strip() email=from_name[0:left-1] else: #ther is only the email nick="" email=from_name if nick=="": nick=from_name return nick,email.strip() class Article: def my_decode_header(self,header): try: parts=email.Header.decode_header(header) except: parts=[[header,None]] header_decoded="" for i in range(len(parts)): charset=parts[i][1] if parts[i][1]!=None: charset=parts[i][1] else: charset=self.fallback_cset try: header_decoded=header_decoded+" "+unicode(parts[i][0],charset,"replace").strip(" ") except :#LookupError: # had to comment the LookupError and add a second except to catch an exception that popped up # trying to reopen an article with some encoded words in the xface ... try: header_decoded=header_decoded+" "+unicode(parts[i][0],self.fallback_cset,"replace").strip(" ") except TypeError: header_decoded=header_decoded+" "+parts[i][0].strip() header_decoded=header_decoded.strip() return header_decoded def decode_header_list(self,list): try: decoded_list=[unicode(line,self.cset,"replace") for line in list] except LookupError: decoded_list=[unicode(line,self.fallback_cset,"replace") for line in list] self.raw_header_list=decoded_list def parse_header_list(self,hlist,rebuild=False): i=0 hlist_len=len(hlist) while i < hlist_len: ind=hlist[i].find(":") if ind>0: header_name=hlist[i][:ind].strip().lower() header_value=hlist[i][ind+1:].strip() j=i+1 while j < hlist_len: if (hlist[j][0]==" " or hlist[j][0]=="\t"): header_value=header_value+hlist[j] j=j+1 i=i+1 else: break header_value=self.my_decode_header( header_value.replace("\r","").replace("\n","")) self.hdict[header_name]=header_value i=i+1 nick,email=self.parse_from(self.hdict.get("from","")) date_parsed=self.parse_date(self.hdict.get("date","")) self.nick=nick self.email=email self.from_name=self.hdict.get("from","") self.ngroups=self.hdict.get("newsgroups","") #self.ref=self.hdict.get("references","") # I don't want to update this field self.fup_to=self.hdict.get("followup-to","") self.reply_to=self.hdict.get("reply-to","") self.user_agent=self.hdict.get("user-agent","") self.subj=self.hdict.get("subject","") self.date=self.hdict.get("date","") self.date_parsed=date_parsed self.x_face=self.hdict.get("x-face",None) self.face=self.hdict.get("face",None) ctype_dict=self.parse_content_type(self.hdict.get("content-type","")) self.ct_enc=self.hdict.get("content-transfer-encoding","") self.cset=ctype_dict.get("charset","") if self.cset=="": self.cset=self.fallback_cset if not rebuild: self.decode_header_list(hlist) else: self.raw_header_list=hlist def get_hdr(self,name): name=name.lower() return self.hdict.get(name,"") def parse_content_type(self,ctype): #split Content-Type in its components sub_parts=ctype.split(";") ctype_dic=dict() if len(sub_parts)>1: for part in sub_parts: if len(part)>0: ind=part.find("=") if ind!=-1: param_name,param_value=part[:ind],part[ind+1:] ctype_dic[param_name.strip()]=param_value.strip() else: ctype_dic["type"]=part.strip() return ctype_dic def parse_from(self,from_name): nick,email=parseaddr(from_name) if not nick: nick=email if not nick and not email: nick,email = old_parse_from(from_name) return nick,email def parse_date(self,date): #data=parsedate(date) try: #trying to prevent the rfc822.parsedate bug with Tue,26 instead of Tue, 26 secs=mktime_tz(parsedate_tz(date)) except: secs=time() self.secs=secs data=parsedate(ctime(secs)) if data[3]<10: ora="0"+repr(data[3]) else: ora=repr(data[3]) if data[4]<10: minuti="0"+repr(data[4]) else: minuti=repr(data[4]) return repr(data[2])+"/"+repr(data[1])+"/"+repr(data[0])+" "+ora+":"+minuti def get_all_headers(self): return self.nick,self.email,self.from_name,self.ngroups,self.ref,self.fup_to,self.reply_to,self.ct_enc,self.cset,self.subj,self.date,self.date_parsed,self.user_agent def get_headers(self): return self.nick,self.from_name,self.ref,self.subj,self.date,self.date_parsed def get_body(self): return self.body def set_body(self,rawbody,rebuild=False): if rebuild: rawbody=rawbody.encode("utf-8") self.raw_body=rawbody msg = email.message_from_string(rawbody) charsets= msg.get_charsets() if msg.is_multipart(): body = '' body_list=[] self.body_parts=[] i=0 for part in msg.walk(): mtype = part.get_content_maintype() ctype = part.get_content_type() # Skip multipart container if mtype != 'multipart': payload=part.get_payload(decode=(mtype=='text')) if type(payload)==type([]): try: body=payload[0].as_string() except: body=str(payload[0]) else: body=str(payload) body = body +'\n' if not rebuild: try: body = unicode(body, str(charsets[i]), 'replace') except LookupError: body = unicode(body, self.fallback_cset, 'replace') body_list.append(body) self.body_parts.append((ctype,body)) i=i+1 # Return one line per item list. body='\n'.join(body_list) self.body= body.splitlines() else: body=msg.get_payload(decode=False) #the q-printable could break if I'm reloading the article if not rebuild: body=msg.get_payload(decode=True) try: body = unicode(body, self.cset, 'replace') except LookupError: body = unicode(body, self.fallback_cset, 'replace') self.body=body.splitlines() self.has_body=True def get_raw(self,return_string=False): try: raw=self.raw_header_list+[""]+self.body except: raw=None if return_string: if raw: raw="\n".join(raw) else : raw=None return raw def set_score(self,score): self.score=score def get_score(self): return self.score def reset_article_score_actions(self): self.score=0 self.marked_for_download=False self.keep=False self.watch=False self.ignore=False self.fg_color=None self.bg_color=None def get_article_info(self,icons): art_fup,art_body,art_unread,art_read,art_mark,art_keep,art_unkeep,art_watch,art_unwatchignore,art_ignore=icons #number=self.number msgid=self.msgid nick,from_name,ref,subj,date,date_parsed=self.get_headers() if self.keep: icon2=art_keep else: icon2=art_unkeep if self.is_read: isUnread=False icon=art_read else: isUnread=True if self.has_body: icon=art_body elif self.marked_for_download: icon=art_mark else: icon=art_unread show_score=True if self.score<0: score_foreground="red" elif self.score>0: score_foreground="darkgreen" else : #self.score==0 score_foreground="darkgreen" show_score=False if self.watch: icon3=art_watch elif self.ignore: icon3=art_ignore else: icon3=art_unwatchignore try : fg_color=self.fg_color except: fg_color_set=False fg_color="black" else: if fg_color: if self.fg_color.lower()!="default": fg_color_set=True try: gtk.gdk.color_parse(fg_color) except: fg_color="black" fg_color_set=False else: fg_color_set=False fg_color="black" else: fg_color_set=False fg_color="black" try : bg_color=self.bg_color except: bg_color_set=False bg_color="white" else: if bg_color: if self.bg_color.lower()!="default": bg_color_set=True try: gtk.gdk.color_parse(bg_color) except: bg_color="white" bg_color_set=False else: bg_color_set=False bg_color="black" else: bg_color_set=False bg_color="white" article_info = [icon,subj,nick,date_parsed,self,isUnread,self.secs,self.score,score_foreground,show_score,icon2,icon3,0,False,fg_color_set,fg_color,bg_color_set,bg_color,False,0] return article_info def __init__(self,number,msgid,from_name,ref,subj,date,fallback_charset,original_group,xref,bytes,lines,rebuild=False): if not rebuild: self.hdict=dict() self.score=0 self.number=number self.fallback_cset=fallback_charset self.msgid=self.my_decode_header(msgid) self.from_name=self.my_decode_header(from_name) self.nick,self.email=self.parse_from(self.from_name) self.ref=self.my_decode_header(ref) self.subj=self.my_decode_header(subj) self.date=date self.date_parsed=self.parse_date(date) self.hdict["message-id"]=msgid self.hdict["from"]=self.my_decode_header(from_name) self.hdict["references"]=self.my_decode_header(ref) self.hdict["subject"]=self.my_decode_header(subj) self.hdict["date"]=date self.hdict["xref"]=xref[5:].strip() self.hdict["bytes"]=bytes self.hdict["lines"]=lines self.body=None self.raw=None self.is_read=False self.marked_for_download=False self.keep=False self.watch=False self.ignore=False self.original_group=original_group self.x_face=None self.face=None self.raw_header_list=None self.fg_color=None self.bg_color=None self.xref=self.hdict.get("xref","") self.raw_body="" self.has_body=False try: self.bytes=int(bytes) except ValueError: self.bytes=0 try: self.lines=int(lines) except ValueError: self.lines=0 else: self.hdict=dict() self.score=0 self.number=number self.fallback_cset=fallback_charset self.msgid=msgid self.from_name=from_name self.nick,self.email=self.parse_from(self.from_name) self.ref=ref self.subj=subj self.date=date self.date_parsed=self.parse_date(date) self.hdict["message-id"]=msgid self.hdict["from"]=self.from_name self.hdict["references"]=self.ref self.hdict["subject"]=self.subj self.hdict["date"]=date self.hdict["xref"]=xref self.hdict["bytes"]=bytes self.hdict["lines"]=lines self.body=None self.raw=None self.is_read=False self.marked_for_download=False self.keep=False self.watch=False self.ignore=False self.original_group=original_group self.x_face=None self.face=None self.raw_header_list=None self.fg_color=None self.bg_color=None self.xref=self.hdict.get("xref","") self.raw_body="" self.has_body=False try: self.bytes=int(bytes) except ValueError: self.bytes=0 try: self.lines=int(lines) except ValueError: self.lines=0 class Article_To_Send: def best_enc(self,text): for best_enc in self.ordered_list: try: text.encode(best_enc,"strict") except: pass else: break return best_enc def my_encode_header(self,header): usascii=True for j in range(len(header)): if ord(header[j])>127: #String is not us-ascii usascii=False break if usascii: header_encoded=header else: #let's search the beginning of the word i=j char=header[i] while char!=" " and i>=0: i=i-1 char=header[i] best_enc=self.best_enc(header) if i==0: head_new=header.encode(best_enc,"replace") header_encoded=str(email.Header.Header(head_new,best_enc)) else: head_new=header[i+1:].encode(best_enc,"replace") header_new_encoded=str(email.Header.Header(head_new,best_enc)) header_encoded=header[:i+1]+header_new_encoded return header_encoded.strip() def encode_body(self,body,output_charset): body_encoded="" for line in body: #string=unicode(list[i]+"\n",input_charset) line=line+"\n" line_encoded=line.encode(output_charset,"replace") body_encoded=body_encoded+line_encoded return body_encoded def get_article(self): article="Newsgroups: "+self.newsgroups+"\n" article=article+"From: "+formataddr([self.nick_encoded,self.email])+"\n" article=article+"Subject: "+self.subject_encoded+"\n" if self.references!="": article=article+"References: "+self.references+"\n" self.references="" article=article+"User-Agent: "+self.user_agent+"\n" article=article+"MIME-Version: 1.0\n" article=article+"Content-Type: text/plain; charset="+self.output_charset+"\n" if self.output_charset.lower()=="us-ascii": article=article+"Content-Transfer-Encoding: 7bit\n" else: article=article+"Content-Transfer-Encoding: 8bit\n" if self.generate_mid=="True": mid=make_msgid("XPN") if self.fqdn: left,right=mid.split("@") def clear_fqdn(s,chars): s=s.encode("us-ascii","replace") for char in chars: s=s.replace(char,"") return s mid=left+"@"+clear_fqdn(self.fqdn,"@\\\"<>()[];:,")+">" article=article+"Message-ID: "+mid+"\n" for header in self.custom_headers: article=article+header+"\n" article=article+"\n" article=article.encode("utf-8")+self.body_encoded return article def parse_from(self,from_name): nick,email=parseaddr(from_name) if not nick: nick=email if not nick and not email: nick,email = old_parse_from(from_name) return nick,email def __init__(self,newsgroups,from_name,subject,references,user_agent,output_charset,ordered_list,body,custom_names,custom_values,generate_mid,fqdn): self.newsgroups=newsgroups self.ordered_list=ordered_list nick,self.email=self.parse_from(from_name) self.nick_encoded=self.my_encode_header(nick) self.subject_encoded=self.my_encode_header(subject) self.references=references self.user_agent=user_agent self.output_charset=output_charset self.body_encoded=self.encode_body(body,output_charset) self.custom_headers=[] for i in range(len(custom_names)): custom_header=custom_names[i].encode("us-ascii","replace")+": "+self.my_encode_header(custom_values[i]) self.custom_headers.append(custom_header) self.generate_mid=generate_mid self.fqdn=fqdn class Mail_To_Send: def best_enc(self,text): for best_enc in self.ordered_list: try: text.encode(best_enc,"strict") except: pass else: break return best_enc def my_encode_header(self,header): usascii=True for j in range(len(header)): if ord(header[j])>127: #String is not us-ascii usascii=False break if usascii: header_encoded=header else: #let's search the beginning of the word i=j char=header[i] while char!=" " and i>=0: i=i-1 char=header[i] best_enc=self.best_enc(header) if i==0: head_new=header.encode(best_enc,"replace") header_encoded=str(email.Header.Header(head_new,best_enc)) else: head_new=header[i+1:].encode(best_enc,"replace") header_new_encoded=str(email.Header.Header(head_new,best_enc)) header_encoded=header[:i+1]+header_new_encoded return header_encoded.strip() def encode_body(self,body,output_charset): body_encoded="" for line in body: #string=unicode(list[i]+"\n",input_charset) line=line+"\n" line_encoded=line.encode(output_charset,"replace") body_encoded=body_encoded+line_encoded return body_encoded def get_article(self): article="To: "+formataddr([self.to_nick_encoded,self.to_email])+"\n" article=article+"From: "+formataddr([self.nick_encoded,self.email])+"\n" article=article+"Subject: "+self.subject_encoded+"\n" article=article+"Date: "+self.date+"\n" if self.references!="": article=article+"References: "+self.references+"\n" self.references="" article=article+"User-Agent: "+self.user_agent+"\n" article=article+"MIME-Version: 1.0\n" article=article+"Content-Type: text/plain; charset="+self.output_charset+"\n" if self.output_charset.lower()=="us-ascii": article=article+"Content-Transfer-Encoding: 7bit\n" else: article=article+"Content-Transfer-Encoding: 8bit\n" article=article+"\n" article=article.encode("utf-8")+self.body_encoded return article def parse_from(self,from_name): nick,email=parseaddr(from_name) if not nick: nick=email if not nick and not email: nick,email = old_parse_from(from_name) return nick,email def __init__(self,to_name,from_name,date,subject,references,user_agent,output_charset,ordered_list,body): self.ordered_list=ordered_list self.to_name=to_name to_nick,self.to_email=self.parse_from(to_name) self.to_nick_encoded=self.my_encode_header(to_nick) self.date=date nick,self.email=self.parse_from(from_name) self.nick_encoded=self.my_encode_header(nick) self.subject_encoded=self.my_encode_header(subject) self.references=references self.user_agent=user_agent self.output_charset=output_charset self.body_encoded=self.encode_body(body,output_charset) xpn-1.2.6/xpn_src/XFace.py0000644000175000017500000004762111141275756013512 0ustar antant# This module is a translation from JavaScript to Python of the Mnheny (a Thunderbird extension) X-Face decoder. # Thanks to: # James Ashton (author of the original C source of 'uncompface') # Andrew Taylor (author the JavaScript translation of 'uncompface') # Karsten Dasterloh (author of the Mnenhy Thunderbird extension) import re LENGTH=48 PIXELS=(LENGTH * LENGTH) FIRSTPRINT = ord('!') LASTPRINT = ord('~') NUMPRINTS = (LASTPRINT - FIRSTPRINT + 1) BITSPERWORD=8 WORDCARRY=(1 << BITSPERWORD) WORDMASK=(WORDCARRY - 1) MAXWORDS=((PIXELS * 2 + BITSPERWORD - 1) / BITSPERWORD) BLACK=0 GREY =1 WHITE=2 F=[] for i in range(0,PIXELS): F.append(0) levels=[ [{"p_offset":255, "p_range":1 }, {"p_offset":0, "p_range":251}, {"p_offset":251, "p_range":4 }],# Top of tree almost always grey [{"p_offset":255, "p_range":1 }, {"p_offset":0, "p_range":200}, {"p_offset":200, "p_range":55 }], [{"p_offset":223, "p_range":33 }, {"p_offset":0, "p_range":159}, {"p_offset":159, "p_range":64 }], [{"p_offset":0, "p_range":131}, {"p_offset":0, "p_range":0 }, {"p_offset":131, "p_range":125}] # Grey disallowed at bottom ] freqs =[ {"p_offset":0, "p_range":0 }, {"p_offset":0, "p_range":38}, {"p_offset":38, "p_range":38}, {"p_offset":152, "p_range":13}, {"p_offset":76, "p_range":38}, {"p_offset":165, "p_range":13}, {"p_offset":178, "p_range":13}, {"p_offset":230, "p_range":6 }, {"p_offset":114, "p_range":38}, {"p_offset":191, "p_range":13}, {"p_offset":204, "p_range":13}, {"p_offset":236, "p_range":6 }, {"p_offset":217, "p_range":13}, {"p_offset":242, "p_range":6 }, {"p_offset":248, "p_range":5 }, {"p_offset":253, "p_range":3 } ] G ={ "g_00":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,0,0,0,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,1,1,0,0,0,0,0,1,0,1,0,0,0,0,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1, 0,1,0,0,0,1,0,1,0,0,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,0,1,0,1,0,1,0,0, 0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,0,0,1,1,1,1,1,0,1,0,1,1,1,0,0,1,1,1,1,0,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1, 0,0,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,1,0,1,1,1,1,1,0,0,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1, 0,0,0,0,1,1,1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1,1,0,1,0,0,1,1,1,1,0,1,0,1,1,1,1,1, 1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1, 1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,1,0,0,1,1,1,1, 1,1,0,1,0,1,1,1,0,0,1,1,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,0,1,1,0,0,0,1,0,0,1,0,1,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1, 1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, 0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,0,1,1,1,1,1, 0,0,0,1,1,0,0,0,1,1,0,1,0,1,1,1,1,0,0,1,0,1,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, 0,0,0,1,1,1,1,1,1,0,1,1,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,0,0,1,0,0,1,0,0,0,1,1,1,1, 0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1, 1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1, 0,1,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1, 1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1, 1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1, 0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,0,0,0,0,1,1,1,1, 0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1, 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,0,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1, 0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,1,0,1,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,1,1,0,0, 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,0,1,0,1, 1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1, 0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,0, 0,0,0,0,0,1,0,1,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,1,0,1,0,1,0,0,1,1,1,1, 0,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,0,1,0,0,1,1,1,1,0,1,0,1,1,1,1,1, 1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,0,0,1,0,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1, 0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,0, 0,0,0,0,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1, 0,1,0,0,0,1,1,1,1,1,1,0,1,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1, 0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1, 1,0,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,1,1,0,0,1,0,1,0,1,1,1, 0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1, 0,1,0,0,0,1,1,1,0,1,1,0,1,1,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, 0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1, 0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0, 0,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0,0,1,0,1, 1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,0,1,0,0,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,1,0,0, 1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,1,1,1,0,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,0,1,1,1,1,0,1,0,0,1,1,1,1, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,0,0,1,1,1,0,1,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], "g_01":[0,0,1,1,0,1,1,1,0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1, 1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], "g_02":[0,1,0,1], "g_10":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1,0,0,1,1,0,1,0,1,1,1,1,1,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1, 0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,0,1,0,1,1,1, 0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,1,0,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,0,1,1,0,0,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0, 0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,1,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,1, 0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,1,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,0,0,0,0,1,1,0, 1,1,1,1,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1, 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], "g_20":[0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,1,0,0,1,0,1,1,1,0, 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1], "g_30":[0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1, 0,0,0,1,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,1,0,0,0,1,0,0,0,1, 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,1,0,0,0,1,0,0,0,1, 0,0,0,1,0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,1, 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,1,0,0,0,1,0,0,0,1,0,0,0,1, 0,0,0,1,0,0,0,1,0,1,1,1,0,1,0,1], "g_40":[0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,0, 1,1,1,0,0,1,0,0,0,0,0,0,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1, 0,1,0,0,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, 1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,0,1,0,0,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1, 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,0,0,1,1,1,1,0,1,0,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1, 0,0,0,0,0,1,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,0,0,1,0,1,0,1,0,1,1,1, 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,0,1,0,1,1,1,0,1,1,1,0,0,0,0,1,1,0,1,0,1,0,1,1,1,1,1, 0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1, 0,0,0,0,0,1,0,1,0,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1, 0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1, 0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1, 0,0,0,0,1,1,0,1,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,1, 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1], "g_11":[0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1], "g_21":[0,0,0,1,0,1,1,1], "g_31":[0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1], "g_41":[0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1,1, 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1], "g_12":[0,1], "g_22":[0], "g_32":[0,0,0,1], "g_42":[0,0,0,1] } def BigPop(p): ''' p is freqs oder levels[lev]''' global B r= B&255 #it is the LS BYTE B= B>>8 i=0 while ((r < p[i]["p_offset"]) or (r >= p[i]["p_range"] + p[i]["p_offset"])): i=i+1 B=B*p[i]["p_range"] B=B+(r-p[i]["p_offset"]) return i def PopGreys(off, len): global B global F if (len > 3): len /= 2 PopGreys(off, len) PopGreys(off + len, len) PopGreys(off + LENGTH * len, len) PopGreys(off + LENGTH * len + len, len) else: len = BigPop(freqs) if (len & 1): F[off] = 1 if (len & 2): F[off + 1] = 1 if (len & 4): F[off + LENGTH] = 1 if (len & 8): F[off + LENGTH + 1] = 1 def UnCompress(off, len, lev): global B big_pop=BigPop(levels[lev]) if big_pop==WHITE: return elif big_pop==BLACK: PopGreys(off, len) return; else : len /= 2 lev=lev+1 UnCompress(off, len, lev) UnCompress(off + len, len, lev) UnCompress(off + len * LENGTH, len, lev) UnCompress(off + len * LENGTH + len, len, lev) return def UnCompAll(fbuf): global B global F B=0L #B is a long integer # convert base 94 to base 256 kl = len(fbuf) for i in range(0,kl): B=B*NUMPRINTS B=B+(ord(fbuf[i]) - FIRSTPRINT) # empty icon for i in range(0,PIXELS): F[i] = 0 #uncompress UnCompress(0, 16, 0) UnCompress(16, 16, 0) UnCompress(32, 16, 0) UnCompress(768, 16, 0) UnCompress(784, 16, 0) UnCompress(800, 16, 0) UnCompress(1536, 16, 0) UnCompress(1552, 16, 0) UnCompress(1568, 16, 0) def Gen(): global F m= l= k= j= i= h=0 for j in range(0,LENGTH): for i in range(0,LENGTH): k = 0 for l in range(i-2,i+2+1): for m in range(j-2,j+1): if ((l >= i) and (m == j)): continue if ((l > 0) and (l <= LENGTH) and (m > 0)): if F[l+m*LENGTH]: k=k*2+1 else: k=k*2 if i== 1 : if j== 1 : F[h] ^= G["g_22"][k] elif j== 2 : F[h] ^= G["g_21"][k] else : F[h] ^= G["g_20"][k] elif i== 2 : if j== 1 : F[h] ^= G["g_12"][k] elif j== 2 : F[h] ^= G["g_11"][k] else : F[h] ^= G["g_10"][k] elif i== LENGTH - 1 : if j== 1 : F[h] ^= G["g_42"][k] elif j== 2 : F[h] ^= G["g_41"][k] else : F[h] ^= G["g_40"][k] elif i== LENGTH : if j== 1 : F[h] ^= G["g_32"][k] elif j== 2 : F[h] ^= G["g_31"][k] else : F[h] ^= G["g_30"][k] else : if j== 1 : F[h] ^= G["g_02"][k] elif j== 2 : F[h] ^= G["g_01"][k] else : F[h] ^= G["g_00"][k] h=h+1 def parseInt(num_string): '''It should convert the numeric string in to a number base 2. For example parseInt("1111") returns 15 If it finds a character that is not in base 2 it stops there converting the leftmost part''' num="" for char in num_string: if char=="0" or char=="1": num=num+char else: break conv=0 for i in range(len(num)-1,-1,-1): conv=conv+int(num[len(num)-1-i])*pow(2,i) return conv def join_num(list): string_list=[] for item in list: string_list.append(str(item)) return "".join(string_list) def replacer1(matchobject): g=matchobject.group(0) return g+"," def replacer2(matchobject): g1,g2,g3,g4,g5,g6= matchobject.groups() return chr(parseInt(g1))+\ chr(parseInt(g2))+\ chr(parseInt(g3))+\ chr(parseInt(g4))+\ chr(parseInt(g5))+\ chr(parseInt(g6)) + "\0\0" def XFaceToBMP(face): global F face=re.sub("[^!-~]","",face) UnCompAll(face) Gen() bmp = "BM\xBE\1\0\0\0\0\0\0>\0\0\0(\0\0\0\x30\0\0\0\x30\0\0\0\1\0\1\0\0\0\0\0\x80\1\0\0\xC4\x0E\0\0\xC4\x0E\0\0\0\0\0\0\0\0\0\0\xFF\xFF\xFF\0\0\0\0\0"; ff=join_num(F) ff=re.sub("(.{48})",replacer1,ff) ff_l=ff.split(",") ff_l.reverse() ff="".join(ff_l) ff=re.sub("(.{8})(.{8})(.{8})(.{8})(.{8})(.{8})",replacer2,ff) bmp=bmp+ff return bmp def XFaceToBuffer(face): global F face=re.sub("[^!-~]","",face) UnCompAll(face) Gen() ff=join_num(F) buff_pos=ff.replace("1",chr(0)).replace("0",chr(255)) return buff_pos xpn-1.2.6/xpn_src/Outbox_Manager.py0000644000175000017500000005612411141275756015434 0ustar antantimport gtk import gobject import os import cPickle import ConfigParser from email.Utils import parsedate,parsedate_tz,mktime_tz from time import ctime from xpn_src.UserDir import get_wdir from xpn_src.Edit_Win import Edit_Win from xpn_src.Edit_Mail_Win import Edit_Mail_Win from xpn_src.Charset_List import load_ordered_list from xpn_src.Article import Article_To_Send,Mail_To_Send from xpn_src.Connections_Handler import Connection,SMTPConnection, SSLConnection from xpn_src.KeyBindings import load_shortcuts ui_string=""" """ class Outbox_Manager: def show(self): self.win.show_all() def delete_event(self,widget,event,data=None): self.outboxwin_width,self.outboxwin_height=self.win.get_size() self.save_sizes() return False def destroy(self,obj): self.save_sizes() self.win.destroy() def populateFolderTree(self): """Builds the Folder Tree content""" folder_icon=gtk.gdk.pixbuf_new_from_file("pixmaps/folder.xpm") folder_open_icon=gtk.gdk.pixbuf_new_from_file("pixmaps/folder_open.xpm") model,iter_selected=self.folderTree.get_selection().get_selected() if iter_selected: path=model.get_path(iter_selected) else: path=None model=self.folderTree.get_model() model.clear() iterOutbox=model.insert_before(None,None) model.set_value(iterOutbox,0,_("OutBox")) model.set_value(iterOutbox,2,folder_open_icon) iterOutboxArticle=model.insert_before(iterOutbox,None) model.set_value(iterOutboxArticle,0,_("OutGoing Articles")) model.set_value(iterOutboxArticle,2,folder_icon) iterOutboxMail=model.insert_before(iterOutbox,None) model.set_value(iterOutboxMail,0,_("OutGoing Mails")) model.set_value(iterOutboxMail,2,folder_icon) iterDraft=model.insert_before(None,None) model.set_value(iterDraft,0,_("Drafts")) model.set_value(iterDraft,2,folder_open_icon) iterDraftArticle=model.insert_before(iterDraft,None) model.set_value(iterDraftArticle,0,_("Draft Articles")) model.set_value(iterDraftArticle,2,folder_icon) iterDraftMail=model.insert_before(iterDraft,None) model.set_value(iterDraftMail,0,_("Draft Mails")) model.set_value(iterDraftMail,2,folder_icon) iterSent=model.insert_before(None,None) model.set_value(iterSent,0,_("Sent")) model.set_value(iterSent,2,folder_open_icon) iterSentArticle=model.insert_before(iterSent,None) model.set_value(iterSentArticle,0,_("Sent Articles")) model.set_value(iterSentArticle,2,folder_icon) iterSentMail=model.insert_before(iterSent,None) model.set_value(iterSentMail,0,_("Sent Mails")) model.set_value(iterSentMail,2,folder_icon) self.folderTree.expand_all() try: articles=os.listdir(os.path.join(self.wdir,"outbox/news")) except: self.statusbar.push(1,_("Problems while opening News OutBox")) else: total=len(articles) model.set_value(iterOutboxArticle,1,total) try: articles=os.listdir(os.path.join(self.wdir,"outbox/mail")) except: self.statusbar.push(1,_("Problems while opening Mail OutBox")) else: total=len(articles) model.set_value(iterOutboxMail,1,total) try: articles=os.listdir(os.path.join(self.wdir,"draft/news")) except: self.statusbar.push(1,_("Problems while opening News Drafts")) else: total=len(articles) model.set_value(iterDraftArticle,1,total) try: articles=os.listdir(os.path.join(self.wdir,"draft/mail")) except: self.statusbar.push(1,_("Problems while opening Mail Drafts")) else: total=len(articles) model.set_value(iterDraftMail,1,total) try: articles=os.listdir(os.path.join(self.wdir,"sent/news")) except: self.statusbar.push(1,_("Problems while opening Sent Articles")) else: total=len(articles) model.set_value(iterSentArticle,1,total) try: articles=os.listdir(os.path.join(self.wdir,"sent/mail")) except: self.statusbar.push(1,_("Problems while opening Sent Mails")) else: total=len(articles) model.set_value(iterSentMail,1,total) if path: column=self.folderTree.get_column(0) self.folderTree.set_cursor(path,None,False) self.folderTree.row_activated(path,column) def openFolder(self,*params): """Opens the selected folder and loads the articles/mails inside it""" model,iter_selected=self.folderTree.get_selection().get_selected() if iter_selected: path=model.get_path(iter_selected) else: path=[] if len(path)>1: folderName="" isMail=False if path[0]==0: folderName="outbox/" elif path[0]==1: folderName="draft/" else : folderName="sent/" if path[1]==0: folderName+="news" else: folderName+="mail" isMail="mail" in folderName try: articles=os.listdir(os.path.join(self.wdir,folderName)) except: self.statusbar.push(1,_("Problems while opening folder :")+folderName) else: model=self.previewTree.get_model() model.clear() for articleName in articles: try: pathToArticle=os.path.join(self.wdir,folderName,articleName) f=open(pathToArticle,"rb") except: self.statusbar.push(1,_("Problems while opening article :")+articleName) else: article=cPickle.load(f) f.close() self.previewArticle(article,isMail,os.path.join(folderName,articleName)) else: self.previewTree.get_model().clear() def parse_date(self,date): #data=parsedate(date) try: #trying to prevent the rfc822.parsedate bug with Tue,26 instead of Tue, 26 secs=mktime_tz(parsedate_tz(date)) except: secs=time() data=parsedate(ctime(secs)) if data[3]<10: ora="0"+repr(data[3]) else: ora=repr(data[3]) if data[4]<10: minuti="0"+repr(data[4]) else: minuti=repr(data[4]) return repr(data[2])+"/"+repr(data[1])+"/"+repr(data[0])+" "+ora+":"+minuti,secs def previewArticle(self,article,isMail,relativePathToArticle): """Shows a summary of the article/mail""" model=self.previewTree.get_model() iter_new=model.insert_before(None,None) subj=article.get("subject","") if isMail: to=article.get("to_name","") else: to=article.get("newsgroups","") date=article.get("date","") date_parsed,secs=self.parse_date(date) model.set_value(iter_new,0,subj.encode("utf-8")) model.set_value(iter_new,1,to.encode("utf-8")) model.set_value(iter_new,2,date_parsed) model.set_value(iter_new,3,article) model.set_value(iter_new,4,isMail) model.set_value(iter_new,5,relativePathToArticle) model.set_value(iter_new,6,secs) def openArticle(self,*params): """Opens the article/mail in the edit window""" model,iterSelected=self.previewTree.get_selection().get_selected() if iterSelected: article=model.get_value(iterSelected,3) isMail=model.get_value(iterSelected,4) rPath=model.get_value(iterSelected,5) isSent=rPath.startswith("sent") server_name=article.get("server_name","") if isMail: editWin=Edit_Mail_Win(self.configs,article.get("to_name",""),None,None,"Draft",article,rPath,self,isSent,id_name=article.get("id_name","")) else: editWin=Edit_Win(self.configs,article.get("newsgroups",""),None,None,self.subscribedGroups,"Draft",article,rPath,self,isSent,server_name,id_name=article.get("id_name","")) editWin.show() def deleteArticle(self,*params): """Deletes the article/mail selected""" model,iterSelected=self.previewTree.get_selection().get_selected() if iterSelected: article=model.get_value(iterSelected,3) isMail=model.get_value(iterSelected,4) rPath=model.get_value(iterSelected,5) try: os.remove(os.path.join(self.wdir,rPath)) except: self.statusbar.push(1,_("Problems while deleting the article: %s" % (os.path.join(self.wdir,rPath)))) else: self.statusbar.push(1,_("Article Deleted")) self.populateFolderTree() def store_article(self,dirName,article_backup): try: out_files=os.listdir(dirName) except: self.statusbar.push(1,_("Problems while opening : ")+dirName) else: num=len(out_files) numbers=map(int,out_files) if not numbers:numbers=[-1] number=max((max(numbers),num)) f=open(os.path.join(dirName,str(number+1)),"wb") cPickle.dump(article_backup,f,1) f.close() def sendQueuedArticles(self,obj): '''Send articles stored in outbox''' ordered_list=load_ordered_list() user_agent=self.VERSION try: articles=os.listdir(os.path.join(self.wdir,"outbox/news")) except: self.statusbar.push(1,_("Problems while opening News OutBox")) else: total=len(articles) news_sent=total cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) self.connectionsPool=dict() for server in cp.sections(): if cp.get(server,"nntp_use_ssl")=="True": self.connectionsPool[server]=SSLConnection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) else: self.connectionsPool[server]=Connection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) i=0 for articleName in articles: i=i+1 try: f=open(os.path.join(self.wdir,"outbox/news/",articleName),"rb") except: self.statusbar.push(1,_("Problems while opening article :")+articleName) else: self.statusbar.push(1,_("Sending Article: ")+articleName) while gtk.events_pending(): gtk.main_iteration(False) draftArticle=cPickle.load(f) f.close() newsgroups=draftArticle.get("newsgroups","") from_name=draftArticle.get("from_name","") subject=draftArticle.get("subject","") references=draftArticle.get("references","") output_charset=draftArticle.get("output_charset","") body=draftArticle.get("body","") custom_names=draftArticle.get("custom_names",[]) custom_values=draftArticle.get("custom_values",[]) article_to_send=Article_To_Send(newsgroups,from_name,subject,references,user_agent,output_charset,ordered_list,body,custom_names,custom_values,self.configs["gen_mid"],self.configs["fqdn"]) article=article_to_send.get_article() server_name=draftArticle.get("server_name","") message,articlePosted=self.connectionsPool[server_name].sendArticle(article) self.statusbar.push(1,message) if articlePosted: os.remove(os.path.join(self.wdir,"outbox/news/",articleName)) self.store_article(os.path.join(self.wdir,"sent/news"),draftArticle) else: news_sent=news_sent-1 while gtk.events_pending(): gtk.main_iteration(False) self.statusbar.push(1,_("Sent %d Articles") % (news_sent,)) for connection in self.connectionsPool.itervalues(): connection.closeConnection() self.populateFolderTree() def sendQueuedMails(self,obj): '''Send mails stored in outbox''' ordered_list=load_ordered_list() user_agent=self.VERSION try: mails=os.listdir(os.path.join(self.wdir,"outbox/mail")) except: self.statusbar.push(1,_("Problems while opening Mail OutBox")) else: total=len(mails) mail_sent=total i=0 self.mailConnection=SMTPConnection(self.configs["smtp_server"],int(self.configs["smtp_port"]),self.configs["smtp_auth"],self.configs["smtp_username"],self.configs["smtp_password"]) for mailName in mails: i=i+1 try: f=open(os.path.join(self.wdir,"outbox/mail/",mailName),"rb") except: self.statusbar.push(1,_("Problems while opening mail :")+mailName) else: self.statusbar.push(1,_("Sending Mail: ")+mailName) while gtk.events_pending(): gtk.main_iteration(False) draftMail=cPickle.load(f) f.close() to_name=draftMail.get("to_name","") from_name=draftMail.get("from_name","") subject=draftMail.get("subject","") references=draftMail.get("references","") output_charset=draftMail.get("output_charset","") body=draftMail.get("body","") date=draftMail.get("date","") mail_to_send=Mail_To_Send(to_name,from_name,date,subject,references,user_agent,output_charset,ordered_list,body) mail=mail_to_send.get_article() f.close() message,mailSent=self.mailConnection.sendMail(from_name,to_name,mail) self.statusbar.push(1,message) if mailSent: os.remove(os.path.join(self.wdir,"outbox/mail/",mailName)) self.store_article(os.path.join(self.wdir,"sent/mail"),draftMail) else: mail_sent=mail_sent-1 while gtk.events_pending(): gtk.main_iteration(False) self.statusbar.push(1,_("Sent %d Mails") % (mail_sent,)) self.mailConnection.closeConnection() self.populateFolderTree() def save_sizes(self): try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"rb") except IOError: sizes={} else: sizes=cPickle.load(f) if not self.outboxwin_width: sizes["outboxwin_width"],sizes["outboxwin_height"]=self.win.get_size() else: sizes["outboxwin_width"]=self.outboxwin_width sizes["outboxwin_height"]=self.outboxwin_height sizes["outboxwin_pos_x"],sizes["outboxwin_pos_y"]=self.win.get_position() sizes["outboxwin_col_subject"]=self.previewTreeColumnSubject.get_width() sizes["outboxwin_col_to"]=self.previewTreeColumnTo.get_width() try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"wb") except IOError: pass else: cPickle.dump(sizes,f,1) f.close() def set_sizes(self): try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"rb") except IOError: self.win.maximize() else: sizes=cPickle.load(f) f.close() outboxwin_width=sizes.get("outboxwin_width",None) outboxwin_height=sizes.get("outboxwin_height",None) if outboxwin_width and outboxwin_height: self.win.resize(int(outboxwin_width),int(outboxwin_height)) else: self.win.maximize() outboxwin_pos_x=sizes.get("outboxwin_pos_x",None) outboxwin_pos_y=sizes.get("outboxwin_pos_y",None) self.previewTreeColumnSubject.set_fixed_width(int(sizes.get("outboxwin_col_subject",350))) self.previewTreeColumnTo.set_fixed_width(int(sizes.get("outboxwin_col_to",150))) if outboxwin_pos_x and outboxwin_pos_y: self.win.move(int(outboxwin_pos_x),int(outboxwin_pos_y)) def create_ui(self): self.ui = gtk.UIManager() accelgroup = self.ui.get_accel_group() actiongroup= gtk.ActionGroup("OutboxWindowActions") self.win.add_accel_group(accelgroup) obcuts=load_shortcuts("outbox") actions=[("Outbox",None,_("_Outbox")), ("send_article","xpn_send_queued_art",_("_Send Queued Articles"),obcuts["send_article"],_("Send Queued Articles"),self.sendQueuedArticles), ("send_mail","xpn_send_queued_mail",_("Send Queued _Mails"),obcuts["send_mail"],_("Send Queued Mails"),self.sendQueuedMails), ("edit","xpn_post",_("_Edit Article/Mail"),obcuts["edit"],_("Edit Article/Mail"),self.openArticle), ("delete","xpn_delete",_("_Delete Article/Mail"),obcuts["delete"],_("Delete Article/Mail"),self.deleteArticle), ("exit","xpn_exit",_("_Exit"),obcuts["exit"],_("Exit"),self.destroy)] for action in actions: if len(action)<7: actiongroup.add_actions([action]) else: actiongroup.add_actions([action[0:6]],action[6:]) self.ui.insert_action_group(actiongroup,0) merge_id = self.ui.add_ui_from_string(ui_string) def __init__(self,mainWin,VERSION): self.configs=mainWin.configs self.VERSION=VERSION self.subscribedGroups=mainWin.subscribed_groups self.win=gtk.Window(gtk.WINDOW_TOPLEVEL) self.win.connect("delete_event",self.delete_event) #self.win.connect("destroy",self.destroy) self.win.set_title(_("Outbox Manager")) self.win.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/outbox.xpm")) vbox=gtk.VBox() #MenuBar self.create_ui() menubar=self.ui.get_widget("/OutboxMenuBar") vbox.pack_start(menubar,False,True) menubar.show() #ToolBar toolbar=self.ui.get_widget("/OutboxToolBar") vbox.pack_start(toolbar,False,True) toolbar.show() #toolbar.set_icon_size(gtk.ICON_SIZE_LARGE_TOOLBAR) toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) toolbar.set_style(gtk.TOOLBAR_ICONS) toolbar.set_style(gtk.SHADOW_NONE) self.win.add(vbox) #HBox hpaned=gtk.HPaned() vbox.pack_start(hpaned,True,True) #Folder Tree self.folderTree=gtk.TreeView() model=gtk.TreeStore(gobject.TYPE_STRING,gobject.TYPE_STRING,gtk.gdk.Pixbuf) self.folderTree.set_model(model) text_renderer_bold=gtk.CellRendererText() text_renderer_bold.set_property("weight",1000) text_renderer_number=gtk.CellRendererText() text_renderer_number.set_property("xalign",.5) pix_renderer=gtk.CellRendererPixbuf() self.folderTreeColumnFolder=gtk.TreeViewColumn(_("Folder")) self.folderTreeColumnFolder.pack_start(pix_renderer) self.folderTreeColumnFolder.pack_start(text_renderer_bold) self.folderTreeColumnFolder.set_attributes(pix_renderer,pixbuf=2) self.folderTreeColumnFolder.set_attributes(text_renderer_bold,text=0) self.folderTreeColumnNumber=gtk.TreeViewColumn(_("Number"),text_renderer_number,text=1) self.folderTree.append_column(self.folderTreeColumnFolder) self.folderTree.append_column(self.folderTreeColumnNumber) #self.folderTree.set_expander_column(self.folderTreeColumn) hpaned.add(self.folderTree) #Preview Tree scrolledwin=gtk.ScrolledWindow() scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.previewTree=gtk.TreeView() scrolledwin.add(self.previewTree) # 0: Subject, 1: Newsgroups/To, 2: Date, 3: Article, 4: IsMail, 5: PathToArticle, 6: Seconds model=gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_PYOBJECT,gobject.TYPE_BOOLEAN,gobject.TYPE_STRING,gobject.TYPE_INT) self.previewTree.set_model(model) text_renderer=gtk.CellRendererText() self.previewTreeColumnSubject=gtk.TreeViewColumn(_("Subject"),text_renderer,text=0) self.previewTreeColumnSubject.set_resizable(True) self.previewTreeColumnSubject.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.previewTreeColumnSubject.set_fixed_width(300) self.previewTreeColumnSubject.set_sort_column_id(0) self.previewTreeColumnTo=gtk.TreeViewColumn(_("Newsgroups/To"),text_renderer,text=1) self.previewTreeColumnTo.set_resizable(True) self.previewTreeColumnTo.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.previewTreeColumnTo.set_fixed_width(150) self.previewTreeColumnTo.set_sort_column_id(1) self.previewTreeColumnDate=gtk.TreeViewColumn(_("Date"),text_renderer,text=2) self.previewTreeColumnDate.set_sort_column_id(6) self.previewTree.append_column(self.previewTreeColumnSubject) self.previewTree.append_column(self.previewTreeColumnTo) self.previewTree.append_column(self.previewTreeColumnDate) hpaned.add(scrolledwin) model.set_sort_column_id(6,gtk.SORT_ASCENDING) self.statusbar=gtk.Statusbar() vbox.pack_start(self.statusbar,False,True) #self.win.maximize() self.wdir=get_wdir() #self.folderTree.connect("row_activated",self.openFolder) self.folderTree.get_selection().connect("changed",self.openFolder) self.previewTree.connect("row_activated",self.openArticle) self.set_sizes() self.outboxwin_width=None self.outboxwin_height=None self.populateFolderTree() xpn-1.2.6/xpn_src/Show_Logs.py0000644000175000017500000000704511141275756014424 0ustar antant#!/usr/bin/env python import gtk import os from xpn_src.UserDir import get_wdir class Logs_Window: def delete_event(self,widget,event,data=None): return False def destroy(self,widget): self.window.destroy() if __name__=="__main__": gtk.mainquit() def insert(self,string): mark=self.buffer.get_insert() iter=self.buffer.get_iter_at_mark(mark) time,log=string.split("::") if ">>" in string: self.buffer.insert_with_tags_by_name(iter,(time+"::").encode("utf-8"),"time") mark=self.buffer.get_insert() iter=self.buffer.get_iter_at_mark(mark) self.buffer.insert_with_tags_by_name(iter,log.encode("utf-8"),"blue") else: self.buffer.insert_with_tags_by_name(iter,(time+"::").encode("utf-8"),"time") mark=self.buffer.get_insert() iter=self.buffer.get_iter_at_mark(mark) self.buffer.insert_with_tags_by_name(iter,log.encode("utf-8"),"red") def load_logs(self): try: f=open(self.FILENAME,"r") except IOError: length="0" else: logs=f.readlines() for line in logs: self.insert(line) f.close() def __init__(self,main_win): self.FILENAME=os.path.join(get_wdir(),"server_logs.dat") self.window=gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event",self.delete_event) self.window.connect("destroy",self.destroy) self.window.set_title(_("Server Logs Viewer")) self.window.set_position(gtk.WIN_POS_CENTER) if main_win!=None: self.window.set_modal(True) self.window.set_transient_for(main_win) vbox=gtk.VBox(False,0) vbox.set_border_width(2) label=gtk.Label("\n"+_("Server Logs")+"\n") label.set_use_markup(True) vbox.pack_start(label,False,True,0) self.buffer=gtk.TextBuffer() scrolledwin=gtk.ScrolledWindow() scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) scrolledwin.set_border_width(4) self.view=gtk.TextView(self.buffer) self.view.set_wrap_mode(gtk.WRAP_WORD) self.view.set_justification(gtk.JUSTIFY_LEFT) self.view.set_cursor_visible(False) self.view.set_editable(False) self.view.set_indent(2) scrolledwin.add(self.view) blue_color=gtk.gdk.color_parse("blue") red_color=gtk.gdk.color_parse("red") black_color=gtk.gdk.color_parse("black") self.tag_table=self.buffer.get_tag_table() self.blue_tag=gtk.TextTag("blue") self.red_tag=gtk.TextTag("red") self.time_tag=gtk.TextTag("time") self.tag_table.add(self.blue_tag) self.tag_table.add(self.red_tag) self.tag_table.add(self.time_tag) self.blue_tag.set_property("foreground-gdk",blue_color) self.red_tag.set_property("foreground-gdk",red_color) self.time_tag.set_property("foreground-gdk",black_color) vbox.pack_start(scrolledwin,True,True,0) self.button=gtk.Button(None,gtk.STOCK_OK) self.button.set_border_width(4) self.button.connect("clicked",self.destroy) vbox.pack_start(self.button,False,True,0) self.window.add(vbox) self.window.set_default_size(550,500) self.window.show_all() self.load_logs() if __name__=="__main__": logs_win=Logs_Window(None) gtk.mainloop() xpn-1.2.6/xpn_src/Groups_Win.py0000700000175000017500000004514611141275756014611 0ustar antantimport sys import gtk import gobject import socket import time import re import threading, Queue import os,shutil import ConfigParser from nntplib import * from string import find from email.Utils import parsedate_tz,mktime_tz from xpn_src.Groups_Pane import Groups_Pane,Groups_List from xpn_src.ListThread import ListThread from xpn_src.Article import Article from xpn_src.Config_File import Config_File from xpn_src.Connections_Handler import Connection, SSLConnection from xpn_src.UserDir import get_wdir from xpn_src.Dialogs import Dialog_OK from xpn_src.Articles_DB import Articles_DB,Groups_DB try: set() except: from sets import Set as set class Groups_Win: def show(self): self.win.show_all() def delete_event(self,widget,event,data=None): return False def destroy(self,obj): for connection in self.connectionsPool.itervalues(): connection.closeConnection() self.win.destroy() def handle_error(self, error_strings): self.statusbar.push(1, error_strings[1]) self.add_log(error_strings[1],False) for connection in self.connectionsPool.itervalues(): connection.closeConnection() return 1 def connected(self, response): self.statusbar.push(1, response[1]) self.add_log(response[1],False) def ended_listing(self, data): lock = threading.Lock() lock.acquire() groups_list = self.listThread.queue.get() lock.release() groups_list.sort() server_name=self.server_combo.get_active_text() self.groups_list_db.createList(groups_list,server_name) self.update_total_list() return 1 def update_total_list(self): file_list=os.listdir(os.path.join(self.wdir,"groups_info")) total_list=[] for file_name in file_list: if file_name.endswith(".groups.sqlitedb"): groups_list=self.groups_list_db.getList(file_name) total_list += groups_list self.total_list=total_list self.groups_list_db.createList(total_list,"","groups.sqlitedb") self.server_list.show_list(self.total_list) def get_list(self,obj): lock = threading.Lock() server=self.server_combo.get_active_text() message,connection_is_up=self.connectionsPool[server]._tryConnection() self.statusbar.push(1,message) if connection_is_up: self.listThread = ListThread(self.connectionsPool[server].serverConnection,server) self.listThread.start() self.statusbar.push(1,_("Please wait, I'm downloading the list")) finished = 0 timer=10 while 1: while gtk.events_pending(): gtk.main_iteration(False) time.sleep(0.001) lock.acquire() try: evt = self.listThread.queue.get_nowait() except Queue.Empty: evt = [None, None] lock.release() _dispatch = {"Connected":self.connected, "Server error":self.handle_error, "Finished Listing":self.ended_listing } if evt[0]!=None: handler = _dispatch.get(evt[0],None) else: handler = None if handler: finished = handler(evt) else: timer=timer-1 if timer<0: self.progressbar.pulse() timer=10 if finished: self.progressbar.set_fraction(0) break def show_subscribed(self): list=self.art_db.getSubscribed() new_list=[] for group in list: total,unread_number=self.art_db.getArticlesNumbers(group[0]) new_list.append((group[0],total)) self.subscribed_list.show_list(new_list) def search_group(self,obj): group_to_search=self.group_entry.get_text() use_regex=self.regex_checkbutton.get_active() def match_regex(field,regex): try: match_rule=re.compile(regex,re.UNICODE).findall(field) except: match_rule=False return match_rule if use_regex: match_rule=lambda field,regex: match_regex(field,regex) else: match_rule=lambda field,word: field.find(word)+1 list=self.total_list i=0 found=[] self.statusbar.push(1,_("Searching...")) while (i> "+message+"\n") else: f.write(time.ctime(time.time())+" :: << "+message+"\n") f.close() def __init__(self,main_win): self.wdir=get_wdir() self.conf=Config_File() self.configs=self.conf.get_configs() cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) self.connectionsPool=dict() for server in cp.sections(): if cp.get(server,"nntp_use_ssl")=="True": self.connectionsPool[server]=SSLConnection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) else: self.connectionsPool[server]=Connection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) self.art_db=main_win.art_db self.groups_list_db=Groups_DB() self.main_win=main_win self.win=gtk.Window(gtk.WINDOW_TOPLEVEL) self.win.set_modal(True) self.win.set_transient_for(main_win.window) self.win.connect("delete_event",self.delete_event) self.win.set_title(_("NewsGroups")) self.win.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/groups.xpm")) self.win.set_default_size(700,480) self.win.set_position(gtk.WIN_POS_CENTER) #main vbox self.vbox1 = gtk.VBox(False,0) self.vbox1.set_border_width(2) self.win.add(self.vbox1) #hpaned self.hpaned =gtk.HPaned() self.hpaned.set_position(310) self.vbox1.pack_start(self.hpaned,True,True,0) #FrameList self.frame_list=gtk.Frame(_("List")) self.hpaned.add(self.frame_list) #VBoxList self.vbox_list=gtk.VBox() self.vbox_list.set_border_width(2) self.frame_list.add(self.vbox_list) #HBoxList self.hbox_list=gtk.HBox() self.vbox_list.pack_start(self.hbox_list,False,True,2) #group_entry self.group_entry=gtk.Entry() self.hbox_list.pack_start(self.group_entry,True,True,2) #search_button self.search_button=gtk.Button(_("Search Group")) self.search_button.connect("clicked",self.search_group) self.hbox_list.pack_start(self.search_button,False,True,2) self.search_button_tooltip=gtk.Tooltips() self.search_button_tooltip.set_tip(self.search_button,_("Start searching")) #live search check_button self.live_search_checkbutton=gtk.CheckButton(_("Perform Live Search")) self.vbox_list.pack_start(self.live_search_checkbutton,False,True,2) self.live_search_checkbutton.connect("clicked",self.change_live_search_status) #regex check_button self.regex_checkbutton=gtk.CheckButton(_("Use Regular Expression")) self.vbox_list.pack_start(self.regex_checkbutton,False,True,2) #full list button self.full_button=gtk.Button(_("Show Full List")) self.full_button.connect("clicked",self.show_full_list) self.vbox_list.pack_start(self.full_button,False,True,2) #GroupsList self.server_list=Groups_List(_("NewsGroups"),_("Mode"),_("Server")) self.server_list.groups_list.set_rules_hint(1) self.server_list.groups_list.connect("row-activated", lambda *w: self.subscribe_selected_groups(None)) self.vbox_list.pack_start(self.server_list.get_widget(),True,True,2) #right_vbox self.right_vbox =gtk.VBox() self.hpaned.add(self.right_vbox) #right_hbox self.right_hbox=gtk.HBox() self.right_vbox.pack_start(self.right_hbox,False,True,0) #Server Frame self.server_frame =gtk.Frame(_("Server")) self.right_hbox.pack_start(self.server_frame,True,True,0) #Server HBox self.server_hbox=gtk.HBox() self.server_frame.add(self.server_hbox) self.server_hbox.set_border_width(5) #Server Button self.server_button=gtk.Button(_("Get Newsgroups List")) self.server_button.connect("clicked",self.get_list) self.server_hbox.pack_start(self.server_button,False,True,5) self.server_button_tooltip=gtk.Tooltips() self.server_button_tooltip.set_tip(self.server_button,_("This could take several minutes")) #Server Label self.server_combo= gtk.combo_box_new_text() for server in cp.sections(): self.server_combo.append_text(cp.get(server,"server")) self.server_combo.set_active(0) if len(cp.sections())==0: self.server_button.set_sensitive(False) self.server_hbox.pack_start(self.server_combo,False,True,5) #Article Frame self.articles_frame =gtk.Frame(_("Articles Number")) self.right_hbox.pack_start(self.articles_frame,False,True,0) #Articles SpinButton self.articles_spinbutton =gtk.SpinButton(gtk.Adjustment(value=500,lower=0,upper=10000,step_incr=1,page_incr=50)) self.articles_spinbutton_tooltip=gtk.Tooltips() self.articles_spinbutton_tooltip.set_tip(self.articles_spinbutton,_("Download this number of articles (headers only)")) self.articles_frame.add(self.articles_spinbutton) #Subscribed Frame self.subscribed_frame= gtk.Frame(_("Subscribed Groups")) self.right_vbox.pack_start(self.subscribed_frame,True,True,2) #Subscribed_hbox self.subscribed_hbox = gtk.HBox() self.subscribed_frame.add(self.subscribed_hbox) #button_box self.vbutton_box=gtk.VButtonBox() self.subscribed_hbox.pack_start(self.vbutton_box,False,False,0) self.vbutton_box.set_layout(gtk.BUTTONBOX_SPREAD) #button_subscribe self.button_subscribe=gtk.Button() self.button_subscribe.connect("clicked",self.subscribe_selected_groups) button_subscribe_image=gtk.Image() button_subscribe_image.set_from_stock(gtk.STOCK_GO_FORWARD,gtk.ICON_SIZE_MENU) self.button_subscribe.add(button_subscribe_image) self.vbutton_box.pack_start(self.button_subscribe,False,False,0) self.subscribe_button_tooltip=gtk.Tooltips() self.subscribe_button_tooltip.set_tip(self.button_subscribe,_("Subscribe selected groups")) #button_unsubscribe self.button_unsubscribe=gtk.Button() self.button_unsubscribe.connect("clicked",self.unsubscribe_selected_groups) button_unsubscribe_image=gtk.Image() button_unsubscribe_image.set_from_stock(gtk.STOCK_GO_BACK,gtk.ICON_SIZE_MENU) self.button_unsubscribe.add(button_unsubscribe_image) self.vbutton_box.pack_start(self.button_unsubscribe,False,False,0) self.unsubscribe_button_tooltip=gtk.Tooltips() self.unsubscribe_button_tooltip.set_tip(self.button_unsubscribe,_("UnSubscribe selected groups")) #subscribed_groups self.subscribed_list=Groups_Pane(_("NewsGroups"),_("Articles"),False,self.configs) self.subscribed_list.groups_list.connect("row-activated", lambda *w: self.unsubscribe_selected_groups(None)) #Subscribed_vbox self.subscribed_vbox= gtk.VBox() self.subscribed_vbox.pack_start(self.subscribed_list.get_widget(),True,True,5) #subscribe manually self.subscribe_manually_entry=gtk.Entry() self.subscribe_manually_button=gtk.Button(_("Subscribe Manually")) subscribe_manually_hbox=gtk.HBox() subscribe_manually_hbox.add(self.subscribe_manually_entry) subscribe_manually_hbox.add(self.subscribe_manually_button) self.subscribe_manually_button.connect("clicked",self.subscribe_manually) self.subscribed_vbox.pack_start(subscribe_manually_hbox,False,False) self.subscribed_hbox.pack_start(self.subscribed_vbox,True,True) #button_close self.button_close= gtk.Button(None,gtk.STOCK_OK) self.vbox1.pack_start(self.button_close,False,True,4) self.button_close.connect("clicked",self.destroy) self.button_close_tooltip=gtk.Tooltips() self.button_close_tooltip.set_tip(self.button_close,_("Close this window")) #hbox_bottom self.hbox_bottom=gtk.HBox() self.vbox1.pack_start(self.hbox_bottom,False,False,0) #progressbar self.progressbar=gtk.ProgressBar() self.hbox_bottom.pack_start(self.progressbar,False,False,0) #statusbar self.statusbar=gtk.Statusbar() self.hbox_bottom.pack_start(self.statusbar,True,True,0) #some inits self.show_subscribed() self.show() self.statusbar.push(1,_("Building Newsgroups list")) self.total_list=[] while gtk.events_pending(): gtk.main_iteration(False) try: f=open(os.path.join(self.wdir,"groups_info/groups.sqlitedb"),"rb") except IOError: self.statusbar.push(1,_("You have to download newsgroups list")) else: groups_list=self.groups_list_db.getList("groups.sqlitedb") self.total_list=groups_list self.server_list.show_list(groups_list) self.statusbar.push(1,_("Newsgroups list loaded")) xpn-1.2.6/xpn_src/add_tag.py0000644000175000017500000000522111141275756014075 0ustar antant#!/usr/bin/env python import gtk import os from locale import getdefaultlocale from xpn_src.UserDir import get_wdir class Tags_Window: def delete_event(self,widget,event,data=None): return False def destroy(self,widget): self.window.destroy() if __name__=="__main__": gtk.main_quit() def append_tag(self,widget): try: f=open(self.FILENAME,"a") except IOError: f=open(self.FILENAME,"w") try: system_enc=getdefaultlocale()[1] except: system_enc="US-ASCII" tag=self.entry.get_text().decode("utf-8").encode(system_enc,"replace") if tag!="": f.write(tag+"\n") self.statusbar.push(1,_("TagLine Added")) self.entry.set_text("") f.close() def show_length(self,widget): length=len(self.entry.get_text().decode("utf-8")) self.statusbar.push(1,_("TagLine length: ")+repr(length)) def load_state(self): try: f=open(self.FILENAME,"r") except IOError: length="0" else: length=repr(len(f.readlines())) f.close() self.statusbar.push(1,_("Found %s tags") % (length,)) def __init__(self): self.FILENAME=os.path.join(get_wdir(),"tags.txt") self.window=gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event",self.delete_event) self.window.connect("destroy",self.destroy) self.window.set_title(_("XPN TagLines Manager")) self.window.set_position(gtk.WIN_POS_CENTER) vbox=gtk.VBox(False,0) vbox.set_border_width(2) label=gtk.Label(_("\nInsert here a tagline\n")) label.set_use_markup(True) vbox.pack_start(label,True,True,0) self.entry=gtk.Entry() self.entry.connect("changed",self.show_length) vbox.pack_start(self.entry,False,True,0) hbox_buttons=gtk.HBox() hbox_buttons.set_border_width(4) self.button_ok=gtk.Button(None,gtk.STOCK_ADD) self.button_ok.connect("clicked",self.append_tag) self.button_close=gtk.Button(None,gtk.STOCK_CLOSE) self.button_close.connect("clicked",self.destroy) hbox_buttons.pack_start(self.button_close,True,True,2) hbox_buttons.pack_start(self.button_ok,True,True,2) vbox.pack_start(hbox_buttons,True,True,0) self.statusbar=gtk.Statusbar() vbox.pack_start(self.statusbar,False,True,0) self.window.add(vbox) self.window.set_default_size(550,60) self.window.show_all() self.load_state() if __name__=="__main__": tags_win=Tags_Window() gtk.main() xpn-1.2.6/xpn_src/Groups_Pane.py0000644000175000017500000002411711141275756014741 0ustar antantimport gtk import pango import gobject import cPickle import os from xpn_src.UserDir import get_wdir class Custom_List(gtk.GenericTreeModel): def __init__(self,list=[]): gtk.GenericTreeModel.__init__(self) self.list=list def on_get_flags(self): return gtk.TREE_MODEL_LIST_ONLY|gtk.TREE_MODEL_ITERS_PERSIST def on_get_n_columns(self): return 3 def on_get_column_type(self, index): return gobject.TYPE_STRING def on_get_iter(self, path): try: self.list[path[0]] return path[0] except IndexError: return None return path[0] def on_get_path(self, rowref): return tuple([rowref]) def on_get_value(self, rowref, column): try: return self.list[rowref][column] except IndexError: return None def on_iter_next(self, rowref): try: self.list[rowref+1] except IndexError: return None else: return rowref+1 def on_iter_children(self, parent): return None def on_iter_has_child(self, rowref): return False def on_iter_n_children(self, rowref): if rowref: return 0 return len(self.list) def on_iter_nth_child(self, parent, n): if parent: return None try: self.list[n] except IndexError: return None else: return n def on_iter_parent(self, child): return None class Groups_List: def get_widget(self): return self.scrolledwin def show(self): self.scrolledwin.show_all() def hide(self): self.scrolledwin.hide_all() def clear(self): self.model=Custom_List() self.groups_list.set_model(self.model) def get_selected_rows(self): model,path_list=self.groups_list.get_selection().get_selected_rows() iter_list=[] for path in path_list: iter_list.append(model.get_iter(path)) return model,path_list,iter_list def show_list(self,list): new_model=Custom_List(list) self.groups_list.set_model(new_model) self.model=new_model def get_sizes(self): try: f=open(os.path.join(get_wdir(),"dats/sizes.dat"),"rb") except IOError: column1_width=145 else: sizes=cPickle.load(f) f.close() column1_width=int(sizes.get("groups_col1",145)) return int(column1_width) def __init__(self,column1_name,column2_name,column3_name): #GroupsScrolledWin self.scrolledwin=gtk.ScrolledWindow() self.scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.model=Custom_List() column1_width=self.get_sizes() #GroupsTree self.groups_list=gtk.TreeView(self.model) text_renderer=gtk.CellRendererText() self.column1=gtk.TreeViewColumn(column1_name,text_renderer,text=0) self.column2=gtk.TreeViewColumn(column2_name,text_renderer,text=1) self.column3=gtk.TreeViewColumn(column3_name,text_renderer,text=2) self.column1.set_resizable(True) self.column1.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.column1.set_fixed_width(column1_width) self.column2.set_resizable(True) self.column2.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.column2.set_fixed_width(40) self.column3.set_resizable(False) self.column3.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.groups_list.append_column(self.column1) self.groups_list.append_column(self.column2) self.groups_list.append_column(self.column3) self.scrolledwin.add(self.groups_list) self.groups_list.set_property("fixed-height-mode",True) self.groups_list.get_selection().set_mode(gtk.SELECTION_MULTIPLE) class Groups_Pane: def get_widget(self): return self.scrolledwin def unparent(self): self.scrolledwin.unparent() def show(self): self.scrolledwin.show_all() def hide(self): self.scrolledwin.hide_all() def clear(self): self.model.clear() def set_background(self,color): color=gtk.gdk.color_parse(color) self.groups_list.modify_base(gtk.STATE_NORMAL,color) def set_foreground(self,color): color=gtk.gdk.color_parse(color) self.groups_list.modify_text(gtk.STATE_NORMAL,color) self.groups_list.modify_fg(gtk.STATE_NORMAL,color) def get_selected_rows(self): model,path_list=self.groups_list.get_selection().get_selected_rows() iter_list=[] for path in path_list: iter_list.append(model.get_iter(path)) return model,path_list,iter_list def get_first_selected_row(self): model,path_list=self.groups_list.get_selection().get_selected_rows() if path_list: return model,path_list[0],model.get_iter(path_list[0]) else: return model,tuple(),None def get_first_selected_group(self): model,path_first,iter_first=self.get_first_selected_row() if iter_first: return model.get_value(iter_first,0) else: return None def append(self,values): iter=self.model.append(values) return iter def show_list(self,list,apply_bold=False): self.clear() if apply_bold==True: for group in list: if int(group[1].split(" ")[0])>0: self.append((group[0],group[1],pango.WEIGHT_BOLD)) else: self.append((group[0],group[1],pango.WEIGHT_NORMAL)) else: for group in list: self.append((group[0],group[1],pango.WEIGHT_NORMAL)) def view_next_group(self,obj): model,path,iter_selected=self.get_first_selected_row() if model: column=self.groups_list.get_column(0) self.groups_list.grab_focus() if not iter_selected: next_iter=model.get_iter_first() else: next_iter=model.iter_next(iter_selected) if not next_iter: next_iter=model.get_iter_first() if next_iter: path=model.get_path(next_iter) self.groups_list.set_cursor(path,None,False) self.groups_list.row_activated(path,column) def select_row_by_path(self,path): column=self.groups_list.get_column(0) self.groups_list.set_cursor(path,None,False) self.groups_list.row_activated(path,column) def get_sizes(self): try: f=open(os.path.join(get_wdir(),"dats/sizes.dat"),"rb") except IOError: column1_width=145 else: sizes=cPickle.load(f) f.close() column1_width=int(sizes.get("groups_col1",145)) return int(column1_width) def update_read_vs_unread(self,is_read,insert=True): if (is_read and insert) or (not is_read and not insert): #if the article is read we update the unreads number model,path,iter_selected=self.get_first_selected_row() unread_vs_total_numbers=model.get_value(iter_selected,1) num,tot=unread_vs_total_numbers.split(" ") if insert: number=int(num)+1 else: number=int(num)-1 model.set_value(iter_selected,1,str(number)+" "+tot) if number>=1: model.set_value(iter_selected,2,pango.WEIGHT_BOLD) else:# number<1 model.set_value(iter_selected,2,pango.WEIGHT_NORMAL) def removed_article(self,is_read): model,path,iter_selected=self.get_first_selected_row() unread_vs_total_numbers=model.get_value(iter_selected,1) num,tot=unread_vs_total_numbers.split(" ") tot="("+str(int(tot[1:-1])-1)+")" if not is_read: num=str(int(num)-1) model.set_value(iter_selected,1,num+" "+tot) if int(num)>=1: model.set_value(iter_selected,2,pango.WEIGHT_BOLD) else:# int(num)<1 model.set_value(iter_selected,2,pango.WEIGHT_NORMAL) def __init__(self,column1_name,column2_name,enable_weight,configs): self.enable_weight=enable_weight #GroupsScrolledWin self.scrolledwin=gtk.ScrolledWindow() self.scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) #Model self.model=gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_INT) column1_width=self.get_sizes() #GroupsTree self.groups_list=gtk.TreeView(self.model) text_renderer=gtk.CellRendererText() self.column1=gtk.TreeViewColumn(column1_name,text_renderer,text=0,weight=2) self.column2=gtk.TreeViewColumn(column2_name,text_renderer,text=1,weight=2) self.column1.set_resizable(True) self.column1.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.column1.set_fixed_width(column1_width) self.column1.set_sort_column_id(0) self.column2.set_resizable(False) self.column2.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.groups_list.append_column(self.column1) self.groups_list.append_column(self.column2) self.scrolledwin.add(self.groups_list) self.groups_list.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.model.set_sort_column_id(0,gtk.SORT_ASCENDING) if enable_weight: color=configs["background_color"] self.set_background(color) color=configs["text_color"] self.set_foreground(color) if configs["use_system_fonts"]=="True": self.groups_list.modify_font(pango.FontDescription("")) else: self.groups_list.modify_font(pango.FontDescription(configs["font_groups_name"])) #self.groups_list.set_property("fixed-height-mode",True) xpn-1.2.6/xpn_src/__init__.py0000644000175000017500000000000011141275756014237 0ustar antantxpn-1.2.6/xpn_src/ID_Win.py0000700000175000017500000004276411141275756013631 0ustar antantimport gtk import ConfigParser import os from xpn_src.UserDir import get_wdir from xpn_src.Dialogs import Dialog_OK from xpn_src.add_tag import Tags_Window class ID_Win: def show(self): self.win.show_all() def delete_event(self,widget,event,data=None): return False def destroy(self,obj): self.win.destroy() def open_filesel_dialog(self,obj): def dispatch_response(dialog,id): if id==gtk.RESPONSE_OK: self.update_sign_entry(None) if id==gtk.RESPONSE_CANCEL: self.file_dialog.destroy() def show_hide_hidden(obj): self.file_dialog.set_property("show_hidden",obj.get_active()) self.file_dialog=gtk.FileChooserDialog(_("Select Signature File"),None,gtk.FILE_CHOOSER_ACTION_OPEN,(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) hidden_checkbutton=gtk.CheckButton(_("Show Hidden Files")) self.file_dialog.set_extra_widget(hidden_checkbutton) hidden_checkbutton.connect("clicked",show_hide_hidden) self.file_dialog.set_local_only(True) self.file_dialog.connect("response",dispatch_response) path=self.file_dialog.get_current_folder() self.file_dialog.set_current_folder(path) self.file_dialog.show() def update_sign_entry(self,obj): filename=self.file_dialog.get_filename() self.sign_entry.set_text(filename) self.file_dialog.destroy() def save_custom_headers(self,id_name): bounds=self.custom_headers_buffer.get_bounds() if bounds: start,stop=bounds f=open(os.path.join(get_wdir(),"dats",id_name+"_custom_headers.txt"),"w") headers=self.custom_headers_buffer.get_text(start,stop,True).decode("utf-8").split("\n") for header in headers: if ":" in header: f.write(header.encode("utf-8")+"\n") f.close() def save_configs(self,obj): cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","id.txt")) id_name=self.id_entry.get_text().decode("utf-8") if id_name!="": try: cp.add_section(id_name) except: pass cp.set(id_name,"nick",self.nick_entry.get_text().decode("utf-8")) cp.set(id_name,"email",self.email_entry.get_text().decode("utf-8")) if self.use_mail_from.get_active(): use_mail_from="True" mail_nick=self.mail_nick_entry.get_text().decode("utf-8") mail_email=self.mail_email_entry.get_text().decode("utf-8") else: use_mail_from="False" mail_nick="" mail_email="" cp.set(id_name,"use_mail_from",use_mail_from) cp.set(id_name,"mail_nick",mail_nick) cp.set(id_name,"mail_email",mail_email) cp.set(id_name,"sign",self.sign_entry.get_text().decode("utf-8")) cp.set(id_name,"use_tags",str(bool(self.tags_checkbutton.get_active()))) cp.set(id_name,"wrap",repr(self.wrap_spinbutton.get_value_as_int())) cp.set(id_name,"attribution",self.attribution_entry.get_text().decode("utf-8")) cp.set(id_name,"reply-to",self.reply_to_entry.get_text().decode("utf-8")) cp.set(id_name,"organization",self.organization_entry.get_text().decode("utf-8")) cp.set(id_name,"mail-copies-to",self.mail_copies_to_entry.get_text().decode("utf-8")) if self.generate_mid_checkbutton.get_active(): cp.set(id_name,"gen_mid","True") cp.set(id_name,"fqdn",self.fqdn_entry.get_text().decode("utf-8")) else: cp.set(id_name,"gen_mid","False") cp.set(id_name,"fqdn","") cp.write(file(os.path.join(get_wdir(),"dats","id.txt"),"w")) self.save_custom_headers(id_name) self.win.destroy() self.config_win.refresh_id_list() else: d=Dialog_OK(_("Please set the Identity Name")) def load_configs(self,id_to_load): pass cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","id.txt")) self.id_entry.set_text(id_to_load) self.nick_entry.set_text(cp.get(id_to_load,"nick").encode("utf-8")) self.email_entry.set_text(cp.get(id_to_load,"email").encode("utf-8")) if cp.get(id_to_load,"use_mail_from")=="True": self.use_mail_from.set_active(True) else: self.use_mail_from.set_active(False) self.mail_nick_entry.set_sensitive(False) self.mail_email_entry.set_sensitive(False) self.mail_nick_label.set_sensitive(False) self.mail_email_label.set_sensitive(False) self.mail_nick_entry.set_text(cp.get(id_to_load,"mail_nick").encode("utf-8")) self.mail_email_entry.set_text(cp.get(id_to_load,"mail_email").encode("utf-8")) self.sign_entry.set_text(cp.get(id_to_load,"sign").encode("utf-8")) self.tags_checkbutton.set_active(cp.get(id_to_load,"use_tags")=="True") self.wrap_spinbutton.set_value(int(cp.get(id_to_load,"wrap"))) self.attribution_entry.set_text(cp.get(id_to_load,"attribution").encode("utf-8")) self.reply_to_entry.set_text(cp.get(id_to_load,"reply-to").encode("utf-8")) self.organization_entry.set_text(cp.get(id_to_load,"organization").encode("utf-8")) self.mail_copies_to_entry.set_text(cp.get(id_to_load,"mail-copies-to").encode("utf-8")) if cp.get(id_to_load,"gen_mid")=="True": self.generate_mid_checkbutton.set_active(True) else: self.generate_mid_checkbutton.set_active(False) self.fqdn_entry.set_sensitive(False) self.fqdn_entry.set_text(cp.get(id_to_load,"fqdn").encode("utf-8")) try: f=open(os.path.join(get_wdir(),"dats",id_to_load+"_custom_headers.txt"),"r") except IOError: pass else: headers=f.read().decode("utf-8") self.custom_headers_buffer.set_text(headers.encode("utf-8")) f.close() def change_mail_from_status(self,obj): status=self.use_mail_from.get_active() self.mail_nick_entry.set_sensitive(status) self.mail_email_entry.set_sensitive(status) self.mail_nick_label.set_sensitive(status) self.mail_email_label.set_sensitive(status) def add_tag_line(self,obj): tag_win=Tags_Window() def change_mid_status(self,obj): status=self.generate_mid_checkbutton.get_active() self.fqdn_entry.set_sensitive(status) self.fqdn_label.set_sensitive(status) def load_defaults(self): self.attribution_entry.set_text("%n wrote:") self.change_mid_status(None) self.change_mail_from_status(None) def __init__(self,config_win,id_to_load=None): self.config_win=config_win self.win=gtk.Window(gtk.WINDOW_TOPLEVEL) self.win.connect("delete_event",self.delete_event) self.win.set_title(_("Identity Settings")) self.win.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/conf.xpm")) self.win.set_position(gtk.WIN_POS_CENTER) notebook=gtk.Notebook() id_page_label=gtk.Label(""+_("Personal Informations")+"") id_page_label.set_alignment(0,0.5) id_page_label.set_use_markup(True) id_vbox=gtk.VBox() id_vbox.set_border_width(4) win_vbox=gtk.VBox() win_vbox.set_border_width(4) self.id_entry=gtk.Entry() id_label=gtk.Label(_("Identity")) id_label.set_size_request(200,-1) id_label.set_alignment(0,0.5) id_entry_hbox=gtk.HBox() id_entry_hbox.pack_start(self.id_entry,True,True,10) id_entry_hbox.pack_start(id_label,True,True,10) id_table=gtk.Table(4,2,False) id_table.set_border_width(8) self.nick_entry=gtk.Entry() self.email_entry=gtk.Entry() nick_label=gtk.Label(_("Name or NickName")) nick_label.set_alignment(0,0.5) email_label=gtk.Label(_("E-Mail address")) email_label.set_alignment(0,0.5) id_table.attach(self.nick_entry,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16) id_table.attach(self.email_entry,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16) id_table.attach(nick_label,1,2,0,1,gtk.EXPAND|gtk.FILL) id_table.attach(email_label,1,2,1,2,gtk.EXPAND|gtk.FILL) self.use_mail_from=gtk.CheckButton(_("Use different From field in mail replies")) self.use_mail_from.connect("clicked",self.change_mail_from_status) self.mail_nick_entry=gtk.Entry() self.mail_email_entry=gtk.Entry() self.mail_nick_label=gtk.Label(_("Name or NickName (for Mail replies)")) self.mail_nick_label.set_size_request(200,-1) self.mail_nick_label.set_alignment(0,0.5) self.mail_email_label=gtk.Label(_("E-Mail address (for Mail replies)")) self.mail_email_label.set_alignment(0,0.5) id_table.attach(self.use_mail_from,0,1,3,4,gtk.EXPAND|gtk.FILL,gtk.FILL,16,6) id_table.attach(self.mail_nick_entry,0,1,4,5,gtk.EXPAND|gtk.FILL,gtk.FILL,16) id_table.attach(self.mail_email_entry,0,1,5,6,gtk.EXPAND|gtk.FILL,gtk.FILL,16) id_table.attach(self.mail_nick_label,1,2,4,5,gtk.EXPAND|gtk.FILL) id_table.attach(self.mail_email_label,1,2,5,6,gtk.EXPAND|gtk.FILL) id_vbox.pack_start(id_table,False,True,4) label_posting_profile=gtk.Label(""+_("Body")+"") label_posting_profile.set_use_markup(True) posting_profile_vbox=gtk.VBox() label_posting_profile_2=gtk.Label(""+_("Headers")+"") label_posting_profile_2.set_use_markup(True) posting_profile_vbox_2=gtk.VBox() compose_vbox=gtk.VBox() compose_label=gtk.Label(""+_("Compose")+"") compose_label.set_alignment(0,0.5) compose_label.set_use_markup(True) compose_vbox.set_border_width(4) compose_vbox.pack_start(compose_label,False,False,4) compose_table=gtk.Table(2,2,False) compose_table.set_border_width(4) wrap_label=gtk.Label(_(" Wrap column")) self.wrap_spinbutton=gtk.SpinButton(gtk.Adjustment(value=72,lower=0,upper=79,step_incr=1,page_incr=10)) wrap_fake_hbox=gtk.HBox() wrap_fake_hbox.pack_start(self.wrap_spinbutton,False,False) wrap_fake_hbox.pack_start(wrap_label,False,True) attribution_label=gtk.Label(_("Attribution line")) attribution_label.set_alignment(0,0.5) self.attribution_entry=gtk.Entry() attribution_label.set_size_request(230,-1) attribution_tooltip=gtk.Tooltips() attribution_tooltip.set_tip(self.attribution_entry,_("%s = Subject\n%g = Newsgroups\n%f = From\n%n = Nick\n%e = Email\n%d = Date")) compose_table.attach(wrap_fake_hbox,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.SHRINK,16) compose_table.attach(self.attribution_entry,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.SHRINK,16) compose_table.attach(attribution_label,1,2,1,2,gtk.FILL,gtk.EXPAND|gtk.FILL,4) compose_vbox.pack_start(compose_table,False,False) posting_profile_vbox.pack_start(compose_vbox,False,True) sign_vbox=gtk.VBox() sign_label=gtk.Label(""+_("Signature")+"") sign_label.set_alignment(0,0.5) sign_label.set_use_markup(True) sign_vbox.set_border_width(4) sign_table=gtk.Table(2,2,False) sign_table.set_border_width(4) sign_vbox.pack_start(sign_label,False,False,4) self.sign_entry=gtk.Entry() self.tags_checkbutton=gtk.CheckButton(_("Use random taglines")) sign_button=gtk.Button(_("Change Signature Path")) sign_button.set_size_request(230,-1) sign_button.connect("clicked",self.open_filesel_dialog) tags_button=gtk.Button(_("Add a Tagline")) tags_button.connect("clicked",self.add_tag_line) sign_table.attach(self.sign_entry,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL|gtk.EXPAND,16) sign_table.attach(self.tags_checkbutton,0,1,1,2,gtk.SHRINK|gtk.FILL,gtk.FILL|gtk.EXPAND,16) sign_table.attach(sign_button,1,2,0,1,gtk.FILL,gtk.SHRINK,4) sign_table.attach(tags_button,1,2,1,2,gtk.FILL,gtk.SHRINK,4) sign_vbox.pack_start(sign_table,False,False) posting_profile_vbox.pack_start(sign_vbox,False,True) #optional headers frame opt_headers_vbox=gtk.VBox() opt_headers_label=gtk.Label(""+_("Optional Headers")+"") opt_headers_label.set_alignment(0,0.5) opt_headers_label.set_use_markup(True) opt_headers_vbox.pack_start(opt_headers_label,False,False,4) opt_headers_vbox.set_border_width(4) opt_headers_table=gtk.Table(3,2,False) opt_headers_table.set_border_width(4) self.reply_to_entry=gtk.Entry() self.organization_entry=gtk.Entry() self.mail_copies_to_entry=gtk.Entry() reply_to_label=gtk.Label(_("Reply-To")) reply_to_label.set_alignment(0,0.5) reply_to_label.set_size_request(110,-1) organization_label=gtk.Label(_("Organization")) organization_label.set_alignment(0,0.5) mail_copies_to_label=gtk.Label(_("Mail-Copies-To")) mail_copies_to_label.set_alignment(0,0.5) opt_headers_table.attach(self.reply_to_entry,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16) opt_headers_table.attach(self.organization_entry,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16) opt_headers_table.attach(self.mail_copies_to_entry,0,1,2,3,gtk.EXPAND|gtk.FILL,gtk.FILL,16) opt_headers_table.attach(reply_to_label,1,2,0,1,gtk.EXPAND|gtk.FILL) opt_headers_table.attach(organization_label,1,2,1,2,gtk.EXPAND|gtk.FILL) opt_headers_table.attach(mail_copies_to_label,1,2,2,3,gtk.EXPAND|gtk.FILL) opt_headers_vbox.pack_start(opt_headers_table,False,False) posting_profile_vbox_2.pack_start(opt_headers_vbox,False,True) message_id_vbox=gtk.VBox() message_id_vbox.set_border_width(4) message_id_label=gtk.Label(""+_("Message-ID")+"") message_id_label.set_alignment(0,0.5) message_id_label.set_use_markup(True) message_id_vbox.pack_start(message_id_label,False,False,4) message_id_table=gtk.Table(2,2,False) message_id_table.set_border_width(4) self.generate_mid_checkbutton=gtk.CheckButton(_("Generate Message-ID")) self.generate_mid_checkbutton.connect("clicked",self.change_mid_status) self.fqdn_entry=gtk.Entry() fqdn_tooltip=gtk.Tooltips() fqdn_tooltip.set_tip(self.fqdn_entry,_("You can write here a FQDN (Fully Qualified Domain Name) that will be used to compose the Message-ID.\nOtherwise if you leave this field blank XPN will use your Host Name.")) self.fqdn_label=gtk.Label(_("Fully Qualified Domain Name")) self.fqdn_label.set_alignment(0,0.5) message_id_table.attach(self.generate_mid_checkbutton,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.FILL,16) message_id_table.attach(self.fqdn_entry,0,1,1,2,gtk.EXPAND|gtk.FILL,gtk.FILL,16) message_id_table.attach(self.fqdn_label,1,2,1,2,gtk.EXPAND|gtk.FILL) message_id_vbox.pack_start(message_id_table,False,False) posting_profile_vbox_2.pack_start(message_id_vbox,False,True) custom_headers_vbox=gtk.VBox() custom_headers_vbox.set_border_width(4) custom_headers_label=gtk.Label(""+_("Custom Headers (X-Headers)")+"") custom_headers_label.set_alignment(0,0.5) custom_headers_label.set_use_markup(True) custom_headers_vbox.pack_start(custom_headers_label,False,False,4) custom_headers_scrolledwin=gtk.ScrolledWindow() custom_headers_scrolledwin.set_border_width(4) custom_headers_scrolledwin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) custom_headers_scrolledwin.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.custom_headers_buffer=gtk.TextBuffer() self.custom_headers_textview=gtk.TextView(self.custom_headers_buffer) custom_headers_scrolledwin.add(self.custom_headers_textview) custom_headers_vbox.pack_start(custom_headers_scrolledwin,True,True) posting_profile_vbox_2.pack_start(custom_headers_vbox,True,True) notebook.append_page(id_vbox,id_page_label) notebook.append_page(posting_profile_vbox,label_posting_profile) notebook.append_page(posting_profile_vbox_2,label_posting_profile_2) #buttons hbox buttons_hbox=gtk.HBox() #cancel_button self.cancel_button=gtk.Button(None,gtk.STOCK_CANCEL) self.cancel_button_tooltip=gtk.Tooltips() self.cancel_button_tooltip.set_tip(self.cancel_button,_("Close window. Discard changes")) self.cancel_button.connect("clicked",self.destroy) buttons_hbox.pack_start(self.cancel_button,True,True,0) #ok_button self.ok_button=gtk.Button(None,gtk.STOCK_OK) self.ok_button.connect("clicked",self.save_configs) self.ok_button_tooltip=gtk.Tooltips() self.ok_button_tooltip.set_tip(self.ok_button,_("Close window and save settings")) buttons_hbox.pack_start(self.ok_button,True,True,0) self.ok_button.set_border_width(5) self.cancel_button.set_border_width(5) win_vbox.pack_start(id_entry_hbox,False,False,10) win_vbox.pack_start(notebook,False,False,0) win_vbox.pack_start(buttons_hbox,False,False,0) self.win.add(win_vbox) if id_to_load: self.load_configs(id_to_load) else: self.load_defaults() xpn-1.2.6/xpn_src/Articles_DB.py0000700000175000017500000007271311141275756014630 0ustar antanttry: # >= Python 2.5 import sqlite3 as sqlite except ImportError: # Python 2.4 try: from pysqlite2 import dbapi2 as sqlite except ImportError: print "you need to install PySqlite2 and SQlite" sys.exit() import os,shutil import cPickle from email.Utils import parsedate_tz,mktime_tz import time from xpn_src.UserDir import get_wdir from xpn_src.Article import Article from xpn_src.Config_File import Config_File from xpn_src.Score import Score_Rules class Groups_DB: '''This class wraps the interface to the groups DataBase''' def __init__(self): '''Class constructor''' self._wdir=get_wdir() self._base_path=os.path.join(self._wdir,"groups_info/") self._conf=Config_File() self._configs=self._conf.get_configs() def createList(self,groups_list,server_name,file_name=""): '''Create the groups list DB''' if file_name: try: os.remove(os.path.join(self._base_path,file_name)) except: pass conn=sqlite.connect(os.path.join(self._base_path,file_name)) else: try: os.remove(os.path.join(self._base_path,server_name+".groups.sqlitedb")) except: pass conn=sqlite.connect(os.path.join(self._base_path,server_name+".groups.sqlitedb")) c=conn.cursor() c.execute('''create table groups (group_name TEXT, mode TEXT, server_name TEXT, PRIMARY KEY(group_name,server_name))''') for group in groups_list: c.execute(''' insert into groups values(?,?,?)''',group) conn.commit() conn.close() def getList(self,file_name): '''Get the groups list''' conn=sqlite.connect(os.path.join(self._base_path,file_name)) c=conn.cursor() groups_list=c.execute('''select * from groups''').fetchall() return groups_list conn.close() class Articles_DB: '''This class wraps the interface to the articles DataBase. It has two types of methods, user-level methods and class-level methodos. The user is intended to use only user-level methods. Class-level methods are used internally also to implement user-level methods. ''' def __init__(self,groups=[]): '''Class constructor it performs some initializations, and open all the DB connections Arguments: groups: a list of groups ''' self._wdir=get_wdir() self._base_path=os.path.join(self._wdir,"groups_info/") self._conf=Config_File() self._configs=self._conf.get_configs() self._connections=dict() self._openSubscribed() for group in groups : self._openGroup(group) def _getCursor(self,group): '''Get the cursor for the group''' return self._connections[group]["cursor"] def _getConnection(self,group): '''Get the cursor for the group''' return self._connections[group]["conn"] def _openGroup(self,group): '''Open the connection to the group DB and create a cursor''' conn = sqlite.connect(os.path.join(self._base_path,group,group+".sqlitedb")) c=conn.cursor() c.execute('''pragma synchronous = OFF;''') self._connections[group]={"conn":conn,"cursor":c} def _closeGroup(self,group): '''Close the connection to the group DB''' self._connections[group]["conn"].close() def closeGroups(self,groups=[]): '''Close all the connections, if groups is given, close only listed groups''' if groups: for group in groups: self._closeGroup(group) else: for group in self._connections.iterkeys(): self._closeGroup(group) def _commitGroups(self,groups=[]): '''Commit changes in all the groups''' if groups: for group in groups: self._getConnection(group).commit() else: for group in self._connections.iterkeys(): self._getConnection(group).commit() def addGroups(self,groups): '''Open the connections for the groups DB and create cursors''' for group in groups: self._openGroup(group) def _openSubscribedConn(self): conn = sqlite.connect(os.path.join(self._base_path,"subscribed.sqlitedb")) c=conn.cursor() self._subscribedConnection={"conn":conn,"cursor":c} def _getSubscribedConnection(self): return self._subscribedConnection["conn"] def _getSubscribedCursor(self): return self._subscribedConnection["cursor"] def _openSubscribed(self): '''Open the connection to the subscribed DB and create a cursor''' try: #Test if the file already exists f=open(os.path.join(self._base_path,"subscribed.sqlitedb"),"rb") except IOError: self._openSubscribedConn() self._createSubscribed() else: self._openSubscribedConn() def _createSubscribed(self): '''Create the table for a subscribed groups''' c=self._getSubscribedCursor() conn=self._getSubscribedConnection() c.execute('''create table subscribed (group_name TEXT, last TEXT, server_name TEXT, id_name TEXT, PRIMARY KEY(group_name))''') conn.commit() def addSubscribed(self,group,last,server_name,id_name): '''Add a subscribed group''' c=self._getSubscribedCursor() conn=self._getSubscribedConnection() c.execute('''insert into subscribed values (?,?,?,?)''',(group,last,server_name,id_name)) conn.commit() def removeSubscribed(self,group): '''Remove a subscribed group''' c=self._getSubscribedCursor() conn=self._getSubscribedConnection() removed=bool(len(c.execute('''select * from subscribed where group_name=?''',(group,)).fetchall())) c.execute('''delete from subscribed where group_name=?''',(group,)) conn.commit() return removed def getSubscribed(self): '''Get subscribed list''' c=self._getSubscribedCursor() conn=self._getSubscribedConnection() c.execute('''select * from subscribed''') subscribed=c.fetchall() subscribed= [list(group) for group in subscribed] return subscribed def updateSubscribed(self,subscribed): '''Update Subscribed table''' c=self._getSubscribedCursor() conn=self._getSubscribedConnection() for group in subscribed: c.execute('''update subscribed set last=?, server_name =?, id_name =? where group_name=? ''',(group[1],group[2],group[3],group[0])) conn.commit() def closeSubscribed(self): '''Close subscribed connection''' c=self._getSubscribedCursor() c.execute("""vacuum""") self._subscribedConnection["conn"].close() def getWatched(self,group): '''Get the watched mids in the group''' c=self._getCursor(group) result=c.execute("select msgid from articles where watched='1'") result=[item[0] for item in result] return result def getIgnored(self,group): '''Get the watched mids in the group''' c=self._getCursor(group) result=c.execute("select msgid from articles where ignored='1'") result=[item[0] for item in result] return result def inIgnored(self,mid,group,cursor=None): '''True if mid is ignored''' c=self._getCursor(group) result=len(c.execute("select * from articles where ignored='1' and msgid=?",(mid,)).fetchall())!=0 return result def inWatched(self,mid,group,cursor=None): '''True if mid is watched''' c=self._getCursor(group) result=len(c.execute("select * from articles where watched='1' and msgid=?",(mid,)).fetchall())!=0 return result def getArticlesNumbers(self,group): '''Return the number of the articles and the unreads number''' c=self._getCursor(group) total=len(c.execute("select msgid from articles").fetchall()) unread_number=len(c.execute("select msgid from articles where read='0'").fetchall()) return total,unread_number def retrieveBody(self,article_to_read,group,server_name,connectionsPool,doCommit=True): '''Retrieve the body of the article Arguments: article_to_read: the xpn_article group : article group server_name : the name of the server to use connectionsPool: the dict of the NNTP connections ''' body=article_to_read.get_body() bodyRetrieved=True message="" raw_body="" if not body: c=self._getCursor(group) c.execute('''select raw_body from bodies where msgid=? and number=?''',(article_to_read.msgid,article_to_read.number)) try: raw_body= c.fetchall()[0][0] except: raw_body="" if not raw_body: message,headerList,body,bodyRetrieved=connectionsPool[server_name].getBody(article_to_read.number,article_to_read.msgid,group) if headerList: article_to_read.parse_header_list(headerList) if bodyRetrieved: raw_body='\n'.join(headerList+['']+body) article_to_read.set_body(raw_body) body=article_to_read.get_body() article_to_read.marked_for_download=False self.updateArticle(group,article_to_read,doCommit) self._insertBody(group,article_to_read,doCommit) else: raw_body_list=raw_body.split("\n") ind=raw_body_list.index("") header_list=raw_body_list[:ind] article_to_read.parse_header_list(header_list,True) article_to_read.set_body(raw_body,True) body=article_to_read.get_body() article_to_read.marked_for_download=False self.updateArticle(group,article_to_read,doCommit) return body,bodyRetrieved,message def getBodyFromDB(self,group,article): '''Get the body of the article from the DB if it is available''' c=self._getCursor(group) c.execute("select raw_body from bodies where msgid=? and number=?",(article.msgid,article.number)) body=None try: raw_body= c.fetchall()[0][0] except: raw_body="" if raw_body: raw_body_list=raw_body.split("\n") ind=raw_body_list.index("") header_list=raw_body_list[:ind] article.parse_header_list(header_list,True) article.set_body(raw_body,True) body=article.get_body() return body def deleteArticle(self,group,xpn_article,doCommit=True): '''Delete the article from the DB''' c=self._getCursor(group) c.execute("""delete from articles where msgid=?""",(xpn_article.msgid,)) if doCommit: conn=self._getConnection(group) conn.commit() def updateArticle(self,group,xpn_article,doCommit=True): '''Update the article in the DB. Only fields that can change are updated ''' c=self._getCursor(group) c.execute("""update articles set has_body =?, score =?, marked_for_download =?, kept =?, read =?, watched =?, ignored =?, fg_color =?, bg_color =? where msgid=?""", (xpn_article.has_body, xpn_article.score, xpn_article.marked_for_download, xpn_article.keep, xpn_article.is_read, xpn_article.watch, xpn_article.ignore, xpn_article.fg_color, xpn_article.bg_color, xpn_article.msgid)) if doCommit: conn=self._getConnection(group) conn.commit() def insertArticle(self,group,xpn_article,doCommit=True): '''Insert the article in the DB.''' c=self._getCursor(group) try: c.execute("""insert into articles values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""", (xpn_article.msgid, xpn_article.number, xpn_article.subj, xpn_article.from_name, xpn_article.date, xpn_article.secs, xpn_article.ref, xpn_article.bytes, xpn_article.lines, xpn_article.xref, xpn_article.original_group, xpn_article.has_body, xpn_article.score, xpn_article.marked_for_download, xpn_article.keep, xpn_article.is_read, xpn_article.watch, xpn_article.ignore, xpn_article.fg_color, xpn_article.bg_color)) except sqlite.IntegrityError: print "Found Duplicated Article ... skipping" if doCommit: conn=self._getConnection(group) conn.commit() def _insertBody(self,group,xpn_article,doCommit=True): '''Insert the body in the bodies DB''' c=self._getCursor(group) raw_body=xpn_article.get_raw(True) if raw_body: c.execute('''insert into bodies values (?,?,?)''',(xpn_article.msgid,xpn_article.number,raw_body)) if doCommit: conn=self._getConnection(group) conn.commit() def markGroupForDownload(self,group): '''Mark the whole group for dowload''' c=self._getCursor(group) c.execute("""update articles set marked_for_download='1' where has_body='0'""") conn=self._getConnection(group) conn.commit() def markGroupRead(self,group,read): '''Mark the whole group read or unread''' c=self._getCursor(group) c.execute('''update articles set read=?''',(read,)) conn=self._getConnection(group) conn.commit() def keepGroup(self,group): '''Keep or unKeep the whole group The first query is used to retrieve the keep status of the first article it will be used as reference for all the other articles. That's because I don't know if I have to keep or unkeep ''' c=self._getCursor(group) keep=not bool(int(c.execute("""select kept from articles limit 1""").fetchall()[0][0])) c.execute("""update articles set kept=?""",(keep,)) conn=self._getConnection(group) conn.commit() def _buildQuery(self,show_bools,search_type=None,text=None): show_read_articles,show_unread_articles,show_kept_articles,show_unkept_articles,show_watched_articles,show_ignored_articles,show_unwatchedignored_articles,show_score_neg_articles,show_score_zero_articles,show_score_pos_articles,show_threads,show_all_read_threads=show_bools pieces=[] nothing_to_show=False if search_type=="bodies.raw_body" and text: pieces.append(" ") #fake piece I need to prevent adding another where base_query="""select articles.msgid, articles.number, articles.subject, articles.from_name, articles.art_date, articles.secs, articles.ref, articles.bytes, articles.lines, articles.xref, articles.group_name, articles.has_body, articles.score, articles.marked_for_download, articles.kept, articles.read, articles.watched, articles.ignored, articles.fg_color, articles.bg_color from articles,bodies where articles.msgid=bodies.msgid and """ else: base_query="select * from articles " def add_piece(piece,addOR=False): if not pieces: pieces.append("where") if len(pieces)>1: if addOR: pieces.append("or") else: pieces.append("and") pieces.append(piece) if show_read_articles and not show_unread_articles : add_piece("read='1'") elif not show_read_articles and show_unread_articles : add_piece("read='0'") elif not show_read_articles and not show_unread_articles: nothing_to_show=True if show_kept_articles and not show_unkept_articles : add_piece("kept='1'") elif not show_kept_articles and show_unkept_articles : add_piece("kept='0'") elif not show_kept_articles and not show_unkept_articles: nothing_to_show=True if not show_unwatchedignored_articles and not show_watched_articles and not show_ignored_articles : nothing_to_show=True elif not show_unwatchedignored_articles and not show_watched_articles and show_ignored_articles : add_piece("ignored='1'") elif not show_unwatchedignored_articles and show_watched_articles and not show_ignored_articles : add_piece("watched='1'") elif not show_unwatchedignored_articles and show_watched_articles and show_ignored_articles : add_piece("(watched='1' OR ignored='1')") elif show_unwatchedignored_articles and not show_watched_articles and not show_ignored_articles : add_piece("watched='0' and ignored='0'") elif show_unwatchedignored_articles and not show_watched_articles and show_ignored_articles : add_piece("watched='0'") elif show_unwatchedignored_articles and show_watched_articles and not show_ignored_articles : add_piece("ignored='0'") if show_score_neg_articles and not show_score_pos_articles and not show_score_zero_articles : add_piece("score<0") elif show_score_neg_articles and show_score_pos_articles and not show_score_zero_articles : add_piece("score!=0") elif show_score_neg_articles and not show_score_pos_articles and show_score_zero_articles : add_piece("score<=0") elif not show_score_neg_articles and not show_score_pos_articles and not show_score_zero_articles : nothing_to_show=True elif not show_score_neg_articles and not show_score_pos_articles and show_score_zero_articles: add_piece("score=0") elif not show_score_neg_articles and show_score_pos_articles and not show_score_zero_articles: add_piece("score>0") elif not show_score_neg_articles and show_score_pos_articles and show_score_zero_articles: add_piece("score>=0") if search_type and text: add_piece(search_type+""" like '%"""+text+"""%'""") if nothing_to_show: query="select * from articles where 1=0" else: query=base_query+" ".join(pieces) return query def getArticles(self,group,show_bools=[],sort_by_num=False,search_type=None,text=None): '''Return all the articles in the group in form of xpn_articles It is a generator. ''' c=self._getCursor(group) if show_bools: query=self._buildQuery(show_bools,search_type,text) else: query="select * from articles" if sort_by_num: query=query+" order by number" headers=c.execute(query).fetchall() for article_header in headers: msgid,number,subject,from_name,date,secs,ref,bytes,lines,xref,group,has_body,score,marked_for_download,kept,read,watched,ignored,fg_color,bg_color=article_header xpn_article=Article(number,msgid,from_name,ref,subject,date,self._configs["fallback_charset"],group,xref,bytes,lines,True) xpn_article.score=int(score) xpn_article.marked_for_download=bool(int(marked_for_download)) xpn_article.keep=bool(int(kept)) xpn_article.is_read=bool(int(read)) xpn_article.watch=bool(int(watched)) xpn_article.ignore=bool(int(ignored)) xpn_article.fg_color=fg_color xpn_article.bg_color=bg_color xpn_article.has_body=bool(int(has_body)) yield xpn_article def createGroup(self,group): '''Create the table for a new group''' try: self.closeGroups((group,)) except:pass try: shutil.rmtree(os.path.join(self._base_path,group)) except: pass os.makedirs(os.path.join(self._base_path,group)) self._openGroup(group) c=self._getCursor(group) conn=self._getConnection(group) c.execute('''create table articles (msgid TEXT, number TEXT, subject TEXT, from_name TEXT, art_date DATE, secs INTEGER, ref TEXT, bytes TEXT, lines TEXT, xref TEXT, group_name TEXT, has_body TEXT, score INTEGER, marked_for_download TEXT, kept TEXT, read TEXT, watched TEXT, ignored TEXT, fg_color TEXT, bg_color TEXT, PRIMARY KEY (msgid,number));''') c.execute('''create trigger delete_article before delete on articles begin delete from bodies where msgid=OLD.msgid and number=OLD.number; end;''') c.execute('''create index watched_index on articles(watched);''') c.execute('''create index ignored_index on articles(ignored);''') c.execute('''create index read_index on articles(read);''') c.execute('''create index kept_index on articles(kept);''') c.execute('''create index marked_index on articles(marked_for_download);''') c.execute('''create table bodies (msgid TEXT, number TEXT, raw_body TEXT, PRIMARY KEY (msgid,number));''') conn.commit() def _isInReadList(self,number,L): if L!="": intervals=L.split(",") for interval in intervals: if "-" in interval: #this is a range start,stop=int(interval.split("-")[0]),int(interval.split("-")[1]) if (number <= stop) and (number >=start): return True else: #this is a single number if number == int(interval): return True return False def _applyRules(self,xpn_article,group,score_rules,server_name,connectionsPool,update=False,read_list=""): '''Apply rules to the article and add it to the DB Arguments: article_to_read: the xpn_article group : article group score_rules : score_rules object server_name : the name of the server to use connectionsPool: the dict of the NNTP connections update : true if the article is already in the DB read_list : list of read articles, it is used when resuming a newsrc file ''' c=self._getCursor(group) try: index=xpn_article.ref.rindex("<") except ValueError: last_ref="" else: last_ref=xpn_article.ref[index:] #applying score rules score=score_rules.apply_score_rules(xpn_article,group) xpn_article.set_score(score) #applying score actions xpn_article,actions=score_rules.apply_action_rules(xpn_article,group) #save only the last mid of references: #xpn_article.ref=last_ref #with this operation Reapplying rules doesn't work correctly #I loose the othere mids in references if not "kill" in actions: to_ignore = self.inIgnored(last_ref,group,c) to_watch = self.inWatched(last_ref,group,c) to_mark_read = self._isInReadList(int(xpn_article.number),read_list) raw_body="None" if ((self._configs["download_bodies"]=="True" and not "markread" in actions) or ("retrieve" in actions) or (to_watch)) and not (to_ignore): body,bodyRetrieved,message=self.retrieveBody(xpn_article,group,server_name,connectionsPool,False) if to_ignore: xpn_article.is_read=True xpn_article.ignore=True xpn_article.watch=False if to_watch: xpn_article.watch=True xpn_article.ignore=False if to_mark_read: xpn_article.is_read=True if update: self.updateArticle(group,xpn_article,False) else: self.insertArticle(group,xpn_article,False) #self._getConnection(group).commit() else: if update: self.deleteArticle(group,xpn_article,True) def addHeaders(self,group,total_headers,server_name,connectionsPool,read_list=""): '''Add articles to the DB Arguments: group : group name total_headers : the list of headers retrieved with XOVER server_name : the name of the server to use connectionsPool: the dict of the NNTP connections ''' #t1=time.time() c=self._getCursor(group) #print "pragma: ",c.execute('''pragma synchronous;''').fetchall() score_rules=Score_Rules() for headers in total_headers: number,subject,from_name,date,msgid,references,bytes,lines,xref=headers xpn_article=Article(number,msgid,from_name,references,subject,date,self._configs["fallback_charset"],group,xref,bytes,lines) self._applyRules(xpn_article,group,score_rules,server_name,connectionsPool,False,read_list) self._getConnection(group).commit() #t2=time.time() #print "Tempo per aggiungere Header: ",t2-t1 def reapply_rules(self,group,server_name,connectionsPool): '''Reapply scoring and actions rules Arguments: group : group name total_headers : the list of headers retrieved with XOVER server_name : the name of the server to use connectionsPool: the dict of the NNTP connections ''' sorted=[] for xpn_article in self.getArticles(group): sorted.append((xpn_article.secs,xpn_article)) sorted.sort() score_rules=Score_Rules() for secs,xpn_article in sorted: #reset the article #xpn_article.reset_article_score_actions() self._applyRules(xpn_article,group,score_rules,server_name,connectionsPool,True) self._getConnection(group).commit() def purgeGroups(self): purge_read_limit=int(self._configs["purge_read"]) purge_read_limit_secs=purge_read_limit*24*60*60 purge_unread_limit=int(self._configs["purge_unread"]) purge_unread_limit_secs=purge_unread_limit*24*60*60 time_now=mktime_tz(parsedate_tz(time.ctime())) subscribed=self.getSubscribed() for group in subscribed: c=self._getCursor(group[0]) conn=self._getConnection(group[0]) if purge_read_limit_secs >0: c.execute("""delete from articles where secs < ? and read='1' and kept='0'""",(time_now-purge_read_limit_secs,)) conn.commit() if purge_unread_limit_secs >0: c.execute("""delete from articles where secs < ? and read='0' and kept='0'""",(time_now-purge_unread_limit_secs,)) conn.commit() c.execute("""vacuum""") conn.commit() yield group[0] xpn-1.2.6/README0000644000175000017500000000163111141275756011345 0ustar antant******************************************************************************* * X Python Newsreader * * README * ******************************************************************************* What is it? XPN is a simple newsreader written in python using the Gtk+ toolkit for the GUI. XPN has a good support for MIME standards (but it has a partial support for multipart articles), so please use it carefully and on text-only newsgroups. However XPN is fully unicode compliant. Requirements: - Python (2.5 or better) - PyGtk (2.8 or better) - GTK+ (2.8 or better) Read "xpn.html" for more informations. XPN - X Python Newsreader Copyright (C) 2003 Antonio Caputo Released under the terms of the GNU General Public License. See the file COPYING for details. xpn-1.2.6/xpn.html0000644000175000017500000001370111141275756012161 0ustar antant XPN Doc

XPN - X Python Newsreader

What is it?

XPN is a newsreader written in python using the Gtk+ toolkit for the GUI. It is a multiplatform newsreader, it should work wherever GTK+ and Python work.

XPN has a good support for MIME standards, but hasn't any support for binary articles, so please use it on text-only newsgroups. XPN is fully Unicode compliant.

Installing XPN

Simply extract the tarball. A directory named "xpn-x.y.z" will be created. In this directory you will find the executable file "xpn.py" that launchs the newsreader.
Type
./xpn.py --help
to get informations on command-line options.

Using XPN

Launch "xpn.py". The first time you have to configure the program. Follow the instructions and fill all the fields.

Now you can download the newsgroups list from the server (this operation is very slow, so please be patient). Open the newsgroups window with the first button on the toolbar (or the voice in the file menu).

Download the list and subscribe the newsgroups. In the main window, when you click on the newsgroup name, XPN shows the unread articles in a thread view. Clicking on the article you will read it.
You can also use the keyboad. With key "n" you will read the next article ("b" for the previous and "u" for the parent) and with "g" the next group. The spacebar will scroll the article until reaching the bottom, and then will move to the next article.

Pressing "p" you can post a new article to the selected group, while pressing "f" you can post a followup to the article selected. When you compose an article XPN automatically chooses the best encoding.

Scoring System

XPN has a scoring/actions system. It is very simple, every article has a "score", initially it is equal to 0.
The score is calculated when you download new headers, with the rules you define. The syntax is very similar to the Hamster's one, however it is simplified.

Rules are saved in scores.txt (it's better if you don't edit it with an external editor, use the internal rule editor), it is divided in ScoreBlocks. Every ScoreBlock starts with a Scope Definition, it defines the groups in wich rules are applied.
[*] Means: apply the rule in the whole groups
[group1 group2 group3] Means: apply the rule in the listed groups

With a rule you test an header (like From, Subject ...) searching for strings and things like that, if the match is successful the score is modified.
Every rule is composed by three parts:

  1. The score modifier. You can increase (+value), decrease (-value) or assign (=+ or =-). the actual score of the article. The processing of the article is stopped if its score is assigned with a successful rule.
  2. The header used. You can chose from :Subject, From, Date, Message-ID, References, Bytes, Lines, Xref, Xpost, Age (in days)
  3. The match definition. The way XPN decides if the rule is successful, it can search for a substring (defined like that "Substring" or like that c"Substring" if you need case sensivity), use a regular expression (defined with {regex} or with c{regex}), or confront numeric values (%>value, %<value, %=value, %[value_inf,value_sup])
You can also invert a match definition prepending a "~". So the rule will be successful only if it doesn't match. The "~" has to prepend the whole match rule, also the "c" modifier. Examples:
    # use this for comments
    [*]
    +100 From c"Nemesis"     #increase the score for the author 'Nemesis'
    =+1000 Subject "xpn"     #assign the score for the articles with the 'xpn' word in the subject
    =-9999 Subject ~c{[a-z]} #assign the score for the articles with a subject that doesn't contain small letters
    
    [it.comp.software.newsreader it.comp.lang.python]
    -500 Age %>10            #decrease the score for articles ten days old
    =-100 Xpost %>2          #assign the score for article posted on more than 2 groups

Actions Rules are very similar to Scoring Rules. When an action rule is successful XPN apply the action specified on the article. You can choose one of these actions :!kill, !markread, !markunread, !mark, !unmark, !retrieve, !keep,!unkeep, !watch, !ignore, !unsetwatchignore, !setcolor(foreground;background). The headers are the same of the Scoring Rules plus the field Score. Actions Rules are always applied after Scoring Rules (even if they are placed before scoring rules in the scores.txt file), so you can modify the score of an article and then apply an action according the score value.

Examples:

    [*]
    !watch Score %>5000                      #Watch articles with Score greater than 5000
    !markread Score %[-1000,4000]            #Mark as read articles with Score in range
    !kill From "Pinco@pallino.com"           #Kill articles from 'Pinco@pallino.com'
    !setcolor(black;yellow) Lines ~%[10,20]  #Set the background color to yellow for articles whith more than
                                             #20 lines and less than 10 lines 
    

Requirements

  • Python (2.5 or better)
  • PyGtk (2.8 or better)
  • GTK+ (2.8 or better)
xpn-1.2.6/tags.txt0000644000175000017500000000004111141275756012156 0ustar antantXPN :: http://xpn.altervista.org xpn-1.2.6/AUTHORS0000644000175000017500000000072111141275756011534 0ustar antantDevelopers: Antonio Caputo Translators: (French) Guillame Bedot Patrick Lamaiziere (Italian) Antonio Caputo (German) Rene Fischer Marek Macioschek Other Contributors: Valentino Volonghi Emmanuele Bassi Facundo Batista xpn-1.2.6/xpn.py0000700000175000017500000041667511141275756011657 0ustar antant#!/usr/bin/env python import os,shutil #os.environ['PATH'] += ';'+os.path.join('gtk/lib')+';'+os.path.join('gtk/bin') #OLD #os.environ['PATH'] = os.path.join('gtk/lib')+';'+os.path.join('gtk/bin')+';'+os.path.join('gtk\\lib')+';'+os.path.join('gtk\\bin')+';'+os.environ['PATH'] #NEW #py2exe 0.6.8 problem import email import email.mime.text import email.iterators import email.generator import email.utils #py2exe 0.6.8 problem import sys import gtk import gobject import pango import cPickle import time import re import platform import glob import gettext import locale import webbrowser import ConfigParser from urllib import quote as url_quote from optparse import OptionParser from email.Utils import parsedate_tz, mktime_tz from xpn_src.Groups_Pane import Groups_Pane from xpn_src.Threads_Pane import Threads_Pane from xpn_src.Article_Pane import Article_Pane from xpn_src.Groups_Win import Groups_Win from xpn_src.Config_File import Config_File from xpn_src.Config_Win import Config_Win from xpn_src.Edit_Win import Edit_Win from xpn_src.Edit_Mail_Win import Edit_Mail_Win from xpn_src.Dialogs import About_Dialog, Dialog_YES_NO, Error_Dialog, MidDialog, Dialog_OK, Dialog_Import_Newsrc from xpn_src.Article import Article, Article_To_Send from xpn_src.Show_Logs import Logs_Window from xpn_src.Newsrc import ImportNewsrc, ExportNewsrc from xpn_src.Find_Win import Find_Win, Search_Win, GlobalSearch from xpn_src.Score import Score_Rules, Score_Win from xpn_src.Charset_List import load_ordered_list from xpn_src.Connections_Handler import Connection, SMTPConnection, SSLConnection from xpn_src.UserDir import UserDir, get_wdir from xpn_src.Outbox_Manager import Outbox_Manager from xpn_src.KeyBindings import KeyBindings, load_shortcuts from xpn_src.Server_Win import NNTPServer_Win from xpn_src.Groups_Vs_ID import Groups_Vs_ID from xpn_src.Articles_DB import Articles_DB, Groups_DB from xpn_src.Custom_Search_Entry import Custom_Search_Entry try: set() except: from sets import Set as set try: user_system=" ; "+platform.system() except: user_system="" NUMBER="1.2.6" VERSION="XPN/%s (Street Spirit%s)" % (NUMBER,user_system) gettext.NullTranslations() gettext.install("xpn") ui_string=""" """ def escape(data): """Escape &, <, and > in a string of data. """ # must do ampersand first data = data.replace("&", "&") data = data.replace(">", ">") data = data.replace("<", "<") return data class MainWin: def open_logs_win(self,object): self.logs_win=Logs_Window(self.window) def open_groups_win(self,object): self.win2=Groups_Win(self) self.win2.show() def open_configure_win(self,object): self.save_sizes() self.win3=Config_Win(self.conf,self) self.win3.show() def open_rules_win(self,object): self.score_win=Score_Win(self.score_rules,self) self.score_win.show() def open_groups_vs_id(self,object): self.groups_vs_id=Groups_Vs_ID(self.subscribed_groups,self) self.groups_vs_id.show() def supersede_cancel_message(self,object,mode): group_selected="" id_name="" model,path,iter_selected=self.groups_pane.get_first_selected_row() if iter_selected!=None: group_selected=model.get_value(iter_selected,0) id_name=self.get_id_for_group(group_selected) model,iter_selected=self.threads_pane.threads_tree.get_selection().get_selected() subj="" cp_id=ConfigParser.ConfigParser() cp_id.read(os.path.join(get_wdir(),"dats","id.txt")) if iter_selected!=None: #subj=model.get_value(iter_selected,1).decode("utf-8") article=self.threads_pane.get_article(model,iter_selected) subj=article.subj try: article.ngroups except AttributeError: self.statusbar.push(1,_("First you have to read the article")) else: nick=cp_id.get(id_name,"nick") email=cp_id.get(id_name,"email") user=nick+" <"+email+">" if article.user_agent.startswith("XPN") and user==article.from_name: if mode=="Supersede": self.win4=Edit_Win(self.configs,article.ngroups,article,None,self.subscribed_groups,"Supersede",server_name=self.current_server,id_name=id_name) #self.win4.show() else: message=Dialog_YES_NO(_("Do you want to CANCEL this article?\n\nSubject: %s ""\nMessage-ID: %s") % (article.subj.encode("utf-8"),escape(article.msgid.encode("utf-8")))) if message.resp: canc_mess=Article_To_Send(article.ngroups,user,"cmsg cancel "+article.msgid,"",VERSION,"us-ascii",load_ordered_list(),["Cancel Message for "+article.msgid],["Control"],["cancel "+article.msgid],cp_id.get(id_name,"gen_mid"),cp_id.get(id_name,"fqdn")) cancel_message=canc_mess.get_article() message,articlePosted=self.connectionsPool[self.current_server].sendArticle(cancel_message) if articlePosted: self.statusbar.push(1,_("Cancel Article Sent: ")+message) else: self.statusbar.push(1,message) else: self.statusbar.push(1,_("You can Cancel/Supersede only your articles")) def open_outbox_manager(self,obj): self.win_outbox=Outbox_Manager(self,VERSION) self.win_outbox.show() def open_edit_win(self,object,is_followup=False): group="" id_name="" model,path,iter_selected=self.groups_pane.get_first_selected_row() if iter_selected!=None: group=model.get_value(iter_selected,0) id_name=self.get_id_for_group(group) if is_followup: #this is a followup model,iter_selected=self.threads_pane.threads_tree.get_selection().get_selected() subj="" if iter_selected!=None: #subj=model.get_value(iter_selected,1).decode("utf-8") article=self.threads_pane.get_article(model,iter_selected) subj=article.subj group=article.original_group try: article.ngroups except AttributeError: self.statusbar.push(1,_("First you have to read the article")) else: self.threads_pane.update_article_icon("fup") bounds=self.article_pane.buffer.get_selection_bounds() selected_text=None if bounds: start=bounds[0] stop=bounds[1] selected_text=self.article_pane.buffer.get_text(start,stop,True).decode("utf-8").split("\n") newsgroups=group if group!=article.ngroups: #this is a crosspost crosspost=True newsgroups=article.ngroups else: crosspost=False if article.fup_to!="": newsgroups=article.fup_to followup_to=True else: followup_to=False if crosspost and not followup_to: message=Dialog_YES_NO(_("This is a crosspost! \n Do you want to send the article only on the original newsgroup (%s) ?") % (group,)) if message.resp: newsgroups=group if followup_to: if article.fup_to!="poster": message=Dialog_YES_NO(_("Original Poster set \"Followup_to\" on %s,\n\nDo you want to send your article on the original newsgroup (%s) ?") % (article.fup_to,group)) if message.resp: newsgroups=group else: message=Dialog_YES_NO(_("Original Poster set \"Followup_to: poster\",\n\nDo you want to reply by mail ?")) if message.resp: self.open_edit_mail_win(None) return None else: newsgroups=group self.win4=Edit_Win(self.configs,newsgroups,article,selected_text,self.subscribed_groups,server_name=self.current_server,id_name=id_name) #self.win4.show() else: #this is a new post self.win4=Edit_Win(self.configs,group,None,None,self.subscribed_groups,server_name=self.current_server,id_name=id_name) #self.win4.show() def open_edit_mail_win(self,object): to_name="" id_name="" model,path,iter_selected=self.groups_pane.get_first_selected_row() if iter_selected!=None: group=model.get_value(iter_selected,0) id_name=self.get_id_for_group(group) model,iter_selected=self.threads_pane.threads_tree.get_selection().get_selected() subj="" if iter_selected!=None: #subj=model.get_value(iter_selected,1).decode("utf-8") article=self.threads_pane.get_article(model,iter_selected) subj=article.subj try: article.reply_to except AttributeError: self.statusbar.push(1,_("First you have to read the article")) else: self.threads_pane.update_article_icon("fup") if article.reply_to!="": to_name=article.reply_to else: to_name=article.from_name bounds=self.article_pane.buffer.get_selection_bounds() selected_text=None if bounds: start=bounds[0] stop=bounds[1] selected_text=self.article_pane.buffer.get_text(start,stop,True).decode("utf-8").split("\n") self.win4=Edit_Mail_Win(self.configs,to_name,article,selected_text,id_name=id_name) self.win4.show() def open_about_dialog(self,object): self.about_dialog=About_Dialog(NUMBER) self.about_dialog.show() def delete_event(self,widget,event,data=None): self.mainwin_width,self.mainwin_height=self.window.get_size() self.mainwin_pos_x,self.mainwin_pos_y=self.window.get_position() return False def save_sizes(self): try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"rb") except IOError: sizes={} else: sizes=cPickle.load(f) sizes["vpaned_pos"]=self.vpaned.get_position() sizes["hpaned_pos"]=self.hpaned.get_position() sizes["threads_col_status"]=self.threads_pane.column1.get_width() sizes["threads_col_subject"]=self.threads_pane.column2.get_width() sizes["threads_col_from"]=self.threads_pane.column3.get_width() sizes["threads_col_date"]=self.threads_pane.column4.get_width() sizes["threads_col_score"]=self.threads_pane.column5.get_width() sizes["groups_col1"]=self.groups_pane.column1.get_width() if not self.mainwin_width: sizes["mainwin_width"],sizes["mainwin_height"]=self.window.get_size() else: sizes["mainwin_width"]=self.mainwin_width sizes["mainwin_height"]=self.mainwin_height if not self.mainwin_pos_x: sizes["mainwin_pos_x"],sizes["mainwin_pos_y"]=self.window.get_position() else: sizes["mainwin_pos_x"]=self.mainwin_pos_x sizes["mainwin_pos_x"]=self.mainwin_pos_x try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"wb") except IOError: pass else: cPickle.dump(sizes,f,1) f.close() def save_checkmenu_options(self): self.configs["raw"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_articles_opts/raw").get_active())) self.configs["fixed"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_articles_opts/fixed").get_active())) self.configs["show_quote"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_articles_opts/show_quote").get_active())) self.configs["show_sign"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_articles_opts/show_sign").get_active())) self.configs["show_spoiler"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_articles_opts/spoiler").get_active())) self.configs["show_threads"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads").get_active())) self.configs["show_all_read_threads"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_all_read_threads").get_active())) self.configs["show_threads_without_watched"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads_without_watched").get_active())) self.configs["show_read_articles"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_read_articles").get_active())) self.configs["show_unread_articles"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unread_articles").get_active())) self.configs["show_kept_articles"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_kept_articles").get_active())) self.configs["show_unkept_articles"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unkept_articles").get_active())) self.configs["show_watched_articles"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_watched_articles").get_active())) self.configs["show_ignored_articles"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_ignored_articles").get_active())) self.configs["show_unwatchedignored_articles"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unwatchedignored_articles").get_active())) self.configs["show_score_neg_articles"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_neg_articles").get_active())) self.configs["show_score_zero_articles"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_zero_articles").get_active())) self.configs["show_score_pos_articles"]=str(bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_pos_articles").get_active())) self.conf.write_configs() def update_checkmenu_options(self): if self.configs["raw"]=="True": self.ui.get_widget("/MainMenuBar/View/view_articles_opts/raw").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_articles_opts/raw").set_active(False) if self.configs["fixed"]=="True": self.ui.get_widget("/MainMenuBar/View/view_articles_opts/fixed").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_articles_opts/fixed").set_active(False) if self.configs["show_quote"]=="True": self.ui.get_widget("/MainMenuBar/View/view_articles_opts/show_quote").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_articles_opts/show_quote").set_active(False) if self.configs["show_sign"]=="True": self.ui.get_widget("/MainMenuBar/View/view_articles_opts/show_sign").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_articles_opts/show_sign").set_active(False) if self.configs["show_spoiler"]=="True": self.ui.get_widget("/MainMenuBar/View/view_articles_opts/spoiler").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_articles_opts/spoiler").set_active(False) if self.configs["show_threads"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads").set_active(False) if self.configs["show_all_read_threads"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_all_read_threads").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_all_read_threads").set_active(False) if self.configs["show_threads_without_watched"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads_without_watched").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads_without_watched").set_active(False) if self.configs["show_read_articles"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_read_articles").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_read_articles").set_active(False) if self.configs["show_unread_articles"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unread_articles").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unread_articles").set_active(False) if self.configs["show_kept_articles"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_kept_articles").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_kept_articles").set_active(False) if self.configs["show_unkept_articles"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unkept_articles").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unkept_articles").set_active(False) if self.configs["show_watched_articles"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_watched_articles").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_watched_articles").set_active(False) if self.configs["show_ignored_articles"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_ignored_articles").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_ignored_articles").set_active(False) if self.configs["show_unwatchedignored_articles"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unwatchedignored_articles").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unwatchedignored_articles").set_active(False) if self.configs["show_score_neg_articles"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_neg_articles").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_neg_articles").set_active(False) if self.configs["show_score_zero_articles"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_zero_articles").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_zero_articles").set_active(False) if self.configs["show_score_pos_articles"]=="True": self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_pos_articles").set_active(True) else: self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_pos_articles").set_active(False) def destroy(self,widget): for connection in self.connectionsPool.itervalues(): connection.closeConnection() self.save_sorting_type() self.save_sizes() self.save_checkmenu_options() self.purge_groups() try: os.remove(os.path.join(self.wdir,"xpn.lock")) except: pass gtk.main_quit() def save_sorting_type(self,obj=None): for n in range(1,5): col=self.threads_pane.threads_tree.get_column(n) if col.get_sort_indicator(): order=col.get_sort_order() col_name=["Subject","From","Date","Score"][n-1] if order==gtk.SORT_ASCENDING: ascend_order="True" else: ascend_order="False" self.configs["ascend_order"]=ascend_order self.configs["sort_col"]=col_name self.conf.write_configs() def show_subscribed(self): model,path_list,iter_list=self.groups_pane.get_selected_rows() list=self.art_db.getSubscribed() new_list=[] self.subscribed_groups=[] groups_to_open=[group[0] for group in list] self.art_db.addGroups(groups_to_open) for group in list: total,unread_number=self.art_db.getArticlesNumbers(group[0]) new_list.append((group[0],str(unread_number)+" ("+str(total)+")")) self.subscribed_groups.append([group[0],group[2],group[3]]) #group_name,server_name,id_name self.groups_pane.show_list(new_list,True) self.threads_pane.clear() self.article_pane.clear() if path_list: self.groups_pane.select_row_by_path(path_list[0]) def show_threads(self,group,search_type=None,text=None): art_fup=gtk.gdk.pixbuf_new_from_file("pixmaps/art_fup.xpm") art_body=gtk.gdk.pixbuf_new_from_file("pixmaps/art_body.xpm") art_unread=gtk.gdk.pixbuf_new_from_file("pixmaps/art_unread.xpm") art_read=gtk.gdk.pixbuf_new_from_file("pixmaps/art_read.xpm") art_mark=gtk.gdk.pixbuf_new_from_file("pixmaps/art_mark.xpm") art_keep=gtk.gdk.pixbuf_new_from_file("pixmaps/art_keep.xpm") art_unkeep=gtk.gdk.pixbuf_new_from_file("pixmaps/art_unkeep.xpm") art_watch=gtk.gdk.pixbuf_new_from_file("pixmaps/art_watch.xpm") art_unwatchignore=gtk.gdk.pixbuf_new_from_file("pixmaps/art_unwatchignore.xpm") art_ignore=gtk.gdk.pixbuf_new_from_file("pixmaps/art_ignore.xpm") icons=(art_fup,art_body,art_unread,art_read,art_mark,art_keep,art_unkeep,art_watch,art_unwatchignore,art_ignore) show_read_articles=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_read_articles").get_active()) show_unread_articles=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unread_articles").get_active()) show_kept_articles=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_kept_articles").get_active()) show_unkept_articles=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unkept_articles").get_active()) show_watched_articles=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_watched_articles").get_active()) show_ignored_articles=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_ignored_articles").get_active()) show_unwatchedignored_articles=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_unwatchedignored_articles").get_active()) show_score_neg_articles=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_neg_articles").get_active()) show_score_zero_articles=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_zero_articles").get_active()) show_score_pos_articles=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_score_pos_articles").get_active()) show_threads=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads").get_active()) show_all_read_threads=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_all_read_threads").get_active()) show_threads_without_watched=bool(self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads_without_watched").get_active()) show_bools=(show_read_articles,show_unread_articles,show_kept_articles,show_unkept_articles,show_watched_articles,show_ignored_articles,show_unwatchedignored_articles,show_score_neg_articles,show_score_zero_articles,show_score_pos_articles,show_threads,show_all_read_threads) if group: self.window.set_title( "%s - XPN %s" % ( group, NUMBER ) ) else: self.window.set_title( "XPN %s" % (NUMBER,) ) if not group: return groups=[line[0] for line in self.groups_pane.model] if not group in groups: return self.threads_pane.clear() model=self.threads_pane.new_model() article_tree = {} self.statusbar.push(1,_("Please Wait. Building Threads")) def thread_alg_1(search_type=None,text=None): sort=True sorted=[] for xpn_article in self.art_db.getArticles(group,show_bools,False,search_type,text): sorted.append((xpn_article.secs,xpn_article)) if sort: sorted.sort() articles=sorted for secs, xpn_article in articles: article_info = xpn_article.get_article_info(icons) nick,from_name,ref,subj,date,date_parsed=xpn_article.get_headers() msgid=xpn_article.msgid if show_threads: try: idx=ref.rindex("<") except ValueError: #Root node article_tree[msgid] = (True, [], article_info) else: #Child node last_ref=ref[idx:] if last_ref in article_tree: #I found the father article_tree[last_ref][1].append(msgid) article_tree[msgid] = (False, [], article_info) else: #Trying threading by subject for old_article_msgid, (old_article_is_root, old_branchs, old_article_info) in article_tree.iteritems(): old_article_subj = old_article_info[1] diff_len = len(subj) - len(old_article_subj) if (old_article_subj in subj) and old_article_is_root and diff_len<=6: #Found a root article with similar subject article_tree[old_article_msgid][1].append(msgid) article_tree[msgid] = (False, [], article_info) break else: #In the list there aren't articles with similar subject article_tree[msgid] = (True, [], article_info) else: # we're populating "article_tree", but always with true because # they're all "root nodes" (show_threads is false) article_tree[msgid] = (True, [], article_info) def thread_alg_2(search_type=None,text=None): #t1=time.time() for xpn_article in self.art_db.getArticles(group,show_bools,False,search_type,text): article_info = xpn_article.get_article_info(icons) msgid=xpn_article.msgid #first create all the nodes article_tree[msgid] = (True, [], article_info) #t2=time.time() if show_threads: for is_root,children,article_info in article_tree.itervalues(): xpn_article=article_info[4] msgid=xpn_article.msgid nick,from_name,ref,subj,date,date_parsed=xpn_article.get_headers() try: idx=ref.rindex("<") except ValueError: #Root node pass else: #Child node last_ref=ref[idx:] if last_ref in article_tree: #I found the father article_tree[last_ref][1].append(msgid) article_tree[msgid] = (False, article_tree[msgid][1], article_tree[msgid][2]) #t3=time.time() #threading by subject orphaned=[(art_info[4].secs,art_info[4]) for mid,(is_root,children,art_info) in article_tree.iteritems() if (is_root and art_info[4].ref)] orphaned.sort() orp=orphaned[:] #t4=time.time() for secs,xpn_article in orphaned: subj=xpn_article.subj for is_root,children,art_info in article_tree.itervalues(): if is_root and not ((art_info[4].secs,art_info[4]) in orp): old_xpn_article=art_info[4] old_subj=old_xpn_article.subj diff_len = len(subj) - len(old_subj) if (old_subj in subj) and diff_len <=6: article_tree[old_xpn_article.msgid][1].append(xpn_article.msgid) article_tree[xpn_article.msgid] = (False, article_tree[xpn_article.msgid][1], article_tree[xpn_article.msgid][2]) break else: continue #found nothing but we can use this article as parent else: #else of the for is not executed when break is called orp.remove((xpn_article.secs,xpn_article)) #t5=time.time() #print "Lettura degli articoli e prima passata:",t2-t1 #print "Seconda passata, vegono riconosciuti i legami padre figlio:",t3-t2 #print "Estrazione degli articoli orfani:", t4-t3 #print "Terza passata, threading by subject:",t5-t4 # here we apply all the "tree wide" filters def anyUnread(node): '''Recursive function to check if all the branch is read.''' (root, branchs, info) = article_tree[node] # if the node is unread, the whole branch has any unread if info[5]: return True # if any of the sons is unread, just pass the flag to the previous call for branch in branchs: if anyUnread(branch): return True # all my sons are read return False def anyWatched(node): (root, branchs, info) = article_tree[node] if info[11]==art_watch: return True for branch in branchs: if anyWatched(branch): return True return False if search_type: search_type=search_type.lower() text=text.lower() if search_type=="from": search_type="from_name" if search_type=="body": search_type="bodies.raw_body" try: self.configs["threading_method"] except KeyError: self.configs["threading_method"]="2" if self.configs["threading_method"]=="2": thread_alg_2(search_type,text) else: thread_alg_1(search_type,text) if not show_all_read_threads: roots = [k for k,v in article_tree.iteritems() if v[0]] for article_root in roots: if not anyUnread(article_root): del article_tree[article_root] if not show_threads_without_watched: roots = [k for k,v in article_tree.iteritems() if v[0]] for article_root in roots: if not anyWatched(article_root): del article_tree[article_root] def walkTree(node, iter_mom): '''Recursive function to build the articles tree in the GTK Widget.''' # took the info about the article in the node (root, branchs, info) = article_tree[node] if info[5]: unread_in_thread = 1 else: unread_in_thread = 0 if info[11]==art_watch: watched_in_thread = 1 else: watched_in_thread = 0 watched_unread_in_thread = unread_in_thread and watched_in_thread # tell TreeStore to build a branch iter_new = self.threads_pane.insert(model, iter_mom, None, info) # build all its sons for branch in branchs: (node_iter, more_unread, more_watched, more_watched_unread) = walkTree(branch, iter_new) unread_in_thread += more_unread watched_in_thread += more_watched watched_unread_in_thread += more_watched_unread return (iter_new, unread_in_thread, watched_in_thread, watched_unread_in_thread) # with the help of walkTree, we'll build... well... the tree roots = [k for k,v in article_tree.iteritems() if v[0]] for article_root in roots: # start a branch from its root (root_iter, unread_in_thread, watched_in_thread, watched_unread_in_thread) = walkTree(article_root, None) # show how many unread items the branch has self.threads_pane.set_unread_in_thread(model, root_iter, unread_in_thread) self.threads_pane.set_unread_in_thread_visible(model, root_iter, unread_in_thread!=0) self.threads_pane.set_watched_in_thread(model, root_iter, watched_in_thread) self.threads_pane.set_watched_unread_in_thread(model, root_iter, watched_unread_in_thread) message=_("%s selected") % (group,) self.statusbar.push(1,message) self.threads_pane.set_model(model) #adjust sorting model=self.threads_pane.threads_tree.get_model() sort_col=self.configs["sort_col"].lower() sortings={"subject":1,"from":2,"date":6,"score":7} sort_col=sortings.get(sort_col,6) if self.configs["ascend_order"]=="True": sort_order=gtk.SORT_ASCENDING else: sort_order=gtk.SORT_DESCENDING model.set_sort_column_id(sort_col,sort_order) def get_server_for_group(self,group_name): server_name="" for group,server,id in self.subscribed_groups: if group==group_name: server_name=server return server_name def get_id_for_group(self,group_name): id_name="" for group,server,id in self.subscribed_groups: if group==group_name: id_name=id return id_name def view_group(self,*params): clicktype=params[-1] if self.configs["oneclick"]=="True" and clicktype=="doubleclick": return if self.configs["oneclick"]=="False" and clicktype=="oneclick": return if self.groups_lock==False: self.groups_lock=True model,path_list,iter_list=self.groups_pane.get_selected_rows() if iter_list: self.group_to_thread=model.get_value(iter_list[0],0) self.current_server=self.get_server_for_group(self.group_to_thread) self.article_pane.clear() self.show_threads(self.group_to_thread) self.msgids[self.group_to_thread]=None self.groups_lock=False if self.configs["expand_group"]=="True": self.expand_all_threads(None,True) def mark_for_download(self,article): '''mark article for download''' article.marked_for_download=not article.marked_for_download self.art_db.updateArticle(self.group_to_thread,article) def mark_subthread_for_download(self,model,root_iter,force_value=None): '''mark subthread for download''' xpn_article=self.threads_pane.get_article(model,root_iter) #let's mark the root article if force_value==True: if xpn_article.body==None: xpn_article.marked_for_download=force_value elif force_value==False: xpn_article.marked_for_download=force_value else: status=not xpn_article.marked_for_download if status==True: if xpn_article.body==None: xpn_article.marked_for_download=status else: xpn_article.marked_for_download=status if xpn_article.marked_for_download: self.threads_pane.update_article_icon("download",root_iter) else: if xpn_article.is_read: self.threads_pane.update_article_icon("read",root_iter) elif xpn_article.body!=None: self.threads_pane.update_article_icon("body",root_iter) else: self.threads_pane.update_article_icon("unread",root_iter) self.art_db.updateArticle(self.group_to_thread,xpn_article) self.threads_pane.set_article(model,root_iter,xpn_article) iter_list=self.threads_pane.get_subthread(root_iter,model,[]) for iter_child in iter_list: xpn_sub_article=self.threads_pane.get_article(model,iter_child) #watching others articles in the subthread if force_value==True: if xpn_sub_article.body==None: xpn_sub_article.marked_for_download=force_value elif force_value==False: xpn_sub_article.marked_for_download=force_value else: status=xpn_article.marked_for_download if status==True: if xpn_sub_article.body==None: xpn_sub_article.marked_for_download=status else: xpn_sub_article.marked_for_download=status if xpn_sub_article.marked_for_download: self.threads_pane.update_article_icon("download",iter_child) else: if xpn_sub_article.is_read: self.threads_pane.update_article_icon("read",iter_child) elif xpn_sub_article.body!=None: self.threads_pane.update_article_icon("body",iter_child) else: self.threads_pane.update_article_icon("unread",iter_child) self.art_db.updateArticle(self.group_to_thread,xpn_sub_article) self.threads_pane.set_article(model,iter_child,xpn_sub_article) def mark_group_for_download(self,group): '''mark the whole group for download''' if group: self.art_db.markGroupForDownload(group) self.view_group(None,None) def keep_subthread(self, model, root_iter): xpn_root_article=self.threads_pane.get_article(model,root_iter) status= xpn_root_article.keep xpn_root_article.keep=not status if status: self.threads_pane.update_article_icon("unkeep",root_iter) else: self.threads_pane.update_article_icon("keep",root_iter) self.art_db.updateArticle(self.group_to_thread,xpn_root_article) self.threads_pane.set_article(model,root_iter,xpn_root_article) iter_list=self.threads_pane.get_subthread(root_iter,model,[]) for iter_child in iter_list: xpn_sub_article=self.threads_pane.get_article(model,iter_child) xpn_sub_article.keep=not status if status: self.threads_pane.update_article_icon("unkeep",iter_child) else: self.threads_pane.update_article_icon("keep",iter_child) self.art_db.updateArticle(self.group_to_thread,xpn_sub_article) self.threads_pane.set_article(model,iter_child,xpn_sub_article) def mark_subthread_read(self,model,root_iter,read): xpn_root_article=self.threads_pane.get_article(model,root_iter) if read: self.remove_from_unreads(xpn_root_article) self.threads_pane.update_article_icon("read",root_iter) self.threads_pane.set_is_unread(model,root_iter,False) else: self.insert_in_unreads(xpn_root_article) if xpn_root_article.body==None: self.threads_pane.update_article_icon("unread",root_iter) else: self.threads_pane.update_article_icon("body",root_iter) self.threads_pane.set_is_unread(model,root_iter,True) self.threads_pane.set_article(model,root_iter,xpn_root_article) iter_list=self.threads_pane.get_subthread(root_iter,model,[]) for iter_child in iter_list: xpn_sub_article=self.threads_pane.get_article(model,iter_child) if read: self.remove_from_unreads(xpn_sub_article) self.threads_pane.update_article_icon("read",iter_child) self.threads_pane.set_is_unread(model,iter_child,False) else: self.insert_in_unreads(xpn_sub_article) if xpn_sub_article.body==None: self.threads_pane.update_article_icon("unread",iter_child) else: self.threads_pane.update_article_icon("body",iter_child) self.threads_pane.set_is_unread(model,iter_child,True) self.threads_pane.set_article(model,iter_child,xpn_sub_article) def set_keep(self,article,group): '''set keep flag''' article.keep=not article.keep self.art_db.updateArticle(group,article) def set_watch(self,model,root_iter): #set watch flag and mark on subthread xpn_article=self.threads_pane.get_article(model,root_iter) xpn_article.watch=not xpn_article.watch show_threads=self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads").get_active() if xpn_article.watch: xpn_article.ignore=False self.threads_pane.update_article_icon("watch",root_iter) self.threads_pane.update_watched_in_thread(xpn_article.watch,show_threads,True) self.threads_pane.update_watched_unread_in_thread(xpn_article.is_read,xpn_article.watch,show_threads,False,True,False) else: self.threads_pane.update_article_icon("unwatchignore",root_iter) self.threads_pane.update_watched_in_thread(xpn_article.watch,show_threads,False) self.threads_pane.update_watched_unread_in_thread(xpn_article.is_read,xpn_article.watch,show_threads,False,False,False) self.threads_pane.set_article(model,root_iter,xpn_article) self.art_db.updateArticle(self.group_to_thread,xpn_article) iter_list=self.threads_pane.get_subthread(root_iter,model,[]) for iter_child in iter_list: #watching others articles in the subthread xpn_sub_article=self.threads_pane.get_article(model,iter_child) xpn_sub_article.watch=xpn_article.watch if xpn_sub_article.watch: self.threads_pane.update_article_icon("watch",iter_child) self.threads_pane.update_watched_in_thread(xpn_article.watch,show_threads,True) self.threads_pane.update_watched_unread_in_thread(xpn_article.is_read,xpn_article.watch,show_threads,False,True,False) else: self.threads_pane.update_article_icon("unwatchignore",iter_child) self.threads_pane.update_watched_in_thread(xpn_article.watch,show_threads,False) self.threads_pane.update_watched_unread_in_thread(xpn_article.is_read,xpn_article.watch,show_threads,False,False,False) xpn_sub_article.ignore=False self.art_db.updateArticle(self.group_to_thread,xpn_sub_article) self.threads_pane.set_article(model,iter_child,xpn_sub_article) self.mark_subthread_for_download(model,root_iter,xpn_article.watch) def set_ignore(self,model,root_iter): #set ignore flag and unmark on subthread xpn_article=self.threads_pane.get_article(model,root_iter) xpn_article.ignore=not xpn_article.ignore show_threads=self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads").get_active() if xpn_article.watch: self.threads_pane.update_watched_in_thread(False,show_threads,False) self.threads_pane.update_watched_unread_in_thread(xpn_article.is_read,False,show_threads,False,False,False) if xpn_article.ignore: xpn_article.watch=False self.remove_from_unreads(xpn_article) self.threads_pane.update_article_icon("ignore",root_iter) else: self.insert_in_unreads(xpn_article) self.threads_pane.update_article_icon("unwatchignore",root_iter) self.threads_pane.set_article(model,root_iter,xpn_article) self.threads_pane.set_is_unread(model,root_iter,not xpn_article.is_read) iter_list=self.threads_pane.get_subthread(root_iter,model,[]) for iter_child in iter_list: #watching others articles in the subthread xpn_sub_article=self.threads_pane.get_article(model,iter_child) xpn_sub_article.ignore=xpn_article.ignore if xpn_sub_article.ignore: xpn_sub_article.watch=False self.remove_from_unreads(xpn_sub_article) self.threads_pane.update_article_icon("ignore",iter_child) else: xpn_sub_article.watch=False self.insert_in_unreads(xpn_sub_article) self.threads_pane.update_article_icon("unwatchignore",iter_child) self.threads_pane.set_article(model,iter_child,xpn_sub_article) self.threads_pane.set_is_unread(model,iter_child,not xpn_sub_article.is_read) self.mark_subthread_for_download(model,root_iter,xpn_article.watch) def insert_in_unreads(self,article): #reinsert article in unreads self.groups_pane.update_read_vs_unread(article.is_read,True) show_threads=self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads").get_active() self.threads_pane.update_unread_in_thread(article.is_read,show_threads,True) self.threads_pane.update_watched_unread_in_thread(article.is_read,article.watch,show_threads,True,False,True) article.is_read=False self.art_db.updateArticle(self.group_to_thread,article) def remove_from_unreads(self,article): #remove article from unreads self.groups_pane.update_read_vs_unread(article.is_read,False) show_threads=self.ui.get_widget("/MainMenuBar/View/view_group_opts/show_threads").get_active() self.threads_pane.update_unread_in_thread(article.is_read,show_threads,False) self.threads_pane.update_watched_unread_in_thread(article.is_read,article.watch,show_threads,False,False,True) article.is_read=True self.art_db.updateArticle(self.group_to_thread,article) def show_article(self,article): self.article_pane.delete_all() vadj=self.article_pane.text_scrolledwin.get_vadjustment() vadj.set_value(0) is_sign=False is_quote=False line_number=0 mute_quote=not bool(self.ui.get_widget("/MainMenuBar/View/view_articles_opts/show_quote").get_active()) mute_quote_text_inserted=False mute_sign=not bool(self.ui.get_widget("/MainMenuBar/View/view_articles_opts/show_sign").get_active()) mute_sign_text_inserted=False RE_bold=r"(?:^|.)(\*.+?\*)(?=.|$)" RE_underline=r"(?:^|[.,:;\s(])(_.+?_)(?=[.,:;\s)]|$)" RE_italic=r"(?:^|[.,:;\s(])(/.+?/)(?=[.,:;\s)]|$)" RE_url=r"(https?://[-a-zA-Z0-9_$.+!*(),;:@%&=?~#'/]*[-a-zA-Z0-9_$+!*(@%&=?~#/])" RE_mid=r"(?:^|.)(?:<)([-a-zA-Z0-9_$.+!*(),;:%&=?~#'/]+@[-a-zA-Z0-9_$.+!*(),;:%&=?~#'/]+)(?:>)(?=.|$)" compiled_bold=re.compile(RE_bold,re.UNICODE|re.DOTALL) compiled_underline=re.compile(RE_underline,re.UNICODE) compiled_italic=re.compile(RE_italic,re.UNICODE|re.DOTALL) compiled_url=re.compile(RE_url) compiled_mid=re.compile(RE_mid) def quote_depth(line): count=0 for char in line: if char==">": count=count+1 else: break if count>3: count=3 if count==0: #this prevent a warning during the mute_quote mode count=1 return str(count) for line in article: line=line.replace("\r","") #this is needed for some strange articles insert_newline=True if len(line)>0: if line[0]==">": is_quote=True elif (len(line)==2 and line[0:2]=="--") or (len(line)==3 and line[0:3]=="-- "): is_sign=True is_quote=False else: is_quote=False tag_prefix="" if is_quote and not is_sign: if mute_quote: if mute_quote_text_inserted: line="" insert_newline=False else: line=_("> [...Muted Quote...]") mute_quote_text_inserted=True quote_level=quote_depth(line) self.article_pane.insert_with_tags(line,"quote"+quote_level) tag_prefix="quote"+quote_level elif is_sign: if mute_sign: if mute_sign_text_inserted: line="" insert_newline=False else: line=_("[...Muted Sign...]") mute_sign_text_inserted=True self.article_pane.insert_with_tags(line,"sign") tag_prefix="sign" mute_quote_text_inserted=False else: self.article_pane.insert_with_tags(line,"text") tag_prefix="text" mute_quote_text_inserted=False matches_bold=compiled_bold.finditer(line) matches_underline=compiled_underline.finditer(line) matches_italic=compiled_italic.finditer(line) matches_url=compiled_url.finditer(line) matches_mid=compiled_mid.finditer(line) self.apply_styles(matches_bold,tag_prefix,"_bold",line_number,1) self.apply_styles(matches_underline,tag_prefix,"_underline",line_number,1) self.apply_styles(matches_italic,tag_prefix,"_italic",line_number,1) self.apply_styles(matches_url,"","url",line_number,0) self.apply_styles(matches_mid,"","mid",line_number,1) if insert_newline: self.article_pane.insert("\n") line_number=line_number+1 if self.ui.get_widget("/MainMenuBar/View/view_articles_opts/spoiler").get_active()==False: self.apply_spoiler() if self.ui.get_widget("/MainMenuBar/View/view_articles_opts/raw").get_active()==True: self.highlight_headers() def apply_styles(self,style_matched,tagPrefix,tagSuffix,line_number,group_number): for match in style_matched: iter_start=self.article_pane.buffer.get_start_iter() iter_start.set_line(line_number) iter_stop=iter_start.copy() iter_start.set_line_offset(match.start(group_number)) iter_stop.set_line_offset(match.end(group_number)) self.article_pane.buffer.delete(iter_start,iter_stop) self.article_pane.insert_with_tags_at_iter(iter_start,match.group(group_number),tagPrefix+tagSuffix) def highlight_headers(self): bounds=self.article_pane.buffer.get_bounds() RE_header="^.+?:" if bounds: start,stop=bounds text=self.article_pane.buffer.get_text(start,stop,True).decode("utf-8") text_splitted=text.splitlines() if "" in text_splitted: index=text_splitted.index("") else: index=0 i=0 headers_block=[] for i in range(index): headers_block.append(text_splitted[i]) text='\n'.join(headers_block) match_header=re.compile(RE_header,re.UNICODE|re.MULTILINE).finditer(text) for match in match_header: match_start,match_stop,match_text= match.start(), match.end(), match.group() iter_start=self.article_pane.buffer.get_iter_at_offset(match_start) iter_stop=self.article_pane.buffer.get_iter_at_offset(match_stop) self.article_pane.buffer.delete(iter_start,iter_stop) self.article_pane.insert_with_tags_at_iter(iter_start,match_text,"quote1_bold") def apply_spoiler(self): bounds=self.article_pane.buffer.get_bounds() RE_spoiler=chr(12)+".+?"+chr(12) if bounds: start,stop=bounds text=self.article_pane.buffer.get_text(start,stop,True).decode("utf-8") matchs_spoiler=re.compile(RE_spoiler,re.UNICODE|re.DOTALL).finditer(text) for match in matchs_spoiler: match_start,match_stop,match_text= match.start(), match.end(), match.group() iter_start=self.article_pane.buffer.get_iter_at_offset(match_start) iter_stop=self.article_pane.buffer.get_iter_at_offset(match_stop) self.article_pane.buffer.delete(iter_start,iter_stop) self.article_pane.insert_with_tags_at_iter(iter_start,match_text,"spoiler") if divmod(text.count(chr(12)),2)[1]!=0: #the number of spoiler chars is an odd number pos=text.rindex(chr(12)) iter_start=self.article_pane.buffer.get_iter_at_offset(pos) iter_stop=self.article_pane.buffer.get_end_iter() match_text=self.article_pane.buffer.get_text(iter_start,iter_stop) self.article_pane.buffer.delete(iter_start,iter_stop) self.article_pane.insert_with_tags_at_iter(iter_start,match_text,"spoiler") def retrieve_body(self,article_to_read,group,server_name=None,single_retrieve=True): if not server_name: if self.current_server: server_name=self.current_server else: server_name=self.get_server_for_group(group) self.article_pane.textview.grab_focus() message="" bodyRetrieved=True body,bodyRetrieved,message=self.art_db.retrieveBody(article_to_read,group,server_name,self.connectionsPool,single_retrieve) if single_retrieve: self.statusbar.push(1,message) return body,bodyRetrieved def view_article(self,*params): #params=obj,path,column,clicktype def return_part_number(obj): self.part_to_show=0 i=0 for button in self.article_pane.multiparts_buttons: if obj==button: self.part_to_show=i i=i+1 self.view_article("oneclick") def get_and_show_body(article_to_read,body): try: article_to_read.body_parts except: pass else: self.article_pane.add_parts_buttons(article_to_read.body_parts) for button in self.article_pane.multiparts_buttons: button.connect("released",return_part_number) try: body=article_to_read.body_parts[self.part_to_show][1].splitlines() self.article_pane.multiparts_buttons[self.part_to_show].set_active(True) except: body=article_to_read.body_parts[0][1].splitlines() if show_raw and bodyRetrieved: body=article_to_read.get_raw() self.show_article(body) clicktype=params[-1] treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() show_raw=bool(self.ui.get_widget("/MainMenuBar/View/view_articles_opts/raw").get_active()) if iter_selected!=None: article_to_read=self.threads_pane.get_article(model,iter_selected) self.msgids[self.group_to_thread]=article_to_read.msgid if self.configs["oneclick_article"]=="True" and clicktype=="doubleclick": return if self.configs["oneclick_article"]=="False" and clicktype=="oneclick": self.article_pane.clear() self.article_pane.update_headers_labels(article_to_read) #body=article_to_read.get_body() if (article_to_read.is_read) and (article_to_read.has_body): body=self.art_db.getBodyFromDB(article_to_read.original_group,article_to_read) bodyRetrieved=True get_and_show_body(article_to_read,body) self.article_pane.update_headers_labels(article_to_read) self.article_pane.set_face_x_face(article_to_read.face,article_to_read.x_face) return #self.article_pane.textview.grab_focus() body,bodyRetrieved=self.retrieve_body(article_to_read,article_to_read.original_group) ########AGGIUSTARE QUA################### ######QUANDO IL CORPO E' VUOTO BODY E' FALSO E IL PROGRAMMA NON VA AVANTI########### #####PER IL MOMENTO METTO !=NONE MA E' DA VERIFICARE NEI CASI DI ERRORI########### if body!=None: self.article_pane.clear() if bodyRetrieved: self.threads_pane.set_is_unread(model,iter_selected,False) self.threads_pane.update_article_icon("read") self.remove_from_unreads(article_to_read) self.article_pane.update_headers_labels(article_to_read) get_and_show_body(article_to_read,body) self.article_pane.set_face_x_face(article_to_read.face,article_to_read.x_face) self.threads_pane.threads_tree.grab_focus() def view_next_article(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() column=self.threads_pane.threads_tree.get_column(0) if iter_selected==None: iter_new=model.get_iter_first() else: path=model.get_path(iter_selected) iter_new=self.threads_pane.find_next_row(model,iter_selected) if iter_new!=None: path=model.get_path(iter_new) self.threads_pane.threads_tree.expand_row(path,False) #need these 3 lines to update the view and correctly point the cursor self.threads_pane.threads_tree.queue_draw() while gtk.events_pending(): gtk.main_iteration(False) self.threads_pane.threads_tree.scroll_to_cell(path,None,True,0.4,0.0) self.threads_pane.threads_tree.set_cursor(path,None,False) self.threads_pane.threads_tree.row_activated(path,column) def view_next_unread_article(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() column=self.threads_pane.threads_tree.get_column(0) if iter_selected==None: iter_selected=model.get_iter_first() if iter_selected!=None: read_status=self.threads_pane.get_is_unread(model,iter_selected) else: read_status=False while (not read_status) and (iter_selected!=None): iter_selected=self.threads_pane.find_next_row(model,iter_selected) if iter_selected!=None: read_status=self.threads_pane.get_is_unread(model,iter_selected) else: read_status=False if read_status: path=model.get_path(iter_selected) root_path=[] root_path.append(path[0]) root_path=tuple(root_path) self.threads_pane.threads_tree.expand_row(root_path,True) #need these 3 lines to update the view and correctly point the cursor self.threads_pane.threads_tree.queue_draw() while gtk.events_pending(): gtk.main_iteration(False) self.threads_pane.threads_tree.grab_focus() self.threads_pane.threads_tree.scroll_to_cell(path,None,True,0.4,0.0) self.threads_pane.threads_tree.set_cursor(path,None,False) self.threads_pane.threads_tree.row_activated(path,column) def view_previous_article(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() column=self.threads_pane.threads_tree.get_column(0) if iter_selected==None: iter_new=model.get_iter_first() else: iter_new=self.threads_pane.find_previous_row(model,iter_selected) if iter_new!=None: path=model.get_path(iter_new) self.threads_pane.threads_tree.set_cursor(path,None,False) self.threads_pane.threads_tree.row_activated(path,column) def view_parent_article(self,obj): model,iter_son=self.threads_pane.threads_tree.get_selection().get_selected() if iter_son!=None: article_son=self.threads_pane.get_article(model,iter_son) references=article_son.ref if references=="": self.statusbar.push(1,_("This is root article")) else: idx=references.rindex("<") last_ref=references[idx:] #First search the parent in the threaded articles iter_current=model.get_iter_first() success=False while iter_current!=None and not success: article_mom=self.threads_pane.get_article(model,iter_current) if article_mom.msgid==last_ref: #It is in the threads, let's show the article selecting its row path=model.get_path(iter_current) self.threads_pane.threads_tree.set_cursor(path,None,False) self.threads_pane.threads_tree.row_activated(path,self.threads_pane.column1) self.statusbar.push(1,_("Article Found")) success=True else: iter_current=self.threads_pane.find_next_row(model,iter_current) if not success: #Let' search the article on the server message,number=self.connectionsPool[self.current_server].getArticleNumber(article_son.original_group,last_ref) self.statusbar.push(1,message) if number!=-1: message,headers,last=self.connectionsPool[self.current_server].getHeaders(article_son.original_group,number,number) self.statusbar.push(1,message) if headers: number,subj,from_name,date,msgid,ref,bytes,lines,xref=headers[0] #If it is not in the threaded articles, let's insert a node for this article article=Article(number,msgid,from_name,ref,subj,date,self.configs["fallback_charset"],article_son.original_group,xref,bytes,lines) #applying score rules score=self.score_rules.apply_score_rules(article,article.original_group) article.set_score(score) nick,from_name,ref,subj,date,date_parsed=article.get_headers() art_unread=gtk.gdk.pixbuf_new_from_file("pixmaps/art_unread.xpm") art_unkeep=gtk.gdk.pixbuf_new_from_file("pixmaps/art_unkeep.xpm") if score<0: score_foreground="red" else: score_foreground="darkgreen" if score==0: show_score=False else: show_score=True iter_new=self.threads_pane.insert(model,None,iter_son,[art_unread,subj,nick,date_parsed,article,True,article.secs,article.score,score_foreground,show_score,art_unkeep,]) path=model.get_path(iter_new) self.threads_pane.threads_tree.set_cursor(path,None,False) self.threads_pane.threads_tree.row_activated(path,self.threads_pane.column1) self.statusbar.push(1,_("Article loaded")) else: self.statusbar.push(1,_("This article is not available on the server")) else: self.statusbar.push(1,_("This article is not available on the server")) def show_activity_list(self,activity_list): msg=_("There are new articles in watched threads: ") report="" if activity_list: for group,number in activity_list.iteritems(): report+=group+": "+str(number)+"\n" d=Dialog_OK(msg+"\n\n"+report) def get_new_headers(self,obj): "Download new headers for the subscribed" subscribed=self.art_db.getSubscribed() activity_list=dict() for group in subscribed: s1=len(self.art_db.getWatched(group[0])) group[1]=self.download_headers(group[0],group[1],group[2]) s2=len(self.art_db.getWatched(group[0])) if s2>s1: activity_list[group[0]]=s2-s1 self.art_db.updateSubscribed(subscribed) self.statusbar.push(1,_("Download Completed")) model,path,iter_selected=self.groups_pane.get_first_selected_row() msgid_selected=self.msgids.get(self.group_to_thread,None) self.show_subscribed() if iter_selected: self.groups_pane.groups_list.set_cursor(path,None,False) self.groups_pane.groups_list.row_activated(path,self.groups_pane.groups_list.get_column(0)) self.show_activity_list(activity_list) self.select_article_again(msgid_selected) return True #for timeout_add def select_article_again(self,msgid_selected): #let's select again the selected article if msgid_selected: treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() iter_new=model.get_iter_first() while iter_new: article=self.threads_pane.get_article(model,iter_new) path=model.get_path(iter_new) if article.msgid == msgid_selected: if len(path)>1: self.threads_pane.threads_tree.expand_row((path[0],),True) self.threads_pane.threads_tree.scroll_to_cell(path,None,True,0.4,0.0) self.threads_pane.threads_tree.set_cursor(path,None,False) iter_new=self.threads_pane.find_next_row(model,iter_new) def get_new_headers_selected(self,obj): "Dowload new headers for selected group" subscribed=self.art_db.getSubscribed() model,path_list,iter_list=self.groups_pane.get_selected_rows() activity_list=dict() msgid_selected=self.msgids.get(self.group_to_thread,None) for path in path_list: iter_selected=model.get_iter(path) group_name=model.get_value(iter_selected,0) for group in subscribed: if group[0]==group_name: s1=len(self.art_db.getWatched(group[0])) group[1]=self.download_headers(group[0],group[1],group[2]) s2=len(self.art_db.getWatched(group[0])) if s2>s1: activity_list[group_name]=s2-s1 self.art_db.updateSubscribed(subscribed) if path_list: self.show_subscribed() self.groups_pane.groups_list.set_cursor(path_list[0],None,False) self.groups_pane.groups_list.row_activated(path_list[0],self.groups_pane.groups_list.get_column(0)) self.show_activity_list(activity_list) self.select_article_again(msgid_selected) def download_headers(self,group,last_number,server_name): first=int(last_number)+1 #Downloading headers self.progressbar.set_text(_("Fetching Headers")) self.progressbar.set_fraction(1/float(2)) while gtk.events_pending(): gtk.main_iteration(False) if self.configs["limit_articles"]=="True": articles_number=int(self.configs["limit_articles_number"]) message,total_headers,last=self.connectionsPool[server_name].getHeaders(group,first,count=articles_number) else: message,total_headers,last=self.connectionsPool[server_name].getHeaders(group,first) if last!=-1: last_number=str(last) self.statusbar.push(1,message) if total_headers: self.progressbar.set_text(_("Building Articles")) else: self.progressbar.set_text(_("No New Headers")) self.progressbar.set_fraction(2/float(2)) while gtk.events_pending(): gtk.main_iteration(False) self.art_db.addHeaders(group,total_headers,server_name,self.connectionsPool) self.progressbar.set_fraction(0) self.progressbar.set_text("") return last_number def reapply_score_actions_rules(self,obj): subscribed=self.art_db.getSubscribed() j=0 for group in subscribed: j=j+1 self.progressbar.set_fraction(j/float(len(subscribed))) self.progressbar.set_text("%s / %s" % (j,len(subscribed))) self.statusbar.push(1,_("Refreshing Group %s") % group[0]) while gtk.events_pending(): gtk.main_iteration(False) for xpn_article in self.art_db.getArticles(group[0]): xpn_article.reset_article_score_actions() self.art_db.updateArticle(group[0],xpn_article) self.art_db.reapply_rules(group[0],group[2],self.connectionsPool) model,path,iter_selected=self.groups_pane.get_first_selected_row() if iter_selected: self.show_subscribed() self.groups_pane.groups_list.set_cursor(path,None,False) self.groups_pane.groups_list.row_activated(path,self.groups_pane.groups_list.get_column(0)) self.progressbar.set_fraction(0) self.progressbar.set_text("") self.statusbar.push(1,"") def get_bodies(self,obj): "Download bodies for marked articles" subscribed=self.art_db.getSubscribed() i=0 length=float(len(subscribed)) for group in subscribed: i=i+1 self.progressbar.set_fraction(i/length) self.download_bodies(group[0],group[2]) self.threads_pane.clear() self.article_pane.clear() self.progressbar.set_fraction(0) self.progressbar.set_text("") self.statusbar.push(1,_("Download Completed")) model,path,iter_selected=self.groups_pane.get_first_selected_row() msgid_selected=self.msgids.get(self.group_to_thread,None) if iter_selected: self.show_subscribed() self.groups_pane.groups_list.set_cursor(path,None,False) self.groups_pane.groups_list.row_activated(path,self.groups_pane.groups_list.get_column(0)) self.select_article_again(msgid_selected) def get_bodies_selected(self,obj): "Download bodies for marked articles in selected group" subscribed=self.art_db.getSubscribed() model,path_list,iter_list=self.groups_pane.get_selected_rows() for path in path_list: iter_selected=model.get_iter(path) group_name=model.get_value(iter_selected,0) for group in subscribed: if group[0]==group_name: self.download_bodies(group[0],group[2]) msgid_selected=self.msgids.get(self.group_to_thread,None) if path_list: self.threads_pane.clear() self.article_pane.clear() self.progressbar.set_fraction(0) self.progressbar.set_text("") self.statusbar.push(1,_("Download Completed")) self.groups_pane.groups_list.set_cursor(path_list[0],None,False) self.groups_pane.groups_list.row_activated(path_list[0],self.groups_pane.groups_list.get_column(0)) self.select_article_again(msgid_selected) def download_bodies(self,group,server_name): self.statusbar.push(1,_("Downloading Bodies for %s") % (group,)) marked_articles=[] for article in self.art_db.getArticles(group): if article.marked_for_download: marked_articles.append(article) #j=0 #length=len(marked_articles) for article in marked_articles: #j=j+1 body,bodyRetrieved=self.retrieve_body(article,group,server_name,False) #self.progressbar.set_fraction(j/float(length)) #self.progressbar.set_text(_("Downloading %s of %s") % (j,length)) while gtk.events_pending(): gtk.main_iteration(False) self.art_db._commitGroups([group,]) def one_key_reading(self,obj): #increment=80 vadj=self.article_pane.text_scrolledwin.get_vadjustment() increment= vadj.page_increment * int(self.configs["scroll_fraction"]) / 100 value= vadj.get_value() if value+increment+vadj.page_sizevadj.lower: vadj.set_value(value-decrement) else: vadj.set_value(vadj.lower) def expand_all_threads(self,obj,expand): if expand: self.threads_pane.threads_tree.expand_all() else: self.threads_pane.threads_tree.collapse_all() self.threads_pane.threads_tree.queue_draw() def expand_selected_row(self,obj,expand): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected: path=model.get_path(iter_selected) if expand: self.threads_pane.threads_tree.expand_row(path,True) else: self.threads_pane.threads_tree.collapse_row(path) self.threads_pane.threads_tree.queue_draw() def mark_group(self,obj,mark_read): "Mark selected groups read or unread" model,path_list,iter_list=self.groups_pane.get_selected_rows() for path in path_list: iter_selected=model.get_iter(path) group_to_mark=model.get_value(iter_selected,0) self.art_db.markGroupRead(group_to_mark,mark_read) if path_list: self.show_subscribed() def mark_all_groups(self,obj,mark_read): "Mark all groups read or unread" subscribed=self.art_db.getSubscribed() for group in subscribed: group_to_mark=group[0] self.art_db.markGroupRead(group_to_mark,mark_read) self.show_subscribed() def keep_group(self,obj): "Set keep flag on the whole selected groups" model,path_list,iter_list=self.groups_pane.get_selected_rows() for path in path_list: iter_selected=model.get_iter(path) group_to_mark=model.get_value(iter_selected,0) self.art_db.keepGroup(group_to_mark) self.show_subscribed() def rot13(self,text): "Rot13 the string passed" string_coded = "" dic={'a':'n','b':'o','c':'p','d':'q','e':'r','f':'s','g':'t', 'h':'u','i':'v','j':'w','k':'x','l':'y','m':'z', 'n':'a','o':'b','p':'c','q':'d','r':'e','s':'f','t':'g', 'u':'h','v':'i','w':'j','x':'k','y':'l','z':'m', 'A':'N','B':'O','C':'P','D':'Q','E':'R','F':'S','G':'T', 'H':'U','I':'V','J':'W','K':'X','L':'Y','M':'Z', 'N':'A','O':'B','P':'C','Q':'D','R':'E','S':'F','T':'G', 'U':'H','V':'I','W':'J','X':'K','Y':'L','Z':'M'} for c in text: char=dic.get(c,c) string_coded=string_coded+char return string_coded def apply_rot13(self,obj): bounds=self.article_pane.buffer.get_selection_bounds() if bounds: #rot selected text start=bounds[0] stop=bounds[1] self.article_pane.buffer.create_mark("start_rot13",start,True) text=self.article_pane.buffer.get_text(start,stop,True).decode("utf-8") text_rotted=self.rot13(text) self.article_pane.buffer.delete_selection(False,False) self.article_pane.insert(text_rotted) start=self.article_pane.buffer.get_iter_at_mark(self.article_pane.buffer.get_mark("start_rot13")) self.article_pane.buffer.move_mark_by_name("insert",start) else: #rot the article bounds=self.article_pane.buffer.get_bounds() if bounds: start,stop=bounds text=self.article_pane.buffer.get_text(start,stop,True).decode("utf-8") text_rotted=self.rot13(text) self.show_article(text_rotted.split("\n")) def set_fixed_pitch(self,obj): monospace=pango.FontDescription("Monospace 9") user=pango.FontDescription(self.configs["font_name"]) style=self.article_pane.textview.get_style().copy() if style.font_desc.get_family()!=monospace.get_family(): self.article_pane.textview.modify_font(monospace) else: self.article_pane.textview.modify_font(user) def show_hide_headers(self,obj): self.article_pane.expander.set_expanded(not self.article_pane.expander.get_expanded()) def export_newsrc(self,obj): def dispatch_response(dialog,id): if id==gtk.RESPONSE_OK: self.save_newsrc(None) if id==gtk.RESPONSE_CANCEL: self.file_dialog.destroy() self.file_dialog=gtk.FileChooserDialog(_("Select Newsrc Export Path"),None,gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK)) self.file_dialog.set_local_only(True) #self.file_dialog.set_current_name("newsrc") self.file_dialog.connect("response",dispatch_response) path=self.file_dialog.get_current_folder() self.file_dialog.set_current_folder(path) self.file_dialog.show() def import_newsrc(self,obj): def dispatch_response(dialog,id): if id==gtk.RESPONSE_OK: self.load_newsrc(None) if id==gtk.RESPONSE_CANCEL: self.file_dialog.destroy() def show_hide_hidden(obj): self.file_dialog.set_property("show_hidden",obj.get_active()) self.file_dialog=gtk.FileChooserDialog(_("Select Newsrc File"),None,gtk.FILE_CHOOSER_ACTION_OPEN,(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) hidden_checkbutton=gtk.CheckButton(_("Show Hidden Files")) self.file_dialog.set_extra_widget(hidden_checkbutton) hidden_checkbutton.connect("clicked",show_hide_hidden) self.file_dialog.set_local_only(True) self.file_dialog.connect("response",dispatch_response) path=self.file_dialog.get_current_folder() self.file_dialog.set_current_folder(path) self.file_dialog.show() def save_newsrc(self,obj): path=self.file_dialog.get_filename() newsrc_file=ExportNewsrc(self.art_db) newsrc_file.save_newsrc(path) self.file_dialog.destroy() self.statusbar.push(1,newsrc_file.message) def load_newsrc(self,obj): path=self.file_dialog.get_filename() self.file_dialog.destroy() file_name=os.path.split(path)[1] try: server_name=file_name[0:file_name.index(".newsrc")] except: server_name="" d=Dialog_Import_Newsrc(_("""To correctly import a newsrc file you have to use the same server you used when you saved the file.\n By default XPN uses a name like 'server_name.newsrc' so it is possible to know wich server was used\n When you try to import a newsrc file XPN searches for the server name in the file name.\n\n Server To Use:"""),server_name) if d.resp==gtk.RESPONSE_OK: server_name=d.server_name try: f=open(path,"rb") except IOError: self.statusbar.push(1,_("File does not exist")) else: newsrc_file=f.readlines() imp_newsrc=ImportNewsrc(newsrc_file,self,self.configs,server_name) self.show_subscribed() self.progressbar.set_fraction(0.0) self.progressbar.set_text("") self.statusbar.push(1,_("Newsrc successful imported")) def modify_keybord_shortcuts(self,obj): self.shortcuts_win=KeyBindings(self) def context_mark_read(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: article=self.threads_pane.get_article(model,iter_selected) self.remove_from_unreads(article) self.threads_pane.update_article_icon("read") self.threads_pane.set_is_unread(model,iter_selected,False) next_iter=self.threads_pane.find_next_row(model,iter_selected) if next_iter!=None and self.configs.get("advance_on_mark","False")=="True": old_path=model.get_path(iter_selected) if not self.threads_pane.threads_tree.row_expanded(old_path): self.threads_pane.threads_tree.set_cursor(old_path,None,False) self.threads_pane.threads_tree.expand_row(old_path,False) path=model.get_path(next_iter) self.threads_pane.threads_tree.expand_row(path,False) self.threads_pane.threads_tree.scroll_to_cell(path,None,True,0.4,0.0) self.threads_pane.threads_tree.set_cursor(path,None,False) def context_mark_unread(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: article=self.threads_pane.get_article(model,iter_selected) self.insert_in_unreads(article) self.threads_pane.set_is_unread(model,iter_selected,True) if article.body==None: self.threads_pane.update_article_icon("unread") else: self.threads_pane.update_article_icon("body") next_iter=self.threads_pane.find_next_row(model,iter_selected) if next_iter!=None and self.configs.get("advance_on_mark","False")=="True": old_path=model.get_path(iter_selected) if not self.threads_pane.threads_tree.row_expanded(old_path): self.threads_pane.threads_tree.set_cursor(old_path,None,False) self.threads_pane.threads_tree.expand_row(old_path,False) path=model.get_path(next_iter) self.threads_pane.threads_tree.expand_row(path,False) self.threads_pane.threads_tree.scroll_to_cell(path,None,True,0.4,0.0) self.threads_pane.threads_tree.set_cursor(path,None,False) def context_keep(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: article=self.threads_pane.get_article(model,iter_selected) self.set_keep(article,self.group_to_thread) if article.keep: self.threads_pane.update_article_icon("keep") else: self.threads_pane.update_article_icon("unkeep") next_iter=self.threads_pane.find_next_row(model,iter_selected) if next_iter!=None and self.configs.get("advance_on_mark","False")=="True": old_path=model.get_path(iter_selected) if not self.threads_pane.threads_tree.row_expanded(old_path): self.threads_pane.threads_tree.set_cursor(old_path,None,False) self.threads_pane.threads_tree.expand_row(old_path,False) path=model.get_path(next_iter) self.threads_pane.threads_tree.expand_row(path,False) self.threads_pane.threads_tree.scroll_to_cell(path,None,True,0.4,0.0) self.threads_pane.threads_tree.set_cursor(path,None,False) def context_delete(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: article=self.threads_pane.get_article(model,iter_selected) self.art_db.deleteArticle(self.group_to_thread,article) if model.iter_has_child(iter_selected): self.threads_pane.delete_row(model,iter_selected) self.show_threads(self.group_to_thread) else: self.threads_pane.delete_row(model,iter_selected) self.groups_pane.removed_article(article.is_read) def context_keep_sub(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: self.keep_subthread(model,iter_selected) def context_watch(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: self.set_watch(model,iter_selected) def context_ignore(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: self.set_ignore(model,iter_selected) def context_modify_score(self,obj,action): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: article=self.threads_pane.get_article(model,iter_selected) newsgroup=self.group_to_thread from_name=article.from_name self.score_win=Score_Win(self.score_rules,self) self.score_win.header_opt_menu.set_active(0) self.score_win.scope_combo.child.set_text("["+newsgroup+"]") self.score_win.match_type_opt_menu.set_active(0) self.score_win.match_value_entry.set_text(from_name.encode("utf-8")) self.score_win.case_checkbutton.set_active(True) self.score_win.score_mod_spinbutton.set_value(100) self.score_win.score_mod_opt_menu.set_active(action) self.score_win.show() self.score_win.notebook.set_current_page(1) def context_mark_download(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: article=self.threads_pane.get_article(model,iter_selected) if article.body==None: self.mark_for_download(article) if article.marked_for_download: self.threads_pane.update_article_icon("download") elif article.body!=None: self.threads_pane.update_article_icon("body") else: self.threads_pane.update_article_icon("unread") next_iter=self.threads_pane.find_next_row(model,iter_selected) if next_iter!=None and self.configs.get("advance_on_mark","False")=="True": old_path=model.get_path(iter_selected) if not self.threads_pane.threads_tree.row_expanded(old_path): self.threads_pane.threads_tree.set_cursor(old_path,None,False) self.threads_pane.threads_tree.expand_row(old_path,False) path=model.get_path(next_iter) self.threads_pane.threads_tree.expand_row(path,False) self.threads_pane.threads_tree.scroll_to_cell(path,None,True,0.4,0.0) self.threads_pane.threads_tree.set_cursor(path,None,False) def context_mark_download_sub(self,obj): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: self.mark_subthread_for_download(model,iter_selected) def context_mark_read_sub(self,obj,read): treesel=self.threads_pane.threads_tree.get_selection() model,iter_selected=treesel.get_selected() if iter_selected!=None: self.mark_subthread_read(model,iter_selected,read) def context_mark_download_group(self,obj): model,path_list,iter_list=self.groups_pane.get_selected_rows() for path in path_list: iter_selected=model.get_iter(path) group_to_mark=model.get_value(iter_selected,0) self.mark_group_for_download(group_to_mark) def threads_context_menu(self,obj,event): if event.button==3: menu=self.ui.get_widget("/flags") menu.popup(None,None,None,event.button,event.time) def groups_context_menu(self,obj,event): if event.button==3: menu=self.ui.get_widget("/mark_group") menu.popup(None,None,None,event.button,event.time) def find_article(self,obj): self.find_win=Find_Win(self) self.find_win.show() def global_search(self,obj): self.GlobalSearch=GlobalSearch(self) self.GlobalSearch.show() def search_in_the_article(self,obj): self.search_win=Search_Win(self) self.search_win.show() def connect_signals(self): #menuitems signals #groups_pane signals self.groups_pane.groups_list.connect("button_release_event",self.groups_context_menu) self.groups_pane.groups_list.connect("row_activated",self.view_group,"doubleclick") self.groups_pane.groups_list.get_selection().connect("changed",self.view_group,"oneclick") #threads_pane signals self.threads_pane.threads_tree.connect("button_release_event",self.threads_context_menu) self.threads_pane.threads_tree.connect("row_activated",self.view_article,"doubleclick") self.threads_pane.threads_tree.get_selection().connect("changed",self.view_article, "oneclick") self.threads_pane.column2.connect("clicked",self.save_sorting_type) self.threads_pane.column3.connect("clicked",self.save_sorting_type) self.threads_pane.column4.connect("clicked",self.save_sorting_type) self.threads_pane.column5.connect("clicked",self.save_sorting_type) #article_pane_signals self.article_pane.vbox.connect("mid_clicked",self.mid_clicked) def mid_clicked(self,obj,mid): dia=MidDialog(mid) if dia.resp==gtk.RESPONSE_OK: mid=dia.entry.get_text() if dia.sel[0]: self.find_article(None) self.find_win.entry_msgid.set_text(mid) self.find_win.checkbutton_start.set_active(True) elif dia.sel[1]: self.global_search(None) self.GlobalSearch.entry_msgid.set_text(mid) else: if self.article_pane.use_custom_browser: launcher=webbrowser.get("xpn_launcher") launcher.open("http://groups.google.com/groups?selm="+url_quote(mid)) else: webbrowser.open("http://groups.google.com/groups?selm="+url_quote(mid)) def build_panes(self): self.groups_pane=Groups_Pane(_("Newsgroups"),_("UnRead"),True,self.configs) self.threads_pane=Threads_Pane(self.configs) if self.configs["show_headers"]=="True": show_headers=True else: show_headers=False self.article_pane=Article_Pane(show_headers,self.configs) def set_sizes(self): try: f=open(os.path.join(self.wdir,"dats/sizes.dat"),"rb") except IOError: vpaned_pos=120 hpaned_pos=200 groups_col1_width=145 threads_col_subject_width=415 threads_col_from_width=201 threads_col_date_width=95 self.window.maximize() else: sizes=cPickle.load(f) f.close() vpaned_pos=sizes.get("vpaned_pos",120) hpaned_pos=sizes.get("hpaned_pos",200) mainwin_width=sizes.get("mainwin_width",640) mainwin_height=sizes.get("mainwin_height",480) mainwin_pos_x=sizes.get("mainwin_pos_x",0) mainwin_pos_y=sizes.get("mainwin_pos_y",0) groups_col1_width=int(sizes.get("groups_col1",145)) threads_col_subject_width=int(sizes.get("threads_col_subject",415)) threads_col_from_width=int(sizes.get("threads_col_from",201)) threads_col_date_width=int(sizes.get("threads_col_date",95)) self.window.resize(int(mainwin_width),int(mainwin_height)) self.window.move(int(mainwin_pos_x),int(mainwin_pos_y)) self.hpaned.set_position(int(hpaned_pos)) self.vpaned.set_position(int(vpaned_pos)) self.groups_pane.column1.set_fixed_width(groups_col1_width) self.threads_pane.column2.set_fixed_width(threads_col_subject_width) self.threads_pane.column3.set_fixed_width(threads_col_from_width) self.threads_pane.column4.set_fixed_width(threads_col_date_width) def build_layout_type_1(self,layout_number,swap=False): if layout_number==1: self.pane_1=self.groups_pane self.pane_2=self.threads_pane self.pane_3=self.article_pane elif layout_number==2: self.pane_1=self.threads_pane self.pane_2=self.groups_pane self.pane_3=self.article_pane elif layout_number==3: self.pane_1=self.article_pane self.pane_2=self.groups_pane self.pane_3=self.threads_pane elif layout_number==4: self.pane_1=self.groups_pane self.pane_2=self.article_pane self.pane_3=self.threads_pane elif layout_number==5: self.pane_1=self.threads_pane self.pane_2=self.article_pane self.pane_3=self.groups_pane elif layout_number==6: self.pane_1=self.article_pane self.pane_2=self.threads_pane self.pane_3=self.groups_pane #Vpaned self.vpaned=gtk.VPaned() self.vbox1.pack_start(self.vpaned,True,True,0) self.vpaned.show() #HPaned self.hpaned=gtk.HPaned() self.hpaned.show() pane_1_parent,pane_2_parent,pane_3_parent=self.unlink_panes() #Groups Pane self.hpaned.add(self.pane_1.get_widget()) self.pane_1.show() #Threads Pane self.hpaned.add(self.pane_2.get_widget()) self.pane_2.show() #Article Pane if not swap: self.vpaned.add(self.hpaned) self.vpaned.add(self.pane_3.get_widget()) else: self.vpaned.add(self.pane_3.get_widget()) self.vpaned.add(self.hpaned) self.pane_3.show() if pane_3_parent!=None and pane_2_parent!=None and pane_1_parent!=None: pane_3_parent.get_parent().remove(pane_3_parent) if pane_1_parent!=pane_3_parent: pane_1_parent.get_parent().remove(pane_1_parent) if pane_2_parent!=pane_3_parent and pane_2_parent!=pane_1_parent: pane_2_parent.get_parent().remove(pane_2_parent) def build_layout_type_2(self,layout_number,swap=False): if layout_number==1: self.pane_1=self.groups_pane self.pane_2=self.threads_pane self.pane_3=self.article_pane elif layout_number==2: self.pane_1=self.groups_pane self.pane_2=self.article_pane self.pane_3=self.threads_pane elif layout_number==3: self.pane_1=self.article_pane self.pane_2=self.groups_pane self.pane_3=self.threads_pane elif layout_number==4: self.pane_1=self.article_pane self.pane_2=self.threads_pane self.pane_3=self.groups_pane elif layout_number==5: self.pane_1=self.threads_pane self.pane_2=self.article_pane self.pane_3=self.groups_pane elif layout_number==6: self.pane_1=self.threads_pane self.pane_2=self.groups_pane self.pane_3=self.article_pane #HPaned self.hpaned=gtk.HPaned() self.vbox1.pack_start(self.hpaned,True,True,0) self.hpaned.show() #Vpaned self.vpaned=gtk.VPaned() self.vpaned.show() pane_1_parent,pane_2_parent,pane_3_parent=self.unlink_panes() #Groups Pane self.vpaned.add(self.pane_1.get_widget()) self.pane_1.show() #Threads Pane self.vpaned.add(self.pane_2.get_widget()) self.pane_2.show() #Article Pane if not swap: self.hpaned.add(self.vpaned) self.hpaned.add(self.pane_3.get_widget()) else: self.hpaned.add(self.pane_3.get_widget()) self.hpaned.add(self.vpaned) self.pane_3.show() if pane_3_parent!=None and pane_2_parent!=None and pane_1_parent!=None: pane_3_parent.get_parent().remove(pane_3_parent) if pane_1_parent!=pane_3_parent: pane_1_parent.get_parent().remove(pane_1_parent) if pane_2_parent!=pane_3_parent and pane_2_parent!=pane_1_parent: pane_2_parent.get_parent().remove(pane_2_parent) def build_layout_type_3(self,layout_number): self.build_layout_type_2(layout_number,True) def build_layout_type_4(self,layout_number): self.build_layout_type_1(layout_number,True) def purge_groups(self): for group in self.art_db.purgeGroups(): self.statusbar.push(1,_("Purging Group: %s") % (group,)) while gtk.events_pending(): gtk.main_iteration(False) self.art_db.closeGroups() self.art_db.closeSubscribed() def rebuild_layout(self): layout_methods = {"1":self.build_layout_type_1, "2":self.build_layout_type_2, "3":self.build_layout_type_3, "4":self.build_layout_type_4 } r,c=divmod(int(self.configs["layout"])-1,6) layout_builder = layout_methods.get(str(r+1), None) if layout_builder: layout_builder(c+1) else: self.build_layout_type_1(1) self.set_sizes() def unlink_panes(self): pane_1_parent=self.pane_1.get_widget().get_parent() if pane_1_parent!=None: pane_1_parent.remove(self.pane_1.get_widget()) pane_2_parent=self.pane_2.get_widget().get_parent() if pane_2_parent!=None: pane_2_parent.remove(self.pane_2.get_widget()) pane_3_parent=self.pane_3.get_widget().get_parent() if pane_3_parent!=None: pane_3_parent.remove(self.pane_3.get_widget()) return pane_1_parent,pane_2_parent,pane_3_parent def focus_pane(self,obj,pane): pane.grab_focus() def zoom_pane(self,pane,button): buttons=[self.zoom_groups_button,self.zoom_threads_button,self.zoom_article_button] status=button.get_active() #mantaining status buttons.remove(button) for other_button in buttons: other_button.set_active(False) button.set_active(status) if button.get_active()==True: parent1=pane.get_widget().get_parent() parent2=parent1.get_parent() parent3=parent2.get_parent() pane_1_parent,pane_2_parent,pane_3_parent=self.unlink_panes() if self.hpaned.get_parent()==self.vbox1: try:self.vbox1.remove(self.hpaned) except:pass if self.vpaned.get_parent()==self.vbox1: try:self.vbox1.remove(self.vpaned) except:pass if button.get_active()==True: self.vbox1.pack_start(pane.get_widget(),True,True,0) # if type(parent1)==type(gtk.VBox()): # self.vbox1.pack_start(pane.get_widget(),True,True,0) # if type(parent2)==type(gtk.VBox()): # parent2.remove(parent1) # self.vbox1.pack_start(pane.get_widget(),True,True,0) # if type(parent3)==type(gtk.VBox()): # parent3.remove(parent2) # self.vbox1.pack_start(pane.get_widget(),True,True,0) else: self.rebuild_layout() def zoom_article(self,obj): self.zoom_pane(self.article_pane,obj) def zoom_groups(self,obj): self.zoom_pane(self.groups_pane,obj) def zoom_threads(self,obj): self.zoom_pane(self.threads_pane,obj) def toggle_zoom_button(self,obj,button): button.set_active(not button.get_active()) def load_languages(self): #loading translation if self.configs["lang"]=="it": it=gettext.translation("xpn","lang",["it"]) it.install() try: #trying to force GTK translation locale.setlocale(locale.LC_MESSAGES,"it_IT") except: pass elif self.configs["lang"]=="fr": fr=gettext.translation("xpn","lang",["fr"]) fr.install() try: #trying to force GTK translation locale.setlocale(locale.LC_MESSAGES,"fr_FR") except: pass elif self.configs["lang"]=="de": de=gettext.translation("xpn","lang",["de"]) de.install() try: #trying to force GTK translation locale.setlocale(locale.LC_MESSAGES,"de_DE") except: pass else: try: #trying to force GTK translation locale.setlocale(locale.LC_MESSAGES,"en_US") except: pass def create_ui(self): #loading icons def _iconset (filename): return gtk.IconSet (gtk.gdk.pixbuf_new_from_file (os.path.join ("pixmaps", filename))) self.icons=gtk.IconFactory() for icon_name in os.listdir("pixmaps"): if "." in icon_name and not icon_name.endswith(".svg"): self.icons.add("xpn_"+icon_name.split(".")[0], _iconset (icon_name)) self.icons.add_default() #try: # self.ui.remove_action_group(self.actiongroup) # self.ui.remove_ui(self.merge_id) # self.window.remove_accel_group(self.accel_group) #except: # pass self.ui = gtk.UIManager() self.accelgroup = self.ui.get_accel_group() self.actiongroup= gtk.ActionGroup("MainWindowActions") self.window.add_accel_group(self.accelgroup) mscuts=load_shortcuts("main") self.actions=[("File",None,_("_File")), ("groups","xpn_groups",_("Groups List..."),mscuts["groups"],_("Manage Groups"),self.open_groups_win), ("rules","xpn_score",_("Scoring and Action Rules..."),mscuts["rules"],_("Edit Scoring and Action Rules"),self.open_rules_win), ("logs",None,_("Server Logs..."),mscuts["logs"],None,self.open_logs_win), ("exp_newsrc",None,_("Export Newsrc..."),mscuts["exp_newsrc"],None,self.export_newsrc), ("imp_newsrc",None,_("Import Newsrc..."),mscuts["imp_newsrc"],None,self.import_newsrc), ("accelerator",None,_("Modify Keyboard Shortcuts..."),mscuts["accelerator"],None,self.modify_keybord_shortcuts), ("conf","xpn_conf",_("Preferences..."),mscuts["conf"],_("Preferences"),self.open_configure_win), ("exit","xpn_exit",_("Exit"),mscuts["exit"],None,self.destroy), ("Search",None,_("_Search")), ("find","xpn_find",_("Find Article..."),mscuts["find"],None,self.find_article), ("global","xpn_global_search",_("Global Search ..."),mscuts["global"],None,self.global_search), ("filter",None,_("Filter Articles ..."),mscuts["filter"],None,self.filter_articles), ("search","xpn_search",_("Search in the Body..."),mscuts["search"],None,self.search_in_the_article), ("View",None,_("_View")), ("view_articles_opts",None,_("Articles View Options")), ("view_group_opts",None,_("Groups View Options")), ("Navigate",None,_("_Navigate")), ("group",None,_("View Next Group"),mscuts["group"],None,self.groups_pane.view_next_group), ("previous","xpn_previous",_("Read Previous Article"),mscuts["previous"],_("Read Previous Article"),self.view_previous_article), ("next","xpn_next",_("Read Next Article"),mscuts["next"],_("Read Next Article"),self.view_next_article), ("next_unread","xpn_next_unread",_("Read Next Unread Article"),mscuts["next_unread"],_("Read Next Unread Article"),self.view_next_unread_article), ("parent",None,_("Read Parent Article"),mscuts["parent"],None,self.view_parent_article), ("one_key",None,_("One-Key Reading"),mscuts["one_key"],None,self.one_key_reading), ("move_up",None,_("One-Key Scroll Up"),mscuts["move_up"],None,self.one_key_move_up), ("focus_article",None,_("Focus to Article Pane"),mscuts["focus_article"],None,self.focus_pane,self.article_pane.textview), ("focus_groups",None,_("Focus to Groups Pane"),mscuts["focus_groups"],None,self.focus_pane,self.groups_pane.groups_list), ("focus_threads",None,_("Focus to Threads Pane"),mscuts["focus_threads"],None,self.focus_pane,self.threads_pane.threads_tree), ("zoom_article",None,_("Zoom Article Pane"),mscuts["zoom_article"],None,self.toggle_zoom_button,self.zoom_article_button), ("zoom_groups",None,_("Zoom Groups Pane"),mscuts["zoom_groups"],None,self.toggle_zoom_button,self.zoom_groups_button), ("zoom_threads",None,_("Zoom Threads Pane"),mscuts["zoom_threads"],None,self.toggle_zoom_button,self.zoom_threads_button), ("Subscribed",None,_("Subscribed _Groups")), ("gethdrs","xpn_receive_headers",_("Get New Headers in Subscribed Groups"),mscuts["gethdrs"],_("Get New Headers in Subscribed Groups"),self.get_new_headers), ("gethdrssel","xpn_receive_headers_selected",_("Get New Headers in Selected Groups"),mscuts["gethdrssel"],None,self.get_new_headers_selected), ("getbodies","xpn_receive_bodies",_("Get Marked Article Bodies in Subscribed Groups"),mscuts["getbodies"],_("Get Marked Article Bodies in Subscribed Groups"),self.get_bodies), ("getbodiessel","xpn_receive_bodies_selected",_("Get Marked Article Bodies in Selected Groups"),mscuts["getbodiessel"],None,self.get_bodies_selected), ("expand","xpn_expand_all",_("Expand All Threads"),mscuts["expand"],_("Expand All"),self.expand_all_threads,True), ("collapse","xpn_collapse_all",_("Collapse All Threads"),mscuts["collapse"],_("Collapse All"),self.expand_all_threads,False), ("expand_row","xpn_expand",_("Expand Selected SubThread"),mscuts["expand_row"],_("Expand Selected SubThread"),self.expand_selected_row,True), ("collapse_row","xpn_collapse",_("Collapse Selected SubThread"),mscuts["collapse_row"],_("Collapse Selected SubThread"),self.expand_selected_row,False), ("mark_group",None,_("Mark Group ...")), ("mark","xpn_mark",_("Mark Selected Groups as Read"),mscuts["mark"],_("Mark Selected Groups as Read"),self.mark_group,True), ("mark_unread_group",None,_("Mark Selected Groups as Unread"),mscuts["mark_unread_group"],None,self.mark_group,False), ("mark_download_group","xpn_mark_multiple",_("Mark Group for Retrieving"),mscuts["mark_download_group"],None,self.context_mark_download_group), ("keepall","xpn_art_keep",_("Keep Articles in Selected Groups"),mscuts["keepall"],None,self.keep_group), ("markall","xpn_mark_all",_("Mark All Groups as Read"),mscuts["markall"],_("Mark All Groups as Read"),self.mark_all_groups,True), ("markall_unread",None,_("Mark All Groups as Unread"),mscuts["markall_unread"],None,self.mark_all_groups,False), ("apply_score",None,_("Apply Scoring and Action Rules"),mscuts["apply_score"],None,self.reapply_score_actions_rules), ("groups_vs_id",None,_("Assign Identities to Groups"),mscuts["groups_vs_id"],None,self.open_groups_vs_id), ("Articles",None,_("_Articles")), ("show_hide_headers",None,_("Show/Hide Headers"),mscuts["show_hide_headers"],None,self.show_hide_headers), ("rot13","xpn_rot13",_("ROT13 Selected Text"),mscuts["rot13"],_("ROT13 Selected Text"),self.apply_rot13), ("flags",None,_("Flags & Score")), ("mark_read","xpn_art_read",_("Mark Article as Read"),mscuts["mark_read"],None,self.context_mark_read), ("mark_unread","xpn_art_unread",_("Mark Article as UnRead"),mscuts["mark_unread"],None,self.context_mark_unread), ("mark_download","xpn_art_mark",_("Mark Article for Retrieving"),mscuts["mark_download"],None,self.context_mark_download), ("keep","xpn_art_keep",_("Keep Article"),mscuts["keep"],None,self.context_keep), ("delete","xpn_art_delete",_("Delete Article"),mscuts["delete"],None,self.context_delete), ("mark_unread_sub",None,_("Mark SubThread as UnRead"),mscuts["mark_unread_sub"],None,self.context_mark_read_sub,False), ("mark_read_sub","xpn_art_read",_("Mark SubThread as Read"),mscuts["mark_read_sub"],None,self.context_mark_read_sub,True), ("mark_download_sub","xpn_mark_multiple",_("Mark SubThread for Retrieving"),mscuts["mark_download_sub"],None,self.context_mark_download_sub), ("keep_sub","xpn_art_keep",_("Keep SubThread"),mscuts["keep_sub"],None,self.context_keep_sub), ("watch","xpn_art_watch",_("Watch SubThread"),mscuts["watch"],None,self.context_watch), ("ignore","xpn_art_ignore",_("Ignore SubThread"),mscuts["ignore"],None,self.context_ignore), ("raise_score","xpn_raise_score",_("Raise Author Score"),mscuts["raise_score"],None,self.context_modify_score,0), ("lower_score","xpn_lower_score",_("Lower Author Score"),mscuts["lower_score"],None,self.context_modify_score,1), ("set_score","xpn_set_score",_("Set Author Score"),mscuts["set_score"],None,self.context_modify_score,2), ("post","xpn_post",_("Post New Article..."),mscuts["post"],_("Post New Article"),self.open_edit_win), ("outbox_manager","xpn_outbox",_("Open Outbox Manager"),mscuts["outbox_manager"],_("Open Outbox Manager"),self.open_outbox_manager), ("followup","xpn_followup",_("Follow-Up To Newsgroup..."),mscuts["followup"],_("Follow-Up To Newsgroup"),self.open_edit_win,True), ("reply","xpn_reply",_("Reply By Mail..."),mscuts["reply"],_("Reply by Mail"),self.open_edit_mail_win), ("supersede","xpn_supersede",_("Supersede Article..."),mscuts["supersede"],None,self.supersede_cancel_message,"Supersede"), ("cancel","xpn_cancel",_("Cancel Article..."),mscuts["cancel"],None,self.supersede_cancel_message,"Cancel"), ("Help",None,_("Help")), ("about","xpn_about",_("About..."),mscuts["about"],None,self.open_about_dialog)] for action in self.actions: if len(action)<7: self.actiongroup.add_actions([action]) else: self.actiongroup.add_actions([action[0:6]],action[-1]) self.toggle_actions=[ ("show_threads",None,_("Show Threads"),mscuts["show_threads"],None,self.view_group,False,None,None), ("show_all_read_threads",None,_("Show All Read Threads"),mscuts["show_all_read_threads"],None,self.view_group,False,None,None), ("show_threads_without_watched",None,_("Show Threads Without Watched Articles"),mscuts["show_threads_without_watched"],None,self.view_group,False,None,None), ("show_read_articles",None,_("Show Read Articles"),mscuts["show_read_articles"],None,self.view_group,False,None,None), ("show_unread_articles",None,_("Show UnRead Articles"),mscuts["show_unread_articles"],None,self.view_group,False,None,None), ("show_kept_articles",None,_("Show Kept Articles"),mscuts["show_kept_articles"],None,self.view_group,False,None,None), ("show_unkept_articles",None,_("Show UnKept Articles"),mscuts["show_unkept_articles"],None,self.view_group,False,None,None), ("show_watched_articles",None,_("Show Watched Articles"),mscuts["show_watched_articles"],None,self.view_group,False,None,None), ("show_ignored_articles",None,_("Show Ignored Articles"),mscuts["show_ignored_articles"],None,self.view_group,False,None,None), ("show_unwatchedignored_articles",None,_("Show UnWatched/UnIgnored Articles"),mscuts["show_unwatchedignored_articles"],None,self.view_group,False,None,None), ("show_score_neg_articles",None,_("Show Articles with Score<0"),mscuts["show_score_neg_articles"],None,self.view_group,False,None,None), ("show_score_zero_articles",None,_("Show Articles with Score=0"),mscuts["show_score_zero_articles"],None,self.view_group,False,None,None), ("show_score_pos_articles",None,_("Show Articles with Score>0"),mscuts["show_score_pos_articles"],None,self.view_group,False,None,None), ("raw",None,_("View Raw Article"),mscuts["raw"],None,self.view_article,False), ("spoiler",None,_("Show Spoilered Text"),mscuts["spoiler"],None,self.view_article,False), ("show_quote",None,_("Show Quoted Text"),mscuts["show_quote"],None,self.view_article,False), ("show_sign",None,_("Show Signatures"),mscuts["show_sign"],None,self.view_article,False), ("fixed",None,_("Fixed Pitch Font"),mscuts["fixed"],None,self.set_fixed_pitch,False)] for action in self.toggle_actions: if len(action)<8: self.actiongroup.add_toggle_actions([action]) else: self.actiongroup.add_toggle_actions([action[0:7]],action[7:]) self.ui.insert_action_group(self.actiongroup,0) self.merge_id = self.ui.add_ui_from_string(ui_string) self.ui.ensure_update() def toolbar_search(self,obj,search_type,text): self.show_threads(self.group_to_thread,search_type,text) def search_focus_changed(self,obj,event,focusIn): if focusIn: #we have to disable accelerator self.window.remove_accel_group(self.accelgroup) else: self.window.add_accel_group(self.accelgroup) def close_filter_toolbar(self,obj): self.filter_toolbar.hide() def filter_articles(self,obj): self.filter_toolbar.show_all() self.cs_entry.grab_focus() def recoverPreviousInstall(self): '''Recover files from 1.0 installation''' #Looking for groups.dat files file_list=os.listdir(os.path.join(self.wdir,"groups_info")) groups_list_db=Groups_DB() for file_name in file_list: if file_name.endswith("groups.dat"): print "Recovering", file_name f=open(os.path.join(self.wdir,"groups_info",file_name)) try: list_to_recover=cPickle.load(f) except: list_to_recover=[] f.close() groups_list_db.createList(list_to_recover,"",file_name.replace(".dat",".sqlitedb")) os.remove(os.path.join(self.wdir,"groups_info",file_name)) #Looking for subscribed.dat files if "subscribed.dat" in file_list: print "Recovering subscribed.dat" f=open(os.path.join(self.wdir,"groups_info","subscribed.dat")) try:subscribed=cPickle.load(f) except:subscribed=[] f.close() for group in subscribed: self.art_db.addSubscribed(group[0],group[1],group[2],group[3]) os.remove(os.path.join(self.wdir,"groups_info","subscribed.dat")) for group in subscribed: print "Recovering Group:", group import shelve try:art=shelve.open(os.path.join(self.wdir,"groups_info",group[0],group[0])) except:art=[] articles=dict(art) try:art.close() except:pass shutil.rmtree(os.path.join(self.wdir,"groups_info",group[0])) self.art_db.createGroup(group[0]) for article in articles.itervalues(): if article.body: #This is needed for the recoverPreviousInstall function article.raw_body=article.get_raw() article.has_body=True self.art_db._insertBody(group[0],article,False) else: article.raw_body="" article.has_body=False self.art_db.insertArticle(group[0],article) def __init__(self,use_home,custom_dir): Edit_Win.VERSION=VERSION Edit_Mail_Win.VERSION=VERSION if use_home: userdir=UserDir(userHome=True) elif custom_dir: userdir=UserDir(customPath=custom_dir) else: userdir=UserDir(cwd=True) ret=userdir.Create() if ret>0 :sys.exit(ret) self.wdir=userdir.dir self.conf=Config_File() self.configs=self.conf.get_configs() self.load_languages() try: open(os.path.join(self.wdir,"xpn.lock"),"r") except IOError:open(os.path.join(self.wdir,"xpn.lock"),"w") else: #raise StandardError, "An istance of XPN is already running, if you think this is an error remove manually the file 'xpn.lock' in your XPN working directory." md=Dialog_YES_NO(_("An instance of XPN is already running.\n\nDo you want to open XPN anyway?")) if not md.resp: sys.exit() try: os.remove(os.path.join(self.wdir,"server_logs.dat")) except: pass try: os.remove(os.path.join(self.wdir,"error_logs.dat")) except: pass try: map(shutil.rmtree,glob.glob(os.path.join(self.wdir,"groups_info/global.search.results.*"))) except: pass try: os.makedirs(os.path.join(self.wdir,"groups_info")) except: pass try: os.makedirs(os.path.join(self.wdir,"dats")) except: pass try: os.makedirs(os.path.join(self.wdir,"outbox/news")) except: pass try: os.makedirs(os.path.join(self.wdir,"outbox/mail")) except: pass try: os.makedirs(os.path.join(self.wdir,"draft/news")) except: pass try: os.makedirs(os.path.join(self.wdir,"draft/mail")) except: pass try: os.makedirs(os.path.join(self.wdir,"sent/news")) except: pass try: os.makedirs(os.path.join(self.wdir,"sent/mail")) except: pass self.s=None self.groups_lock=False self.group_to_thread="" self.current_server="" self.subscribed_groups=[] self.art_db=Articles_DB() self.recoverPreviousInstall() cp=ConfigParser.ConfigParser() cp.read(os.path.join(get_wdir(),"dats","servers.txt")) self.connectionsPool=dict() for server in cp.sections(): if cp.get(server,"nntp_use_ssl")=="True": self.connectionsPool[server]=SSLConnection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) else: self.connectionsPool[server]=Connection(cp.get(server,"server"),cp.get(server,"port"),cp.get(server,"auth"),cp.get(server,"username"),cp.get(server,"password")) #loading score rules self.score_rules=Score_Rules() #MainMenuBar self.window=gtk.Window (gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event",self.delete_event) self.window.connect("destroy",self.destroy) self.window.set_title("XPN "+NUMBER) self.window.set_icon(gtk.gdk.pixbuf_new_from_file("pixmaps/xpn-icon.png")) self.window.set_size_request(300,200) self.build_panes() self.zoom_article_button=gtk.ToggleButton("A") self.zoom_threads_button=gtk.ToggleButton("H") self.zoom_groups_button=gtk.ToggleButton("G") #UIManager self.create_ui() #Filter Toolbar se_toolitem=gtk.ToolItem() self.cs_entry=Custom_Search_Entry() self.cs_entry.connect("do_search",self.toolbar_search) self.cs_entry.connect("search_focus_in",self.search_focus_changed,True) self.cs_entry.connect("search_focus_out",self.search_focus_changed,False) se_toolitem.add(self.cs_entry) se_toolitem.show_all() label_toolitem=gtk.ToolItem() label=gtk.Label(_("Filter Articles by: ")) label_toolitem.add(label) label_toolitem.show_all() close_tool_button=gtk.ToolButton(gtk.STOCK_CLOSE) try: close_tool_button.set_tooltip_text(_("Close Filter Toolbar")) except: pass #doesn't work with some old GTK close_tool_button.connect("clicked",self.close_filter_toolbar) close_tool_button.show_all() self.filter_toolbar=gtk.Toolbar() self.filter_toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) self.filter_toolbar.set_style(gtk.TOOLBAR_ICONS) self.filter_toolbar.insert(label_toolitem,-1) self.filter_toolbar.insert(se_toolitem,-1) self.filter_toolbar.insert(close_tool_button,-1) menubar=self.ui.get_widget("/MainMenuBar") toolbar=self.ui.get_widget("/MainToolBar") #toolbar.set_icon_size(gtk.ICON_SIZE_LARGE_TOOLBAR) toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) toolbar.set_style(gtk.TOOLBAR_ICONS) #main vbox self.vbox1 = gtk.VBox(False,0) self.window.add(self.vbox1) self.vbox1.show() self.vbox1.pack_start(menubar,False,True,0) menubar.show() #Handlebox self.vbox1.pack_start(toolbar,False,False,0) toolbar.show() self.vbox1.pack_start(self.filter_toolbar,False,False,0) layout_methods = {"1":self.build_layout_type_1, "2":self.build_layout_type_2, "3":self.build_layout_type_3, "4":self.build_layout_type_4 } r,c=divmod(int(self.configs["layout"])-1,6) layout_builder = layout_methods.get(str(r+1), None) if layout_builder: layout_builder(c+1) else: self.build_layout_type_1(1) # If there is no layout associated to # self.configs["layout"] then build 1 #hbox_bottom hbox_bottom=gtk.HBox() self.vbox1.pack_end(hbox_bottom,False,False,0) hbox_bottom.show() #progressbar self.progressbar=gtk.ProgressBar() hbox_bottom.pack_start(self.progressbar,False,False,0) self.progressbar.show() #Zoom Buttons self.zoom_article_button.set_relief(gtk.RELIEF_NONE) self.zoom_threads_button.set_relief(gtk.RELIEF_NONE) self.zoom_groups_button.set_relief(gtk.RELIEF_NONE) self.zoom_article_button.connect("clicked",self.zoom_article) self.zoom_threads_button.connect("clicked",self.zoom_threads) self.zoom_groups_button.connect("clicked",self.zoom_groups) zoom_article_tip=gtk.Tooltips() zoom_threads_tip=gtk.Tooltips() zoom_groups_tip=gtk.Tooltips() zoom_article_tip.set_tip(self.zoom_article_button,_("Zoom Article Pane")) zoom_threads_tip.set_tip(self.zoom_threads_button,_("Zoom Headers Pane")) zoom_groups_tip.set_tip(self.zoom_groups_button,_("Zoom Groups Pane")) hbox_bottom.pack_start(self.zoom_article_button,False,False,0) hbox_bottom.pack_start(self.zoom_threads_button,False,False,0) hbox_bottom.pack_start(self.zoom_groups_button,False,False,0) self.zoom_article_button.show() self.zoom_threads_button.show() self.zoom_groups_button.show() separator=gtk.VSeparator() separator.show() hbox_bottom.pack_start(separator,False,False,0) #statusbar self.statusbar=gtk.Statusbar() hbox_bottom.pack_start(self.statusbar,True,True,0) self.statusbar.show() self.connect_signals() self.show_subscribed() self.update_checkmenu_options() monospace=pango.FontDescription("Monospace 9") if self.configs["use_system_fonts"]=="True": user=pango.FontDescription("") else: user=pango.FontDescription(self.configs["font_name"]) if self.configs["fixed"]=="True": self.article_pane.textview.modify_font(monospace) else: self.article_pane.textview.modify_font(user) self.article_pane.textview.set_indent(5) self.set_sizes() self.mainwin_width=None #I must use these because if I close the window with the [x] self.mainwin_height=None #I loose window sizes self.mainwin_pos_x=None self.mainwin_pos_y=None self.window.show() if not self.conf.found_config_file: dia=Dialog_YES_NO(_("Missing Config File.\n\nDo you want to Configure XPN now?")) if dia.resp: self.open_configure_win(None) self.msgids=dict() timeout=int(self.configs.get("download_timeout",'30')) do_auto_download=eval(self.configs.get("automatic_download","False")) if do_auto_download: gobject.timeout_add(timeout*1000*60,self.get_new_headers,None) def hook(et,ev,eb): import traceback ex_list=traceback.format_exception(et,ev,eb) list="".join(ex_list) if not ("sys.exit()" in list or "systemexit" in list.lower()): message="\n"+"".join(ex_list) log=message try: f=open(os.path.join(wdir,"error_logs.dat"),"a") except IOError: pass else: f.write(":::: "+time.ctime(time.time())+" :::: \n"+message+"\n\n") f.close() try: f=open(os.path.join(wdir,"error_logs.dat"),"rb") except IOError: pass else: log=f.read() try: error_dialog=Error_Dialog(unicode(message,"us-ascii","replace").encode("utf-8"),unicode(log,"us-ascii","replace").encode("utf-8")) error_dialog.run() except: sys.stderr.write(_('Unexpected error in the excepthook.')) sys.stderr.write('\n\n') message = message="\n"+"".join(traceback.format_exception(*sys.exc_info())) sys.stderr.write(message) else: error_dialog.destroy() parser=OptionParser(usage=_("python %prog [-d] [-cCUSTOM_DIR]\n\nWith command line options you can decide where XPN will save config files and articles.\nIf you don't use any option, the current working directory will be used.\nIf you use the '--home_dir' option, XPN will create a .xpn directory inside your home directory, and will store informations inside that directory.\nIf you use the '--custom_dir' option, XPN will create a .xpn directory inside that custom_directory.\n\nNOTE: If you set the '--home_dir' option, XPN will ignore the '--custom_dir' option (if you used it).\n\nExamples:\npython xpn.py\npython xpn.py -d\npython xpn.py --custom_dir /home/user/custom")) parser.add_option("-d","--home_dir",action="store_true",dest="use_home",default=False, help=_("use home directory to store config files and articles")) parser.add_option("-c","--custom_dir",dest="custom_dir", help=_("specify an existing directory where store config files and articles")) options,args=parser.parse_args() try: dir=os.path.dirname(sys.argv[0]) except: dir="" if dir: try:os.chdir(dir) except: pass try: main=MainWin(options.use_home,options.custom_dir) wdir=main.wdir except: def eHook(): hook(*sys.exc_info()) gtk.main_quit() wdir='' gobject.timeout_add(100,eHook) gtk.main() else: #reload(sys) #sys.setdefaultencoding("ascii") sys.excepthook=hook gtk.main() xpn-1.2.6/INSTALL0000644000175000017500000000152211141275756011515 0ustar antant******************************************************************************* * X Python Newsreader * * INSTALL * ******************************************************************************* No installation required. You just have to launch the programm from its directory, using: ./xpn.py type ./xpn.py --help to get informations on command-line options Note: XPN won't work if you launch it with a symlink that point to the file xpn.py. But you can create a simple launcher script like this: #! /usr/bin/env bash /path/to/xpn/dir/xpn.py and then you can creat a symlink that points on this launcher. XPN - X Python Newsreader Copyright (C) 2003 Antonio Caputo xpn-1.2.6/pixmaps/0000755000175000017500000000000011141275756012145 5ustar antantxpn-1.2.6/pixmaps/discard.xpm0000644000175000017500000001104711141275756014307 0ustar antant/* XPM */ static char * discard_xpm[] = { "24 24 209 2", " c None", ". c #905A4D", "+ c #A25E4E", "@ c #AE5E4E", "# c #A35545", "$ c #884335", "% c #956256", "& c #BF6550", "* c #DD573A", "= c #DA4424", "- c #D63A1B", "; c #D23719", "> c #CF391E", ", c #B6341F", "' c #842516", ") c #9C675A", "! c #D85B3D", "~ c #DC411E", "{ c #D93C1B", "] c #D53919", "^ c #D23618", "/ c #CF3317", "( c #CB2F15", "_ c #C82C14", ": c #C22912", "< c #8E1C0D", "[ c #97675B", "} c #DC5738", "| c #DC3F1C", "1 c #D83C1B", "2 c #D53819", "3 c #D13518", "4 c #CE3217", "5 c #C42912", "6 c #C12511", "7 c #BC220F", "8 c #84160A", "9 c #8C665E", "0 c #CA5F47", "a c #DB3F1C", "b c #D83B1B", "c c #D43819", "d c #CE3216", "e c #C72C14", "f c #C42812", "g c #BD220F", "h c #BA1F0E", "i c #B21B0C", "j c #5D0C05", "k c #A0685C", "l c #DA4423", "m c #D73B1A", "n c #D33819", "o c #CF3417", "p c #CC3116", "q c #C92E15", "r c #C62B13", "s c #C22812", "t c #BF2510", "u c #BB220F", "v c #B81E0E", "w c #B61C0C", "x c #B3180B", "y c #871007", "z c #000000", "A c #140E0D", "B c #AD5745", "C c #D73B1B", "D c #CB4E36", "E c #DAABA2", "F c #DDADA5", "G c #DBABA3", "H c #D8A9A2", "I c #D7A7A0", "J c #D5A59F", "K c #D3A39D", "L c #D1A29C", "M c #D0A09B", "N c #BE4F45", "O c #AF1509", "P c #930E05", "Q c #110100", "R c #E8E3E3", "S c #BD4B34", "T c #D43719", "U c #D05D48", "V c #F3F3F3", "W c #F7F7F7", "X c #F6F6F6", "Y c #F4F4F4", "Z c #F1F1F1", "` c #F0F0F0", " . c #EEEEEE", ".. c #CF7B75", "+. c #AC1208", "@. c #9C0D05", "#. c #C0A7A6", "$. c #FEFEFE", "%. c #FFFFFF", "&. c #120D0C", "*. c #B53D26", "=. c #D03417", "-. c #CE5B47", ";. c #F2F2F2", ">. c #EDEDED", ",. c #ECECEC", "'. c #CC7872", "). c #A80E06", "!. c #8F0A04", "~. c #B7A2A1", "{. c #EEE8E7", "]. c #96301E", "^. c #CC3F28", "/. c #D77769", "(. c #D87B6F", "_. c #D67A6E", ":. c #D3766B", "<. c #D07268", "[. c #CE7067", "}. c #CC6D65", "|. c #C96962", "1. c #C5635E", "2. c #B12B25", "3. c #A40B04", "4. c #7C0C09", "5. c #0A0000", "6. c #E9E9E9", "7. c #FCFBFB", "8. c #A4655B", "9. c #C52C14", "0. c #C62A13", "a. c #C22711", "b. c #BF2410", "c. c #BB210E", "d. c #B81D0D", "e. c #B51A0C", "f. c #B2170A", "g. c #AE1409", "h. c #AB1107", "i. c #A70E06", "j. c #A40A04", "k. c #990703", "l. c #4D0100", "m. c #A7A7A7", "n. c #D5D5D5", "o. c #CCB9B6", "p. c #A52815", "q. c #C22611", "r. c #BF2310", "s. c #BB200E", "t. c #B41A0B", "u. c #B1170A", "v. c #AA1007", "w. c #A70D06", "x. c #9F0703", "y. c #810201", "z. c #5D4545", "A. c #9E9E9E", "B. c #C9C9C9", "C. c #FBFAFA", "D. c #9C6760", "E. c #B0200E", "F. c #AE1309", "G. c #A00703", "H. c #8A0201", "I. c #531515", "J. c #707070", "K. c #9D9D9D", "L. c #CACACA", "M. c #F5F3F3", "N. c #975E57", "O. c #A41B0D", "P. c #B3190B", "Q. c #B0160A", "R. c #AD1308", "S. c #A60D05", "T. c #A30904", "U. c #9D0602", "V. c #810200", "W. c #521818", "X. c #605E5E", "Y. c #888888", "Z. c #B1B1B1", "`. c #DADADA", " + c #F3F1F1", ".+ c #AE8E8A", "++ c #710D05", "@+ c #9C1107", "#+ c #A60F06", "$+ c #A40C05", "%+ c #9B0903", "&+ c #860501", "*+ c #5C0000", "=+ c #220000", "-+ c #747272", ";+ c #919191", ">+ c #B0B0B0", ",+ c #D3D3D3", "'+ c #EAE6E6", ")+ c #B9A4A3", "!+ c #280201", "~+ c #875755", "{+ c #7E5756", "]+ c #130000", "^+ c #959292", "/+ c #AAAAAA", "(+ c #DFDFDF", "_+ c #FBFBFB", ":+ c #999999", " . + @ # $ ", " % & * = - ; > , ' ", " ) ! ~ { ] ^ / ( _ : < ", " [ } | 1 2 3 4 ( _ 5 6 7 8 ", " 9 0 a b c 3 d ( e f 6 g h i j ", " k l m n o p q r s t u v w x y ", " z z A B C D E F G H I J K L M N O P Q z z z ", " z z R S T U V W X Y V Z ` . ...+.@.#.$.z z ", " z %.&.*.=.-.` V ;.Z ` .>.,.,.'.).!.~.z %.z ", " z %.{.].p ^./.(._.:.<.[.}.|.1.2.3.4.5.6.%.z ", " z %.7.8.9.0.a.b.c.d.e.f.g.h.i.j.k.l.m.n.%.z ", " z %.%.o.p.q.r.s.d.t.u.g.v.w.j.x.y.z.A.B.%.z ", " z %.%.C.D.E.s.d.t.u.F.v.w.j.G.H.I.J.K.L.%.z ", " z %.%.%.M.N.O.P.Q.R.v.S.T.U.V.W.X.Y.Z.`.%.z ", " z %.%.%.%. +.+++@+#+$+%+&+*+=+-+;+>+,+ .%.z ", " z %.%.%.%.%.z '+)+!+~+{+]+^+/+z B.(+Z _+%.z :+", " z %.%.%.%.z %.%.%.%.z z %.%.%.%.z %.%.%.%.z :+", " z %.%.%.z %.%.%.%.%.%.%.%.%.%.%.%.z %.%.%.z :+", " z %.%.z %.%.%.%.%.%.%.%.%.%.%.%.%.%.z %.%.z :+", " z %.z %.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.z %.z :+", " z z %.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.z z :+", " z z z z z z z z z z z z z z z z z z z z z z ", ":+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+ ", ":+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+ "}; xpn-1.2.6/pixmaps/receive_bodies.xpm0000644000175000017500000000561711141275756015653 0ustar antant/* XPM */ static char * receive_headers_xpm[] = { "24 24 103 2", " c None", ". c #000000", "+ c #E2E2E2", "@ c #F2F2F2", "# c #F3F3F3", "$ c #F4F4F4", "% c #F5F5F5", "& c #F6F6F6", "* c #F7F7F7", "= c #DBDBDB", "- c #F0F0F0", "; c #E0E0E0", "> c #E1E1E1", ", c #E3E3E3", "' c #E4E4E4", ") c #E5E5E5", "! c #E6E6E6", "~ c #E7E7E7", "{ c #E8E8E8", "] c #E9E9E9", "^ c #EAEAEA", "/ c #EBEBEB", "( c #ECECEC", "_ c #EDEDED", ": c #EEEEEE", "< c #EFEFEF", "[ c #868686", "} c #878787", "| c #888888", "1 c #898989", "2 c #8A8A8A", "3 c #8B8B8B", "4 c #8C8C8C", "5 c #8D8D8D", "6 c #8E8E8E", "7 c #F1F1F1", "8 c #8F8F8F", "9 c #909090", "0 c #858585", "a c #C1D6BD", "b c #AEC5A8", "c c #A6BFA0", "d c #778E6F", "e c #6B8661", "f c #6C8562", "g c #65815C", "h c #919191", "i c #929292", "j c #DDDDDD", "k c #BDD3B8", "l c #AEC8AD", "m c #ABC7AA", "n c #698D60", "o c #5B7950", "p c #506B46", "q c #F8F8F8", "r c #838383", "s c #BFD4BB", "t c #ABC7A8", "u c #A8C6A5", "v c #6B9063", "w c #939393", "x c #F9F9F9", "y c #DEDEDE", "z c #C2D7BE", "A c #A7C5A4", "B c #FAFAFA", "C c #848484", "D c #959595", "E c #FBFBFB", "F c #FCFCFC", "G c #AAC6A7", "H c #A9C7A6", "I c #FDFDFD", "J c #FEFEFE", "K c #DADADA", "L c #8CA782", "M c #B1CDAE", "N c #B4CEB1", "O c #B0CAAD", "P c #AAC7A8", "Q c #ACC8A9", "R c #445B2C", "S c #FFFFFF", "T c #7A7A7A", "U c #77A16E", "V c #B2CBB0", "W c #ADC8AD", "X c #818181", "Y c #DFDFDF", "Z c #CDCDCD", "` c #709867", " . c #A8C7A8", ".. c #D6D6D6", "+. c #C9C9C9", "@. c #CFCFCF", "#. c #A5C4A3", "$. c #AFC8AD", "%. c #BDBDBD", "&. c #0F1308", "*. c #7F9F76", "=. c #A4C3A2", "-. c #6B9060", " . . . . . . . . . . . . . . . . . . . . ", ". + @ @ @ @ # # # $ $ $ % % % & & * * $ = . ", ". - ; ; > + , ' ) ! ~ { { ] ^ / ( _ : < _ . ", ". @ > [ [ } } | 1 1 2 2 3 3 4 4 5 5 6 - 7 . ", ". @ + , , ' ) ! ~ { ] ^ / ( ( _ : < - 7 @ . ", ". # , } | | 1 1 2 2 3 4 4 5 5 5 6 8 8 @ # . ", ". # ' ) ! ~ ~ { ] ^ / ( _ : < < - 7 @ # $ . ", ". # ) 1 1 2 2 2 3 4 4 5 5 6 8 8 8 9 9 $ % . ", ". $ ! ~ { ] ) . . . . . . . . . : # $ % & . ", ". $ ~ 2 2 2 0 . a b c d e f g . 2 h i & * . ", ". % { ] ^ ] j . k l m n o o p . ) $ * * q . ", ". % ] 3 4 2 r . s t u v o o p . | h w q x . ", ". % ^ / ( / y . z t A v o o p . ! & x B B . ", ". & / 4 5 3 C . z t u v o o p . 1 i D E F . ", ". * _ ( ( / y . z G H v o o p . ! & x E I . ", ". * : . . . . . z u t v o o p . . . . . J . ", ". q - K . L M N O P Q v o o o p p R . ~ S . ", ". q 7 0 T . U Q V W P v o o o o R . X ( S . ", ". @ @ ( Y Z . ` P .t v o o o R . ..^ q ( . ", ". +._ * : > @.. ` #.$.v o o R . ..^ q _ %.. ", " . . . . . . . &.*.=.v o R . . . . . . . ", " . -.n R . ", " . R . ", " . "}; xpn-1.2.6/pixmaps/send_queued_art.xpm0000644000175000017500000000320011141275756016035 0ustar antant/* XPM */ static char * send_queued_art_xpm[] = { "24 24 62 1", " c None", ". c #000000", "+ c #C4D4E3", "@ c #2A435B", "# c #A6BED5", "$ c #3F6588", "% c #A3BCD4", "& c #AAC1D7", "* c #ABC2D8", "= c #29425A", "- c #B4B4B4", "; c #F8F8F8", "> c #EBEBEB", ", c #D9D9D9", "' c #AEC4D9", ") c #C2C2C2", "! c #CBCBCB", "~ c #E5E5E5", "{ c #BABABA", "] c #E9E9E9", "^ c #E4E4E4", "/ c #DDDDDD", "( c #BDBDBD", "_ c #CFCFCF", ": c #E6E6E6", "< c #989898", "[ c #828282", "} c #7F7F7F", "| c #6892B9", "1 c #2D4760", "2 c #C0C0C0", "3 c #787878", "4 c #B1B1B1", "5 c #E7E7E7", "6 c #636363", "7 c #5A5A5A", "8 c #6B6B6B", "9 c #E8E8E8", "0 c #B3B3B3", "a c #FFFFFF", "b c #F2F2F2", "c c #E0E0E0", "d c #C8C8C8", "e c #D1D1D1", "f c #D6D6D6", "g c #818181", "h c #FAFAFA", "i c #E3E3E3", "j c #A7A7A7", "k c #8F8F8F", "l c #8C8C8C", "m c #D3D3D3", "n c #848484", "o c #C6C6C6", "p c #808080", "q c #FDFDFD", "r c #D5D5D5", "s c #EFEFEF", "t c #6D6D6D", "u c #767676", "v c #F5F5F5", "w c #C3C3C3", " .. ", " .+@. ", " .+#$@. ", " .+%&$$@. ", " ......*=..... ", " .-;>,.'=.)!~{... ", " .;]^/.%=.(_~:.+@. ", " .;<[}.|1.234.+#$@. ", " .;]]5....),.+%&$$@. ", " .;67]8[-9.....*=..... ", " .;]]]]]].0abc.'=.deaf. ", " .;<[[][g.aahb.%=._iaa. ", " .;]]]]]9.ajkl.|1.mnoa. ", " .;677]8p.aaaq....rsaa. ", " .;]]]]]5.at6aukoaokaa. ", " .;<[[][g.aaaaaaaaaaaa. ", " .v]]]]]9.ajkkakkoa c #E1E1E1", ", c #E3E3E3", "' c #E4E4E4", ") c #E5E5E5", "! c #E6E6E6", "~ c #E7E7E7", "{ c #E8E8E8", "] c #E9E9E9", "^ c #EAEAEA", "/ c #EBEBEB", "( c #ECECEC", "_ c #EDEDED", ": c #EEEEEE", "< c #EFEFEF", "[ c #868686", "} c #878787", "| c #888888", "1 c #898989", "2 c #8A8A8A", "3 c #8B8B8B", "4 c #8C8C8C", "5 c #8D8D8D", "6 c #8E8E8E", "7 c #F1F1F1", "8 c #8F8F8F", "9 c #909090", "0 c #919191", "a c #929292", "b c #F8F8F8", "c c #939393", "d c #F9F9F9", "e c #FAFAFA", "f c #949494", "g c #959595", "h c #FBFBFB", "i c #FCFCFC", "j c #FDFDFD", "k c #969696", "l c #FEFEFE", "m c #FFFFFF", "n c #979797", "o c #989898", "p c #C9C9C9", "q c #BDBDBD", " .................... ", ".+@@@@###$$$%%%&&**$=. ", ".-;;>+,')!~{{]^/(_:<_. ", ".@>[[}}|11223344556-7. ", ".@+,,')!~{]^/((_:<-7@. ", ".#,}||1122344555688@#. ", ".#')!~~{]^/(_:<<-7@#$. ", ".#)1122234455688899$%. ", ".$!~{]^^/(_:<-7@##$%&. ", ".$~22344455688990aa&*. ", ".%{]^/(_::<-7@#$%&**b. ", ".%]344556888990aaccbd. ", ".%^/(_:<-7@@#$%&*bdee. ", ".&/4556889900aaccfghi. ", ".*__:<-7@#$%%&*bdehij. ", ".*:6688990aacccfggkjl. ", ".b-7@@#$%&*bdehhijlmm. ", ".b79900aaccfggkkknomm. ", ".@@#$%&&*bdehijlmmmm(. ", ".p_b%&*bbdehijlmmmm:q. ", " .................... ", " ", " ", " "}; xpn-1.2.6/pixmaps/groups.xpm0000644000175000017500000000776611141275756014232 0ustar antant/* XPM */ static char * groups_xpm[] = { "24 24 174 2", " c None", ". c #000000", "+ c #FDFDFD", "@ c #F5F5F5", "# c #F6F6F6", "$ c #D0D0D0", "% c #C1C1C1", "& c #C3C3C3", "* c #C6C6C6", "= c #C8C8C8", "- c #8D8D8D", "; c #CACACA", "> c #919191", ", c #EFEFEF", "' c #878787", ") c #8A8A8A", "! c #5C5C5C", "~ c #F8F8F8", "{ c #EAEAEA", "] c #CCCCCC", "^ c #CECECE", "/ c #979797", "( c #CDCDCD", "_ c #A1A1A1", ": c #090600", "< c #A3A3A3", "[ c #C5C5C5", "} c #C4C4C4", "| c #D1D1D1", "1 c #D2D2D1", "2 c #D2D2D2", "3 c #9A9A9A", "4 c #E8E8E8", "5 c #949494", "6 c #939393", "7 c #574F4F", "8 c #FDFDFC", "9 c #777777", "0 c #7E7E7E", "a c #9D9D9D", "b c #6B6B6B", "c c #F1F1F1", "d c #ECECEC", "e c #CFCFCF", "f c #575050", "g c #FDFAF8", "h c #A5A5A5", "i c #B9B9B9", "j c #EEEEEE", "k c #EDEDED", "l c #D5D5D5", "m c #BABABA", "n c #6D6767", "o c #F9F1EA", "p c #9E9E9E", "q c #B5B5B5", "r c #D9D9D9", "s c #D7D7D7", "t c #BCBCBC", "u c #625C5B", "v c #F9EEE4", "w c #4F4D4A", "x c #646464", "y c #747474", "z c #D6D6D5", "A c #DFDFDF", "B c #A0A0A0", "C c #615C5B", "D c #F9F0E4", "E c #746C67", "F c #FEFDFC", "G c #FFFEFD", "H c #131210", "I c #636363", "J c #7C7C7C", "K c #F3F2F2", "L c #98948F", "M c #F9EFE3", "N c #A09489", "O c #FEFDFD", "P c #766D68", "Q c #736961", "R c #A3A3A2", "S c #A6A6A6", "T c #DBDBDB", "U c #C7C7C7", "V c #E8E5E2", "W c #97938E", "X c #F6E9D8", "Y c #84817A", "Z c #FBF3EA", "` c #908C86", " . c #F1EDE7", ".. c #7B7975", "+. c #878786", "@. c #070000", "#. c #FAFAFA", "$. c #DDDDDD", "%. c #E2DFDC", "&. c #A8A199", "*. c #F0E0CE", "=. c #C8BFB4", "-. c #D5CCBF", ";. c #DFD7CD", ">. c #DAD3C9", ",. c #DDCFC4", "'. c #928C84", "). c #A8A8A8", "!. c #959595", "~. c #040000", "{. c #D9D5D2", "]. c #D9CABB", "^. c #D7C8B8", "/. c #DECFBF", "(. c #D8C9B9", "_. c #E3D3C2", ":. c #C9BBAC", "<. c #D9CEC2", "[. c #7F766D", "}. c #909090", "|. c #D3D3D3", "1. c #060100", "2. c #C0BDBA", "3. c #8C8782", "4. c #C2B5A7", "5. c #BFB4A6", "6. c #B8AB9D", "7. c #BAAD9E", "8. c #BEB0A2", "9. c #948A7F", "0. c #716860", "a. c #E2E2E2", "b. c #A9A9A8", "c. c #332C2B", "d. c #5D5954", "e. c #79736C", "f. c #958C80", "g. c #8D8379", "h. c #988D82", "i. c #706760", "j. c #787878", "k. c #E4E4E4", "l. c #C2C2C2", "m. c #201A1A", "n. c #57514F", "o. c #625C59", "p. c #625A53", "q. c #6B625A", "r. c #585251", "s. c #696764", "t. c #080000", "u. c #989898", "v. c #B0B0B0", "w. c #AFAFAF", "x. c #999999", "y. c #9D9897", "z. c #050000", "A. c #0C0303", "B. c #080100", "C. c #030000", "D. c #282523", "E. c #5A5A5A", "F. c #868686", "G. c #ECE4E2", "H. c #DED7D5", "I. c #D8D1D0", "J. c #E0DBD7", "K. c #E9E6E3", "L. c #FCFBFA", "M. c #030500", "N. c #0B0505", "O. c #14100F", "P. c #090806", "Q. c #000100", " ", " . . . . . . . . . . . . . . . . . . . . ", " . + @ @ @ @ @ @ @ # # # # # # # # # $ . ", " . @ % % % & & & & * * * * * = = = = - . ", " . # & & & * * * * = = = = = ; ; ; ; > . ", " . , ' ' ' ) ) ) ) - - - - - > > > > ! . ", " . ~ { { { { { { { { { { { { { { { { ; . ", " . # ; ; ; ] ] ] ] ] ^ ^ ^ ^ $ $ $ $ / . ", " . # ] ] ] ( ^ ^ ^ _ : < [ } | 1 | 2 3 . ", " . 4 5 5 5 / / / 6 7 8 . 9 0 - a a a b . ", " . ~ c d d d d d e f g . h i $ j j k * . ", " . ~ 2 2 2 2 l l m n o . > p q r r r < . ", " . ~ l l l l s s t u v w . x . y p z < . ", " . A B B B B < 9 . C D E F . G H . I J . ", " . ~ @ , , , j . K L M N O P F Q R . S . ", " . ~ T T T T U . V W X Y Z ` ...+.@.< . ", " . #.$.$.$.$.& . %.&.*.=.-.;.>.,.'.@.p . ", " . { ).).).).!.~.{.].^./.(._.:.<.[.@.}.. ", " . #.@ c c c |.1.2.3.4.5.6.7.8.9.0.@.] . ", " . #.a.a.a.a.l b.c.d.e.f.g.9.h.i.. j.q . ", " . #.a.a.a.a.k.l.j.m.n.o.p.q.r.s.t.u.q . ", " . a.v.v.v.v.v.w.x.y.z.A.t.B.C.D.E.F.m . ", " . . . . . . . . . ~.G.H.I.J.K.L.M.. . . ", " ~.N.z.O.C.P.. Q. "}; xpn-1.2.6/pixmaps/xpn.xpm0000644000175000017500000001204311141275756013500 0ustar antant/* XPM */ static char * XPN_xpm[] = { "32 32 183 2", " c None", ". c #8D8D8D", "+ c #5D5D5D", "@ c #909090", "# c #F2F2F2", "$ c #F1F1F1", "% c #F0F0F0", "& c #EFEFEF", "* c #EDEDED", "= c #EAEAEA", "- c #E7E7E7", "; c #DDDDDD", "> c #D6D6D6", ", c #D1D1D1", "' c #C6C6C6", ") c #515151", "! c #EEEEEE", "~ c #EBEBEB", "{ c #E8E8E8", "] c #E2E2E2", "^ c #D5D5D5", "/ c #BEBEBE", "( c #545454", "_ c #575757", ": c #6B6B6B", "< c #4F4F4F", "[ c #DEDEDE", "} c #E1E1E1", "| c #D8D8D8", "1 c #D0D0D0", "2 c #555555", "3 c #777777", "4 c #434343", "5 c #DFDFDF", "6 c #DCDCDC", "7 c #D7D7D7", "8 c #C1C1C1", "9 c #767676", "0 c #858585", "a c #454545", "b c #DADADA", "c c #C0C0C0", "d c #737373", "e c #848484", "f c #464646", "g c #D9D9D9", "h c #D4D4D4", "i c #CCCCCC", "j c #BCBCBC", "k c #C8C8C8", "l c #BDBDBD", "m c #727272", "n c #FBFBFB", "o c #FAFAFA", "p c #F9F9F9", "q c #F7F7F7", "r c #F6F6F6", "s c #F4F4F4", "t c #ECECEC", "u c #E9E9E9", "v c #E5E5E5", "w c #CECECE", "x c #C7C7C7", "y c #6F6F6F", "z c #828282", "A c #999999", "B c #6D6D6D", "C c #838383", "D c #F5F5F5", "E c #F3F3F3", "F c #E6E6E6", "G c #E3E3E3", "H c #DBDBDB", "I c #CFCFCF", "J c #C3C3C3", "K c #BBBBBB", "L c #F8F8F8", "M c #878787", "N c #2C2C2C", "O c #000000", "P c #B2B2B2", "Q c #6A6A6A", "R c #747474", "S c #818181", "T c #8A8A8A", "U c #8F8F8F", "V c #D3D3D3", "W c #C9C9C9", "X c #C2C2C2", "Y c #BABABA", "Z c #797979", "` c #0A0A0A", " . c #222222", ".. c #2D2D2D", "+. c #7B7B7B", "@. c #919191", "#. c #A1A1A1", "$. c #7A7A7A", "%. c #949494", "&. c #696969", "*. c #BFBFBF", "=. c #7E7E7E", "-. c #9D9D9D", ";. c #0B0B0B", ">. c #9E9E9E", ",. c #898989", "'. c #9A9A9A", "). c #C5C5C5", "!. c #B8B8B8", "~. c #E4E4E4", "{. c #8B8B8B", "]. c #717171", "^. c #686868", "/. c #9F9F9F", "(. c #B5B5B5", "_. c #7F7F7F", ":. c #757575", "<. c #A4A4A4", "[. c #C4C4C4", "}. c #E0E0E0", "|. c #AAAAAA", "1. c #B9B9B9", "2. c #B7B7B7", "3. c #B3B3B3", "4. c #676767", "5. c #7D7D7D", "6. c #D2D2D2", "7. c #CBCBCB", "8. c #B1B1B1", "9. c #AFAFAF", "0. c #666666", "a. c #7C7C7C", "b. c #4E4E4E", "c. c #B6B6B6", "d. c #B0B0B0", "e. c #AEAEAE", "f. c #646464", "g. c #2F2F2F", "h. c #ADADAD", "i. c #ABABAB", "j. c #616161", "k. c #CDCDCD", "l. c #CACACA", "m. c #ACACAC", "n. c #A9A9A9", "o. c #606060", "p. c #787878", "q. c #6C6C6C", "r. c #B4B4B4", "s. c #2B2B2B", "t. c #9B9B9B", "u. c #A7A7A7", "v. c #A6A6A6", "w. c #5E5E5E", "x. c #252525", "y. c #969696", "z. c #5B5B5B", "A. c #A0A0A0", "B. c #9C9C9C", "C. c #A5A5A5", "D. c #979797", "E. c #595959", "F. c #6E6E6E", "G. c #A2A2A2", "H. c #989898", "I. c #565656", "J. c #A3A3A3", "K. c #959595", "L. c #939393", "M. c #5F5F5F", "N. c #5A5A5A", "O. c #474747", "P. c #707070", "Q. c #656565", "R. c #636363", "S. c #626262", "T. c #505050", "U. c #4C4C4C", "V. c #414141", "W. c #3E3E3E", "X. c #3B3B3B", "Y. c #3C3C3C", "Z. c #4A4A4A", " ", ". . . . . . . . . . . . . . . . . . . . . . . . . . . . + ", "@ # # # # # # # # # $ % & * = # # # $ % & * = - ; > , ' ) ", "@ # ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ~ { ] ; ^ / ( _ : < ", "@ # ! ! ! ! ! ! ( ! ! ( ! ( ( ( ( ! ( ( ! [ ( } ; | 1 / 2 3 . 4 ", "@ # ! ! ! ! ! ! ( ( ! ( ! ( ! ! ( ! ( ( ( [ ( 5 6 7 1 8 2 9 0 a ", "@ # ! ! ! ! ! ! ! ( ( ! ! ( ( ( ( ! ( ! ( [ ( [ b > 1 c 2 d e f ", "@ $ ! ! ! ! ! ! ( ! ( ( ! ( ! ! ! ! ( ! ( ( ( ; g h i j 2 d 0 f ", "@ $ ! ! ! ! ! ! ( ! ! ( ! ( ! ! ! ! ( ! [ ( ( b 7 , k l 2 m 0 f ", "@ $ n n o o p ! q r s s ! # ! ! t u v ] [ [ 6 7 ^ w x / 2 y z f ", "@ % n A A A A A A A A A A A A A A A A A A A A A A i ' / 2 B C f ", "@ % o p q q D s E # $ % ! ! ~ = u F G 5 H H | ^ I k J K 2 : C a ", "@ * L q M N a = c O . P t Q y R S S e T U g > V w W X Y 2 : C a ", "@ = r D Z ` } Q .w ..C = y +.@.#.. $.U %.^ ( ( ( k 8 Y 2 &.S f ", "@ - s E *.B & O =.-.( ;.u R @ >.,.m 9 %.'.V , i W ).c !.2 &.S f ", "@ ~.# $ % & * * ~ = u { - $.U {.].^.].'./., ( ( ( 8 l (.2 &.S f ", "@ } % ! ( ( ( ( ( ( ( ( v _.e e _.:.0 /.<.I i x [./ Y (.2 &._.f ", "@ [ ! t t = u { - F v G }.e T U %.'./.<.|.i ( ( ( 1.2.3.2 4.5.f ", "@ H t = ( ( ( ( ( ( ( ( ; g | V 6.1 1 7.x x [.c K !.8.9.2 0.5.f ", "@ b = { { F F ~.G ] } 6 H a.O b.1 O w 3 ).( ( ( ( c.d.e.2 f.a.f ", "@ g { - ( ( ( ( ( ( ( ( | g.P C O 3 k O X l j Y (.P h.i.2 j.Z f ", "@ 7 F G } ] ] 5 ; b g > V 1 k.l.k ).J / K ( ( ( ( 9.m.n.2 o.p.f ", "@ h ; ; O q.j.r.s.5.t.1 k.( ( ( ( ( ( ( (.(.P d.i.u.v.<.2 w.9 f ", "@ , }.[ [ 5 5 H g h V 1 k.k ).8 j 1.!.!.r.( ( ( ( u.v.<.2 w.:.f ", "@ w [ H ( ( ( ( ( ( ( ( k 3 O l x.q.y.8.e.9.h.|.u.v.#./.2 z.].f ", "@ 7.| | 7 g | V 1 i 7.k ).J *.Y 1.r.8.9.|.( ( ( ( A.B.A 2 z.].f ", "@ k h 6.( ( ( ( ( ( ( ( 8 ( ( ( ( ( ( n.v.v.C.#./.'.A D.2 E.F.f ", "@ )., I k.1 w l.x [.J c j Y c.d.e.m.n.C.G.G.A.-.A H.D.%.2 I.Q f ", "@ c W k x x ).X *.l K !.(.3.9.m.|.u.<.J.>.>.-.'.D.K.L.L.2 _ : f ", "@ -.D.@ T e a.9 y 4.M.N.I.I.2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 z.q.O.", " + y $.P.B B q.Q ^.4.0.Q.R.S.o.w.+ z.N.E._ _ I.2 I.E.o.: a ", " q.].&.R.w.N.2 T.U.f V.W.X.X.X.X.X.X.X.X.X.X.X.X.Y.W.V.a Z."}; xpn-1.2.6/pixmaps/outbox.xpm0000644000175000017500000000334011141275756014213 0ustar antant/* XPM */ static char * outbox_xpm[] = { "24 24 69 1", " c None", ". c #000000", "+ c #E66040", "@ c #EE937E", "# c #E55E3F", "$ c #E1431F", "% c #EC8770", "& c #F0A08E", "* c #F3B7A9", "= c #EF9985", "- c #E76749", "; c #ED8C75", "> c #F5BEB1", ", c #F3B4A5", "' c #F4B8AA", ") c #F1A593", "! c #E55B3B", "~ c #E45534", "{ c #F4BDB0", "] c #F4BAAC", "^ c #EF9C89", "/ c #E34E2B", "( c #C0391A", "_ c #8A2912", ": c #3E3E3C", "< c #D4D3D2", "[ c #DB411D", "} c #F1A999", "| c #D23E1C", "1 c #812611", "2 c #C7C7C5", "3 c #ACABA8", "4 c #6A6966", "5 c #E9775D", "6 c #CECDCC", "7 c #A93217", "8 c #9B9A97", "9 c #494846", "0 c #9A9996", "a c #BBBBB9", "b c #747370", "c c #A5A4A1", "d c #AAA9A6", "e c #686765", "f c #7D7C79", "g c #686764", "h c #9C9B98", "i c #999895", "j c #ABAAA7", "k c #A9A8A5", "l c #AF3417", "m c #E55D3D", "n c #C5C5C3", "o c #8D8C89", "p c #626260", "q c #B2B1AE", "r c #A7A6A3", "s c #B4B4B2", "t c #C3C3C1", "u c #92918E", "v c #D1D0CF", "w c #373735", "x c #CACAC8", "y c #A8A7A4", "z c #CCCCCA", "A c #52514E", "B c #C8C8C6", "C c #B5B5B3", "D c #7E7D7A", " . ", " .. ", " .+. ", " ....@#. ", " .$%&*=@-. ", " .;>,')@@@!. ", " .~{]*^@@@@@-.", " ...@>/((((((_. ", " .:<.[}|((((((1. ", " ..234.5+(_...(1. ", " ..63444.@(7...._. ", " ..6344448.@(.90a.. ", ".634444bcd.#$.eff.a.. ", ".gh34bijkk.lm.iffff0a. ", ".ggghniikdo..pddiffffq. ", ".ggggghniikdkkkdddiffr. ", " ..ggggghniikdkkdddsta. ", " ..ggggghnurdkksvvw. ", " ..gggggxrdyzvA.. ", " ...gggB3qCA.. ", " ...gDv... ", " ..... ", " ", " "}; xpn-1.2.6/pixmaps/art_mark.xpm0000644000175000017500000000230111141275756014467 0ustar antant/* XPM */ static char * art_mark_xpm[] = { "18 16 54 1", " c None", ". c #000000", "+ c #636E61", "@ c #647260", "# c #495745", "$ c #3F4F39", "% c #354430", "& c #030303", "* c #FFE8B7", "= c #A7BCA4", "- c #ACC7AA", "; c #73946B", "> c #5D7A52", ", c #4C6543", "' c #FEE7B7", ") c #A8BCA4", "! c #A9C6A6", "~ c #72956A", "{ c #5B7950", "] c #4A6341", "^ c #FEE8B7", "/ c #050505", "( c #A9BDA5", "_ c #E5D1A7", ": c #A6997F", "< c #A2967B", "[ c #A8BDA5", "} c #AAC7A7", "| c #72956B", "1 c #A59676", "2 c #A5987B", "3 c #E2CFA7", "4 c #E3D0A7", "5 c #ADC5AA", "6 c #ABC7A8", "7 c #73956B", "8 c #54704A", "9 c #E0CEA6", "0 c #999999", "a c #83A27E", "b c #ADC8AB", "c c #ABC7AA", "d c #5A784F", "e c #475F38", "f c #88A984", "g c #AAC7A8", "h c #4C663D", "i c #E6D1A5", "j c #8CAA87", "k c #709368", "l c #4D663D", "m c #E5D0A4", "n c #E0CBA0", "o c #DFCAA0", " ", " ", " ", " ....... ", ".....+@#$%.&... ", "..**.=-;>,.**.. ", ".*.'.)!~{].*.*. ", ".^^/.(!~{]..^^. ", "._:<.[}|{].123. ", ".4...567{8...9.0 ", ".'..abc|{de..'.000", ".**..fg7{h..**.000", ".*.*i.jkl.m*.*.00 ", "..***n...o***..00 ", "...............0 ", " 000000000000000 "}; xpn-1.2.6/pixmaps/raise_score.xpm0000644000175000017500000000207411141275756015174 0ustar antant/* XPM */ static char * exand_xpm[] = { "24 24 24 1", " c None", ". c #000000", "+ c #D0D9E3", "@ c #B9C6D5", "# c #909DAC", "$ c #7590AE", "% c #5E738B", "& c #5A6F86", "* c #ADBCCE", "= c #9DB0C5", "- c #93A6BD", "; c #839BB5", "> c #A5B6C9", ", c #B8C5D4", "' c #B6C4D3", ") c #93A0AD", "! c #C4CEDC", "~ c #617891", "{ c #7589A0", "] c #6883A1", "^ c #869DB8", "/ c #A2B3C7", "( c #A5B2C0", "_ c #4E6074", " ", " ", " ", " ... ", " .+@#. ", " .@$%. ", " .@$%. ", " .@$%. ", " .@$%. ", " ......@$&...... ", " .*=====-$;>,'''). ", " .!$$$$$$$$$$$$$~. ", " .{%%%%%$$]%%%%%%. ", " ......^$%....... ", " ./$%. ", " .'$%. ", " .'$%. ", " .'$%. ", " .(%_. ", " .... ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/set_score.xpm0000644000175000017500000000155611141275756014670 0ustar antant/* XPM */ static char * set_score_xpm[] = { "24 24 10 1", " c None", ". c #000000", "+ c #ADBCCE", "@ c #B6C4D3", "# c #93A0AD", "$ c #C4CEDC", "% c #7590AE", "& c #617891", "* c #7589A0", "= c #5E738B", " ", " ", " ", " ", " ", " ", " ............... ", " .+@@@@@@@@@@@@@#. ", " .$%%%%%%%%%%%%%&. ", " .*==============. ", " ................ ", " ", " ", " ............... ", " .+@@@@@@@@@@@@@#. ", " .$%%%%%%%%%%%%%&. ", " .*==============. ", " ................ ", " ", " ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/mark_multiple.xpm0000644000175000017500000000247511141275756015550 0ustar antant/* XPM */ static char * mark_multiple_xpm[] = { "18 18 59 1", " c None", ". c #000000", "+ c #FFE8B7", "@ c #302B22", "# c #201D16", "$ c #636E61", "% c #647260", "& c #495745", "* c #3F4F39", "= c #354430", "- c #A7BCA4", "; c #ACC7AA", "> c #73946B", ", c #5D7A52", "' c #4C6543", ") c #1F1C16", "! c #A8BCA4", "~ c #A9C6A6", "{ c #72956A", "] c #5B7950", "^ c #4A6341", "/ c #403A2D", "( c #020202", "_ c #A9BDA5", ": c #BFAD89", "< c #FDE6B5", "[ c #91856F", "} c #A2967B", "| c #A8BDA5", "1 c #AAC7A7", "2 c #72956B", "3 c #B5A582", "4 c #D7C49C", "5 c #FBE4B4", "6 c #ADC5AA", "7 c #ABC7A8", "8 c #73956B", "9 c #54704A", "0 c #100E0B", "a c #83A27E", "b c #ADC8AB", "c c #ABC7AA", "d c #5A784F", "e c #475F38", "f c #9F9072", "g c #88A984", "h c #AAC7A8", "i c #4C663D", "j c #F5DFB0", "k c #8CAA87", "l c #709368", "m c #4D663D", "n c #0E0D0A", "o c #544C3C", "p c #0D0C0A", "q c #8F8266", "r c #4C4536", "s c #EBD9B1", "t c #F2DEB3", " ", " ", "............... ", "..++++@.....#.. ", ".+.....$%&*=..... ", ".+..++.-;>,'.++.. ", ".+.+.).!~{]^./....", ".+.+.(._~{]^.:+++.", ".+.<[}.|12]^.34+..", ".+.5...678]9..0.+.", ".+.+..abc2]de0.++.", "...+.f.gh8]i#.+++.", "...+.+j.klm/n+.++.", " ...++o...p+++.+.", " ...+.+q.r+++++..", " ..+++st++++++.", " ..............", " "}; xpn-1.2.6/pixmaps/art_unwatchignore.xpm0000644000175000017500000000067311141275756016424 0ustar antant/* XPM */ static char * art_unread_xpm[] = { "18 16 1 1", " c None", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/next_unread.xpm0000644000175000017500000000253711141275756015216 0ustar antant/* XPM */ static char * next_unread_xpm[] = { "24 24 43 1", " c None", ". c #000000", "+ c #8CA782", "@ c #B1CDAE", "# c #77A16E", "$ c #B4CEB1", "% c #ACC8A9", "& c #709867", "* c #C1D6BD", "= c #BDD3B8", "- c #BFD4BB", "; c #C2D7BE", "> c #B0CAAD", ", c #B2CBB0", "' c #AAC7A8", ") c #0F1308", "! c #AEC5A8", "~ c #AEC8AD", "{ c #ABC7A8", "] c #AAC6A7", "^ c #A8C6A5", "/ c #ADC8AD", "( c #A8C7A8", "_ c #A5C4A3", ": c #7F9F76", "< c #A6BFA0", "[ c #ABC7AA", "} c #A7C5A4", "| c #A9C7A6", "1 c #AFC8AD", "2 c #A4C3A2", "3 c #6B9060", "4 c #778E6F", "5 c #698D60", "6 c #6B9063", "7 c #445B2C", "8 c #6B8661", "9 c #5B7950", "0 c #FFE8B7", "a c #6C8562", "b c #65815C", "c c #506B46", "d c #999999", " ", " ", " ", " . ", " .. ", " .+. ", " .@#. ", " ........$%&. ", " .*=-;;;;>,'&) ", " .!~{{{]^'/(_:. ", " .<[^}^|{%'{123. ", " .45666666666657....... ", " .8999999999997.00000.. ", " .a99999999997.00000.0. ", " .bcccccc9997.00000.00. ", " ........c97.00000.000. ", " .c7.0.000.0000.d", " .7.0.0.0.0.000.d", " ..0.000.000.00.d", " .0.000000000.0.d", " ..00000000000..d", " ...............d", " ", " "}; xpn-1.2.6/pixmaps/reply.xpm0000644000175000017500000000754611141275756014042 0ustar antant/* XPM */ static char * reply3_xpm[] = { "24 24 165 2", " c None", ". c #000000", "+ c #FFFFFF", "@ c #FBE73B", "# c #F2B64D", "$ c #FCEB3D", "% c #F7B544", "& c #5D502C", "* c #F9F9F8", "= c #FCE93B", "- c #F7B545", "; c #6C5F34", "> c #EFEFEF", ", c #FAE43A", "' c #F4B244", ") c #605737", "! c #222222", "~ c #F9DF39", "{ c #F3AF42", "] c #625637", "^ c #F7F7F7", "/ c #F9DC38", "( c #EFB44D", "_ c #665A32", ": c #F8D837", "< c #F0A93F", "[ c #655930", "} c #E1E1E1", "| c #C1C1C1", "1 c #CBCBCB", "2 c #FAFAFA", "3 c #F6D236", "4 c #EDA43E", "5 c #5C5130", "6 c #808000", "7 c #FCFCFC", "8 c #ADADAD", "9 c #696969", "0 c #898989", "a c #DDDDDD", "b c #D7AE74", "c c #61562F", "d c #F8F8F8", "e c #B9B9B9", "f c #363932", "g c #545E46", "h c #2B2E26", "i c #4F4115", "j c #1A1A1A", "k c #E7E7E7", "l c #808080", "m c #FFE8B7", "n c #535353", "o c #2D2F2A", "p c #6E7C5D", "q c #566049", "r c #B8B8B7", "s c #0B0B0B", "t c #0D0D0D", "u c #666666", "v c #2B3024", "w c #72805F", "x c #5B5B5B", "y c #FBFBFB", "z c #E3E3E3", "A c #F6F6F6", "B c #C0C0C0", "C c #F9E7C2", "D c #262626", "E c #7A8A64", "F c #627347", "G c #747474", "H c #BCBCBC", "I c #8D8D8D", "J c #ACACAC", "K c #D1D1D1", "L c #CCCCCC", "M c #030303", "N c #E9D7AE", "O c #161616", "P c #A2B783", "Q c #586C33", "R c #282828", "S c #656565", "T c #797979", "U c #0A0A0A", "V c #545454", "W c #7F7F7F", "X c #AFA796", "Y c #F9E8C3", "Z c #B0C78E", "` c #6B8637", " . c #374026", ".. c #8F8F8F", "+. c #C6C6C6", "@. c #0A0C05", "#. c #3F492B", "$. c #D4D4D4", "%. c #F2E5C8", "&. c #323232", "*. c #171717", "=. c #A5B98B", "-. c #8CA85B", ";. c #627B32", ">. c #252B19", ",. c #131313", "'. c #14190A", "). c #668034", "!. c #2C351B", "~. c #585858", "{. c #1C1E1A", "]. c #E0CFAB", "^. c #FBE9C3", "/. c #3E3E3E", "(. c #798668", "_. c #B4C896", ":. c #89A553", "<. c #7D9C42", "[. c #7C9B40", "}. c #283214", "|. c #929291", "1. c #FFE9BC", "2. c #F3DEB2", "3. c #757575", "4. c #B6C4A9", "5. c #BECFA4", "6. c #9DB672", "7. c #93AE63", "8. c #91AD5F", "9. c #819A57", "0. c #3F4733", "a. c #5F5F5F", "b. c #F6EEDE", "c. c #515250", "d. c #6E7867", "e. c #C9D7BC", "f. c #D1DEBF", "g. c #CADAB4", "h. c #BFD3A4", "i. c #BAD09D", "j. c #ACBD96", "k. c #5C6551", "l. c #878787", "m. c #FFEEC9", "n. c #C3C3C3", "o. c #5D5F5C", "p. c #6B7562", "q. c #AFBEA0", "r. c #C5D6B0", "s. c #CADAB5", "t. c #BCD1A0", "u. c #AFC198", "v. c #575D50", "w. c #878786", "x. c #292929", "y. c #232423", "z. c #20221E", "A. c #20231C", "B. c #3C4235", "C. c #AFC199", "D. c #595F53", "E. c #141413", "F. c #3D3D3D", "G. c #737373", "H. c #141514", " . . . . . . . . . . . . ", " . + + + + + + + + . . . @ # . ", " . + + + + + + + + . + . . $ % & . ", " . + . + . . . . + . + * . . = - ; . ", " . + + + + + + + + . > + . , ' ) . ", " . + . . . . . . + ! . . ~ { ] . ", " . + + + + + + + ^ + . / ( _ . ", " . + . . . . . + + . : < [ . . ", " . . + + + } | 1 2 . 3 4 5 . + . ", " . 6 . + . 7 8 9 0 a . b c . d + 6 . ", " . . . + + e f g h . i . j k + . . . l ", " . m . + n o p q r . . + s . + . m . l ", " . m m t u v w x y z A + + B . m m . l ", " . m m C D E F G H I J K L M m m m . l ", " . m m N O P Q R S T U V W X m m m . l ", " . m m Y D Z ` ...+.@.#.0 $.%.m m . l ", " . m m &.*.=.-.;.>.,.'.).!.~.{.].m . l ", " . m . ^./.(._.:.<.[.[.[.` }.|.{.1.. l ", " . . m 2.3.{.4.5.6.7.8.8.8.9.0.a.{.. l ", " . m m m b.c.d.e.f.g.h.i.i.j.k.l.m.. l ", " . . . . D n.o.p.q.r.s.t.u.v.w.{.. . l ", " l l l 9 x.y.z.A.B.C.D.E.F.G.l l l ", " H.{.. ", " {. "}; xpn-1.2.6/pixmaps/xpn-icon.png0000644000175000017500000000465311141275756014416 0ustar antantPNG  IHDR10sBIT|dtEXtSoftwarewww.inkscape.org< =IDATh՚{pU?{MBB GCxP[Pu>ڡv X20"QXQG[ LB?y{,ܙ{CI| X_?[DR"g p@ Dl(YB@` &_rϝua5VB/Xgywo;`E`"0}laPޱeߋJf}oL5Iaathd@Tpo'گC$eYm v1zW*hRā f }VVTV O麟Ĵ)/^}.ӭ0Ks\1{ԧUSr s ҙoX=mP1#CDuyoupy @Խ&0w %e71 0f45OTT}91N!e&r&SA\_ UI)% i!4i1 )G Hń´EvuIIgf lbQFWR U0Қ׏WD7bdž+{It~:c q.+b nFS4'֙4:Oo.#ip pϝT43;:,#%|dZd |dՏ[kgS)gղ!, +} GB!'߶`;-[Kg$=s>WxrLȵ&Ƙ- L 1W_'Jr:}+N6b/ n[93:BTVR`!(|KSE}SҾXASv a|f! w'X^{S6JI$C@Vg:KNN,đS.iBh#ywӭ # KjIu'ʶ~A\p5 jsr4@0k))V O Ne䖎p:-/ kfrxMIL0ȕ}1d9'BA%'b]Ť0Zb: \Gݼ}U>vub+N5V0! lJ&ƪB.3;HF  Y"$\υ "LNtO۪\2Ths YɍL"iDni햊I0x~/ǂ WvIv (W$R۱2гpeQ(dK8Y񀅱]@ jk$͹X`̟j=P6W驵)ӂ)kɺQO(?݂^Pq@zV~$>Nu!s 9>60zj' ;>&aۭSmd繏򳓤3)Tdg`/7 6fNb5BȩVW Phөc}lt9Jofƞn-0䜽NseLQ5W8Ls2Qr B=!97rAJ~Ke\LĖҺ}B{6eק0H|EV1!/`G .@|'@Aj0oɸpR"_.DgR.˅cۿ^pa3'z_rSSMX)<GJ|!79sfVuts_%; ` x O@^qei.dh#_2l a5teZ!> KGg=o4Բh5L484m@)ML(\O!j֞n!|xy K>7dS6BʀB'6Ơ}f,8C5kV`kdՠn{M,`YD2+1c0Z:EGlZe(jͷZtwiu=y@J{>.<@ lbQkLkNF.;ᣱw7||V2ZB)|\A.((0[E=5F)tŵq5yLJTR(_NF<#kzz#Ӛ)_vXcѼΈI F ouZ! ʉ0F>EG5LSRKRJ)j ېb),K"-iI 4A)R ,"G֡Sac4hrQmiG;J{Jn:Vզ6 7%rA lLL`B(4o(hJ`%,%ȬɐY) sk_Rsm}P F{hlMWy7%Z}]x+W%Xj鰻-CND,47o&!zqDL iKe{ *S- >l1ioڀyߒfpJ1\%,0݇]9DK2XYc(w| Bx]Zt`sJy4&]͑1 l ^G%NODZ,z8y1vNوX0JԞ.!ͬjׁ,~ue5y^}^m<.hI.L!@XX ˶aƥ k z Zd,fs? :7rW%WmiőQ a2Pp v .|7r<}(k`B BGQp}6;3IQ{A yf,[ǐrm_.֟QL,1)HłUc4kHdIa⌍'hv2k29VSGTA 5@\ x+[=ŋ)9$vM|nˮ;¾aO31\6λF.؂'YecHisΦkP%ŁJZԶվOx*x%Ef1&mͶ_{,Yu.=)2" \Œ,y\u] T2J"vS]xk h ]ѱ}-I2<iFՃS*\ƝV^y' *^Uh(NyƁMq0 8!|Kn^vFEJYzf}y:JGARe )n&Ng_)am,[):OݐLbHʴl}{)``gށѓ޿ӛheՒVnnSh]nAִ,_pfB0Ze ) jɒ!ӡhmʚY$t:¦ 70tjÕMsCCC AOCC^ 5nB+{ FB&( >Gs/.INIG5rGFA~ M74# /B+mPSat2Gsa|ʕ6Ap2 B;`* A:ڹ3l+|!_}HzGyk!s#%]=xd/ Gr W ;wDˋBx kʝ4_) ˤC^*Nӷ5z] s ;װ|[=EH iRO{`J4g+?/GYKiS*01O6oc&DF!+s@uMm44I-qv*|sB8!z:JN`'k"NZ Xh 0%r`pAs2ްaܽ{5Wb&FY8t=!hϗO!WU#&>N_@,(Ifׅ" 3ܩ5_X#b< )#""Tm|tRHHٱ2 O{Ts"-7׈R)f޾WIENDB`xpn-1.2.6/pixmaps/send_queue.xpm0000644000175000017500000000707211141275756015036 0ustar antant/* XPM */ static char * send_queue_xpm[] = { "24 24 146 2", " c None", ". c #3A3A3A", "+ c #505050", "@ c #524A39", "# c #38301E", "$ c #1C1915", "% c #3D3D3D", "& c #9E9E9E", "* c #D4D4D4", "= c #E6E6E6", "- c #C8BBA1", "; c #D9BC83", "> c #BA9F68", ", c #766645", "' c #1E1A14", ") c #4C4C4C", "! c #D7D7D7", "~ c #F3F3F3", "{ c #F5F5F5", "] c #DDDDDD", "^ c #2E291F", "/ c #DCB361", "( c #DEB666", "_ c #D6B36D", ": c #AD9360", "< c #26211A", "[ c #3C3C3C", "} c #F6F6F6", "| c #ECECEC", "1 c #E3E3E3", "2 c #363129", "3 c #D1AA5C", "4 c #DAB160", "5 c #D5AE5F", "6 c #D4B26E", "7 c #AE9461", "8 c #000000", "9 c #040404", "0 c #969696", "a c #EBEBEB", "b c #FAFAFA", "c c #FBFBFB", "d c #2E2A22", "e c #CAA45A", "f c #E4BA65", "g c #E2B864", "h c #CEA85B", "i c #D1B171", "j c #67583B", "k c #020202", "l c #FEFEFE", "m c #848484", "n c #D2D2D2", "o c #F4F4F4", "p c #F1F1F1", "q c #FDFDFD", "r c #E2E2E2", "s c #1F1D17", "t c #C7A158", "u c #E3B965", "v c #D8B160", "w c #D4AD60", "x c #A58F62", "y c #7A7975", "z c #E9E9E9", "A c #FFFFFF", "B c #707070", "C c #E5E5E5", "D c #E1E1E1", "E c #F9F9F9", "F c #AFAFAF", "G c #090908", "H c #A18347", "I c #E3B964", "J c #E1B864", "K c #D4AD5E", "L c #C39F56", "M c #C0AA7C", "N c #5E594E", "O c #DEDEDE", "P c #4A4A4A", "Q c #D0D0D0", "R c #5A5A5A", "S c #585858", "T c #585141", "U c #E2D0AC", "V c #DFCDAB", "W c #8D826C", "X c #4D473B", "Y c #C5BCA9", "Z c #56534E", "` c #6F6F6F", " . c #C3C3C3", ".. c #5B5B5B", "+. c #111111", "@. c #999999", "#. c #EDEDED", "$. c #C6C6C6", "%. c #212121", "&. c #D8D8D8", "*. c #FCFCFC", "=. c #C8C8C8", "-. c #EEEEEE", ";. c #F2F2F2", ">. c #E8E8E8", ",. c #989898", "'. c #2E2E2E", "). c #B7B7B7", "!. c #E7E7E7", "~. c #D9D9D9", "{. c #A4A4A4", "]. c #777777", "^. c #B4B4B4", "/. c #8E8E8E", "(. c #DCDCDC", "_. c #F0F0F0", ":. c #EFEFEF", "<. c #E4E4E4", "[. c #C4C4C4", "}. c #CBCBCB", "|. c #D3D3D3", "1. c #6D6D6D", "2. c #A2A2A2", "3. c #B8B8B8", "4. c #DFDFDF", "5. c #DBDBDB", "6. c #D5D5D5", "7. c #A5A5A5", "8. c #676767", "9. c #CECECE", "0. c #666666", "a. c #B6B6B6", "b. c #D6D6D6", "c. c #CACACA", "d. c #4D4D4D", "e. c #CCCCCC", "f. c #A3A3A3", "g. c #575757", "h. c #C0C0C0", "i. c #121212", "j. c #787878", "k. c #AAAAAA", "l. c #7B7B7B", "m. c #606060", "n. c #252525", "o. c #202020", " ", " . + @ # $ ", " % & * = - ; > , ' ", " ) ! ~ { ] ^ / ( _ : < ", " [ ! } | ~ 1 2 3 4 5 6 7 $ ", " 8 8 8 9 0 ~ a b c 1 d e f g h i j k 8 8 8 8 ", " 8 8 l m n o p b q r s t f u v w x y z q 8 8 ", " 8 A 8 B C D | E c F G H I J K L M N O 8 A 8 ", " 8 A c P Q R & o E S 8 T U V W X Y Z 8 c A 8 ", " 8 A c ` C p ~ { } ...+.@.#.| O $.%.&.c A 8 ", " 8 A *.m =.-.p ~ ~ ;.>.,.'.).!.~.{.].O c A 8 ", " 8 A l ^./.C (._._.:.<.| ).[.}.|.1.2.z q A 8 ", " 8 A A #.].3.1 !.z 4./.>.1 5.6.7.8.9.{ l A 8 ", " 8 A A *.5.0.a.9.b.c.d.&.e.c.f.g.h.a *.A A 8 ", " 8 A A A b ] i.j.k.$.$.[.f.1.8.8 !.b A A A 8 @.", " 8 A A A A 8 C F l.m.n.o.].2.9.a 8 A A A A 8 @.", " 8 A A A 8 A *.{ z O &.&.O z { *.A 8 A A A 8 @.", " 8 A A 8 A A A A l *.c c *.l A A A A 8 A A 8 @.", " 8 A 8 A A A A A A A A A A A A A A A A 8 A 8 @.", " 8 8 A A A A A A A A A A A A A A A A A A 8 8 @.", " 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 ", "@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@. ", "@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@.@. ", " "}; xpn-1.2.6/pixmaps/art_watch.xpm0000644000175000017500000000074011141275756014650 0ustar antant/* XPM */ static char * art_watch_xpm[] = { "16 16 7 1", " c None", ". c #000000", "+ c #9DB8D2", "@ c #FFFFFF", "# c #89A1B9", "$ c #859DB4", "% c #8199AF", " ", " ", " ", " ", " ", " . . ", " . . . .", " . . .", " ........... ", " .+@+. .+@+. ", " .#+$. .#+%. ", " ... ... ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/art_keep.xpm0000644000175000017500000000314411141275756014467 0ustar antant/* XPM */ static char * art_keep2_xpm[] = { "16 16 84 1", " c None", ". c #000000", "+ c #FEFEFE", "@ c #FDFDFD", "# c #E0E0E0", "$ c #C1C1C1", "% c #F1F1F1", "& c #C3C3C3", "* c #FBFBFB", "= c #A8A8A8", "- c #ADADAD", "; c #767676", "> c #5D5D5D", ", c #404040", "' c #0E0E0E", ") c #727272", "! c #F0F0F0", "~ c #E2E2E2", "{ c #858585", "] c #4B4B49", "^ c #161616", "/ c #965647", "( c #E1837D", "_ c #D07773", ": c #6A1F0E", "< c #1E0F0C", "[ c #2E140F", "} c #50413E", "| c #B0B0B0", "1 c #EFEFEF", "2 c #EEEEEE", "3 c #C5C5C5", "4 c #DC6D64", "5 c #DC6E64", "6 c #D64240", "7 c #A52E26", "8 c #531D15", "9 c #793430", "0 c #9C4C45", "a c #3E2722", "b c #EDEDED", "c c #ECECEC", "d c #C4C4C4", "e c #B74930", "f c #D02725", "g c #922821", "h c #310D05", "i c #6D160D", "j c #6F1C0E", "k c #230B06", "l c #33201B", "m c #59514F", "n c #A5A5A5", "o c #EBEBEB", "p c #D4483D", "q c #C43225", "r c #D02420", "s c #7B1811", "t c #431309", "u c #6D170D", "v c #3C1B12", "w c #EAEAEA", "x c #CE1C18", "y c #901210", "z c #170703", "A c #2E1009", "B c #4E332D", "C c #9F9F9F", "D c #E8E8E8", "E c #C0C0C0", "F c #6F6F6F", "G c #E9E9E9", "H c #E7E7E7", "I c #BFBFBF", "J c #E5E5E5", "K c #BEBEBE", "L c #E6E6E6", "M c #E4E4E4", "N c #BDBDBD", "O c #E3E3E3", "P c #BBBBBB", "Q c #CACACA", "R c #BCBCBC", "S c #A0A0A0", " ......... ", " .++++++@#$. ", " .+%%%%%%&*=. ", " .+%%%%%%-;>,. ", " ..')%%%%!~{]^. ", " /(_:<[}|11223. ", ".4567890a2bbcd. ", ".4efghijklmno&. ", ".pqrstujvowww$. ", " /xy.zABCDDDDE. ", " ..'FwGGDDDHHI. ", " .@DDDDDDDDJK. ", " .@HHLLLJJMMN. ", " .@LJJJMMOOOP. ", " .QNNNRRPPPPS. ", " ........... "}; xpn-1.2.6/pixmaps/part.xpm0000644000175000017500000000106611141275756013644 0ustar antant/* XPM */ static char * part_xpm[] = { "16 16 13 1", " c None", ". c #4B6983", "+ c #4F4F4F", "@ c #494949", "# c #4C4C4C", "$ c #505050", "% c #DADADA", "& c #FFFFFF", "* c #BDBDBD", "= c #A37A1F", "- c #D1940C", "; c #4D4D4D", "> c #A9872E", "................", ". .", ". +@@@@# .", ". $%&&&&%+ .", ". @&&&*+@@@@# .", ". @&&&$%&&&&%+ .", ". @&&&@&&&&&&@ .", ". @&&&@&&&&&&@ .", ". @&&&@&&&&&&@ .", ". @&&&@&&&&&&@ .", " +%&&@&&&&&&@ .", " =-@@@&&&&&&@ .", " --- +%&&&&%; .", "---- $@@@@; .", " --- .", " >- ..........."}; xpn-1.2.6/pixmaps/find.xpm0000644000175000017500000000330411141275756013613 0ustar antant/* XPM */ static char * search_xpm[] = { "24 23 69 1", " c None", ". c #AFAFAF", "+ c #9B9B9B", "@ c #9A9A9A", "# c #525252", "$ c #1E1E1E", "% c #030303", "& c #1C1C1C", "* c #4E4E4E", "= c #949494", "- c #989898", "; c #FAFAFA", "> c #D6D6D6", ", c #313131", "' c #262626", ") c #DDDDDD", "! c #F7F7F7", "~ c #CECECE", "{ c #464646", "] c #2B2B2B", "^ c #C7C7C7", "/ c #F2F2F2", "( c #F8F8F8", "_ c #F9F9F9", ": c #969696", "< c #C0C0C0", "[ c #828282", "} c #E1E1E1", "| c #000000", "1 c #B6B6B6", "2 c #868686", "3 c #F6F6F6", "4 c #6F6F6F", "5 c #E6E6E6", "6 c #303030", "7 c #D1D1D1", "8 c #FFFFFF", "9 c #ABABAB", "0 c #252525", "a c #9C9C9C", "b c #B5B5B5", "c c #050505", "d c #F5F5F5", "e c #040404", "f c #CACACA", "g c #E9E9E9", "h c #999999", "i c #F4F4F4", "j c #BFBFBF", "k c #020202", "l c #7A7A7A", "m c #8E8E8E", "n c #E0E0E0", "o c #D7D7D7", "p c #A4A4A4", "q c #686868", "r c #757575", "s c #858585", "t c #E8E8E8", "u c #E3E3E3", "v c #6D6D6D", "w c #E5E5E5", "x c #E4E4E4", "y c #A1A1A1", "z c #1F1F1F", "A c #676767", "B c #333333", "C c #787878", "D c #393939", " ", " ", " ", " ", " ", " .++++++@#$%%&*=-@++++. ", " +;;;;;>,')!!~{]^/(;;;+ ", " +;;;;_,:(;;;;<[$}.|1;+ ", " +;;;;2{(;;;;;13{453;;+ ", " +;;;_67;;;;;81;90a|b;+ ", " +;;;(c!;;;;;81;defg(;+ ", " .+++h%!;;;;;;1ijklmh+ ", " |n;;;;;;;;o| ", " |{p+++++++q| ", " rst;;;_uv|| ", " |{pwxy{|||| ", " |||||| zz|| ", " |AB|| ", " |CD|| ", " |A$| ", " || ", " ", " "}; xpn-1.2.6/pixmaps/previous.xpm0000644000175000017500000000253411141275756014553 0ustar antant/* XPM */ static char * previuos_xpm[] = { "24 24 43 1", " c None", ". c #000000", "+ c #B9D0B9", "@ c #CDDECB", "# c #B6C7B6", "$ c #B1C9B0", "% c #B3C4B3", "& c #B4CBB2", "* c #B5CEB5", "= c #B7CCB5", "- c #B9CEB7", "; c #BAD1BA", "> c #BBCFBA", ", c #BBD0B9", "' c #B2C9B0", ") c #7EAB78", "! c #AAC7A8", "~ c #B3CAB1", "{ c #B0C9B0", "] c #B0C9AE", "^ c #AEC7AC", "/ c #AAC5A8", "( c #A9C4A7", "_ c #698267", ": c #2D2D2D", "< c #CFDFCC", "[ c #ADC8AB", "} c #B0C7AE", "| c #ADC6AB", "1 c #678C63", "2 c #9BAD9A", "3 c #85AE81", "4 c #87AF84", "5 c #87B083", "6 c #88AF84", "7 c #88B085", "8 c #86AF82", "9 c #547150", "0 c #3C5235", "a c #5B7950", "b c #4A6342", "c c #3B5035", "d c #415639", " ", " ", " ", " . ", " .. ", " .+. ", " .@#. ", " .@$%........ ", " .@&*=-;->,'). ", " .@!~{]^///^(_. ", " :<[}||[!^^}^[1. ", " .23444445645789. ", " .0aaaaaaaaaaab. ", " .0aaaaaaaaaab. ", " .0aabccccccd. ", " .0ab........ ", " .0b. ", " .b. ", " .. ", " . ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/post.xpm0000644000175000017500000000375411141275756013671 0ustar antant/* XPM */ static char * post_xpm[] = { "24 24 87 1", " c None", ". c #000000", "+ c #E2E2E2", "@ c #F2F2F2", "# c #F3F3F3", "$ c #F4F4F4", "% c #F5F5F5", "& c #F6F6F6", "* c #F7F7F7", "= c #EAEAEA", "- c #F0F0F0", "; c #E0E0E0", "> c #E1E1E1", ", c #E3E3E3", "' c #E4E4E4", ") c #E5E5E5", "! c #E6E6E6", "~ c #E7E7E7", "{ c #E8E8E8", "] c #E9E9E9", "^ c #EBEBEB", "/ c #ECECEC", "( c #FBE73B", "_ c #F2B64D", ": c #868686", "< c #878787", "[ c #888888", "} c #898989", "| c #8A8A8A", "1 c #8B8B8B", "2 c #8C8C8C", "3 c #FCEB3D", "4 c #F7B544", "5 c #5D502C", "6 c #EBEAE8", "7 c #ECEBE9", "8 c #FCE93B", "9 c #F7B545", "0 c #6C5F34", "a c #FAE43A", "b c #F4B244", "c c #605737", "d c #F9DF39", "e c #F3AF42", "f c #625637", "g c #F9DC38", "h c #EFB44D", "i c #665A32", "j c #F8D837", "k c #F0A93F", "l c #655930", "m c #8D8D8D", "n c #F6D236", "o c #EDA43E", "p c #5C5130", "q c #989794", "r c #929292", "s c #EDEDED", "t c #EEEEEE", "u c #E8E7E4", "v c #E6E5E2", "w c #E0DFDC", "x c #D7AE74", "y c #61562F", "z c #F8F8F8", "A c #8E8E8E", "B c #4F4115", "C c #939393", "D c #F9F9F9", "E c #EFEFEF", "F c #F1F1F1", "G c #FAFAFA", "H c #8F8F8F", "I c #909090", "J c #919191", "K c #949494", "L c #959595", "M c #FBFBFB", "N c #FCFCFC", "O c #FDFDFD", "P c #969696", "Q c #FEFEFE", "R c #FFFFFF", "S c #979797", "T c #989898", "U c #C9C9C9", "V c #BDBDBD", " .................... ", ".+@@@@###$$$%%%&&*==.. ", ".-;;>+,')!~{{]=^/==.(_. ", ".@>::<<[}}||112222.345. ", ".@+,,')!~{]=^/=67.890. ", ".#,<[[}}||122222.abc.. ", ".#')!~~{]=^====.def.=. ", ".#)}}|||122222.ghi.$%. ", ".$!~{]=======.jkl.=%&. ", ".$~||1222m22.nop.qr&*. ", ".%{]=^/stuvw.xy.%&**z. ", ".%]122mmA22.B..rrCCzD. ", ".%=^/stE-F=..$%&*zDGG. ", ".&^2mmAHHIIJJrrCCKLMN. ", ".*sstE-F@#$%%&*zDGMNO. ", ".*tAAHHIIJrrCCCKLLPOQ. ", ".z-F@@#$%&*zDGMMNOQRR. ", ".zFIIJJrrCCKLLPPPSTRR. ", ".@@#$%&&*zDGMNOQRRRR/. ", ".Usz%&*zzDGMNOQRRRRtV. ", " .................... ", " ", " ", " "}; xpn-1.2.6/pixmaps/art_body.xpm0000644000175000017500000000072411141275756014501 0ustar antant/* XPM */ static char * art_unread_xpm[] = { "18 16 4 1", " c None", ". c #000000", "+ c #FFE8B7", "@ c #999999", " ", " ", " ", " ", "............... ", "..+++++++++++.. ", ".+.+++++++++.+. ", ".++.+++++++.++. ", ".+++.+++++.+++. ", ".++++.+++.++++.@ ", ".+++.+.+.+.+++.@@@", ".++.+++.+++.++.@@@", ".+.+++++++++.+.@@ ", "..+++++++++++..@@ ", "...............@ ", " @@@@@@@@@@@@@@@ "}; xpn-1.2.6/pixmaps/de.xpm0000644000175000017500000000570211141275756013267 0ustar antant/* XPM */ static char * de_xpm[] = { "18 12 155 2", " c None", ". c #000000", "+ c #FFFFFF", "@ c #D03536", "# c #C73A3B", "$ c #E76768", "% c #3A3B3B", "& c #C69000", "* c #C79205", "= c #D39E10", "- c #CD9C18", "; c #AC8621", "> c #ECBA35", ", c #DEB138", "' c #CEA434", ") c #F7C746", "! c #C88D00", "~ c #C98F03", "{ c #CA9405", "] c #C89009", "^ c #D1970D", "/ c #DCA41D", "( c #DFAB21", "_ c #D29E1F", ": c #A47C1B", "< c #EAB32F", "[ c #AF8623", "} c #B89028", "| c #BB902A", "1 c #C39A2E", "2 c #D1A435", "3 c #F6C142", "4 c #E1B542", "5 c #E6B746", "6 c #FBC84F", "7 c #FACB50", "8 c #F1C44E", "9 c #C79A30", "0 c #F5C450", "a c #C78400", "b c #C68503", "c c #CC8A07", "d c #CA8C12", "e c #D69514", "f c #E2A326", "g c #B68526", "h c #D8A02F", "i c #C08F2D", "j c #EFB33A", "k c #CB9833", "l c #DBA73E", "m c #F9BF4A", "n c #EEB74C", "o c #F8C151", "p c #EEB950", "q c #C80C01", "r c #C70C01", "s c #CE140A", "t c #C9170D", "u c #D92218", "v c #D33027", "w c #E5352B", "x c #BE332C", "y c #C93A31", "z c #F3473E", "A c #D5423A", "B c #FA564D", "C c #EA5149", "D c #E85048", "E c #F65A51", "F c #F96B64", "G c #CB0000", "H c #C70000", "I c #AD0100", "J c #C80303", "K c #AD0303", "L c #CF0505", "M c #CC0505", "N c #B20707", "O c #C70909", "P c #D00D0D", "Q c #D71010", "R c #0B0101", "S c #B21212", "T c #BD1414", "U c #D21818", "V c #DB1D1D", "W c #E32121", "X c #CF2020", "Y c #CA2626", "Z c #E92F2F", "` c #F13535", " . c #932121", ".. c #C63030", "+. c #C22F2F", "@. c #E13838", "#. c #D23434", "$. c #F54242", "%. c #D83A3A", "&. c #FC4646", "*. c #E24140", "=. c #E44242", "-. c #E54646", ";. c #C73F3E", ">. c #FE5050", ",. c #FA4F4F", "'. c #F54E4E", "). c #F45050", "!. c #E34A4A", "~. c #D94C4C", "{. c #F55757", "]. c #E35151", "^. c #D95050", "/. c #BE4646", "(. c #F55E5E", "_. c #F46565", ":. c #FE6A6A", "<. c #130A0A", "[. c #160D0D", "}. c #100A0A", "|. c #211818", "1. c #342B2B", "2. c #2F2727", "3. c #473E3E", "4. c #302A2A", "5. c #504848", "6. c #554D4D", "7. c #595151", "8. c #504949", "9. c #605959", "0. c #6B6464", "a. c #6A6A6A", "b. c #656565", "c. c #5E5E5E", "d. c #575757", "e. c #505050", "f. c #4F4F4F", "g. c #464646", "h. c #424242", "i. c #414141", "j. c #383838", "k. c #353535", "l. c #323232", "m. c #2F2F2F", "n. c #212121", "o. c #1F1F1F", "p. c #1D1D1D", "q. c #191919", "r. c #181818", "s. c #111111", "t. c #101010", "u. c #0D0D0D", "v. c #090909", "w. c #050505", "x. c #030303", ". . . . . . . . . . . . . . . . . . ", ". . . q.% a.d.j.r.w.. w.t.n.k.g.e.. ", ". . s.l.b.c.i.o.v.. x.u.p.m.h.f.e.. ", ". }.4.9.0.5.2.[.R R <.|.1.3.6.7.8.. ", ". ./.$ ^.+.S K I N T Y %.!.].~.;.. ", ". # :.{.@.U M G L Q W ` &.>.'.=.#.. ", ". _.(.*.X O H J P V Z $.,.).-.@ ... ", ". F D v t r q s u w z B E C A y x . ", ". p h d b a c e f j m o n l k i g . ", ". , - * & { = ( > ) 7 8 4 ' 1 } ; . ", ". _ ] ! ~ ^ / < 3 6 0 5 2 9 | [ : . ", ". . . . . . . . . . . . . . . . . . "}; xpn-1.2.6/pixmaps/art_unkeep.xpm0000644000175000017500000000067311141275756015036 0ustar antant/* XPM */ static char * art_unread_xpm[] = { "18 16 1 1", " c None", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/mark.xpm0000644000175000017500000000712411141275756013631 0ustar antant/* XPM */ static char * mark_xpm[] = { "24 24 148 2", " c None", ". c #0D110D", "+ c #000000", "@ c #2424D9", "# c #737466", "$ c #E4E5DE", "% c #D3D5CA", "& c #A5A797", "* c #F3F4F0", "= c #ABAE99", "- c #AEB19C", "; c #AEB09C", "> c #B2B5A1", ", c #B2B4A0", "' c #AFB29D", ") c #6E715C", "! c #1B1BA8", "~ c #181893", "{ c #000900", "] c #E6E7DD", "^ c #F5F6F3", "/ c #E4E5DB", "( c #71726C", "_ c #3F403A", ": c #F7F7F6", "< c #D3D6C5", "[ c #D1D5C3", "} c #D0D3C1", "| c #CFD2BF", "1 c #CDD0BE", "2 c #CCCFBC", "3 c #CBCDBA", "4 c #B0B3A1", "5 c #171B16", "6 c #7A7C67", "7 c #F0F0EB", "8 c #D2D4C3", "9 c #D1D4C3", "0 c #CFD3C1", "a c #CFD1C0", "b c #CED0BD", "c c #CCCEBC", "d c #CACEB9", "e c #2727D9", "f c #022202", "g c #76786A", "h c #93967C", "i c #F0F1EC", "j c #D1D3C1", "k c #74776C", "l c #8E9083", "m c #CCCFBD", "n c #CBCEBB", "o c #989A8B", "p c #3031D9", "q c #2627D9", "r c #BEC1A8", "s c #909478", "t c #EFF0EB", "u c #CFD1BF", "v c #6A71E2", "w c #B3B5A4", "x c #191917", "y c #3D3FDC", "z c #3F41DD", "A c #3132DB", "B c #BFC2AB", "C c #BEC0A8", "D c #8E9175", "E c #6B71C1", "F c #909AE8", "G c #676CE1", "H c #252522", "I c #65665C", "J c #5054DE", "K c #494CDE", "L c #3C3EDD", "M c #2E2FDA", "N c #242420", "O c #BFC3AB", "P c #BEC1A9", "Q c #BDC0A8", "R c #020203", "S c #8F9AE8", "T c #474ADD", "U c #000001", "V c #666CE1", "W c #6167E1", "X c #5358E0", "Y c #4649DE", "Z c #2D2EDA", "` c #B5B8A2", " . c #BDC1A9", ".. c #BCBFA7", "+. c #666DE1", "@. c #848CE6", "#. c #585DE0", "$. c #7880E5", "%. c #6B72E3", "&. c #5E63E1", "*. c #4144DC", "=. c #0F190E", "-. c #A9AD98", ";. c #C0C3AC", ">. c #BEC2AA", ",. c #BEC0A9", "'. c #BCBFA6", "). c #EDEEE8", "!. c #3F4039", "~. c #6A70E2", "{. c #8B96E6", "]. c #909BE8", "^. c #838BE6", "/. c #757DE4", "(. c #565BDF", "_. c #10180F", ":. c #9DA08D", "<. c #BCC0A8", "[. c #BCBEA6", "}. c #8B8F72", "|. c #ECEEE7", "1. c #C7CBB6", "2. c #4A4C44", "3. c #565ADF", "4. c #8E98E6", "5. c #8D98E7", "6. c #5E65E1", "7. c #162C16", "8. c #797B6D", "9. c #C1C4AD", "0. c #C0C2AB", "a. c #BBBEA5", "b. c #E8E8E0", "c. c #C7C9B4", "d. c #C6C9B4", "e. c #4A4B43", "f. c #656CE1", "g. c #696FE2", "h. c #797A6D", "i. c #C1C4AE", "j. c #BDC0A7", "k. c #BABEA4", "l. c #C6C9BA", "m. c #8E9276", "n. c #47493B", "o. c #4345DD", "p. c #34352A", "q. c #646751", " ", " ", " ", " . . ", " + + + + + + + @ @ + ", " # $ % % % % & + + @ @ + ", " + * = - ; > , ' ) + + + ! @ @ ~ { + + ", " + ] ^ ] ] ] ] ] / ] ( + @ @ @ @ @ + _ + ", " + : < [ } | 1 2 3 4 5 @ @ @ @ @ @ + 6 + ", " + 7 8 9 0 a b c d + e @ @ @ @ @ f g h + ", " + i j k + l m n o + p q @ @ @ @ + r s + ", " + t u + v + w 3 x y z A @ @ @ + B C D + ", " + 7 + E F G H I + J K L M @ N O P Q h + ", " + i R F S F T U V W X Y Z N ` B ...s + ", " + t + +.F S @.#.$.%.&.*.=.-.;.>.,.'.D + ", " + ).!.+ ~.{.].S ^./.(._.:.;.O P <.[.}.+ ", " + |.1.2.+ 3.4.F 5.6.7.8.9.0.>.C ..a.}.+ ", " + b.c.d.e.+ f.4.g.+ h.i.;.B .j.[.k.}.+ ", " + l.s m.D n.+ o.+ p.}.}.}.}.}.}.}.}.q.+ ", " + + + + + + + + + + + + + + + + + + + ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/spoiler_char.xpm0000644000175000017500000001175411141275756015355 0ustar antant/* XPM */ static char * spoiler_char_xpm[] = { "24 24 237 2", " c None", ". c #000000", "+ c #0E0E0E", "@ c #1D1D1D", "# c #383838", "$ c #929292", "% c #9A9A9A", "& c #909090", "* c #767676", "= c #363636", "- c #797979", "; c #B1B1B1", "> c #8D8D8D", ", c #6E6E6E", "' c #6D6D6D", ") c #686868", "! c #1F1F1F", "~ c #606060", "{ c #C0C0C0", "] c #868686", "^ c #6A6A6A", "/ c #676767", "( c #555555", "_ c #424242", ": c #0F0F0F", "< c #999999", "[ c #4D4D4D", "} c #545454", "| c #212121", "1 c #474747", "2 c #7D7D7D", "3 c #464646", "4 c #353535", "5 c #4A4A4A", "6 c #C8C8C8", "7 c #5F5F5F", "8 c #3A3A3A", "9 c #060606", "0 c #666660", "a c #A5A5A5", "b c #343434", "c c #292929", "d c #2F2F2F", "e c #636253", "f c #B9B26A", "g c #F3E453", "h c #CAC16B", "i c #C6C6C6", "j c #2A2A2A", "k c #525139", "l c #5F5D29", "m c #11100A", "n c #A0A09B", "o c #BEBEBE", "p c #2E2E2E", "q c #98903C", "r c #F5EA6F", "s c #FAF39E", "t c #CDC8AB", "u c #D1D1D1", "v c #554C31", "w c #E8DF5B", "x c #22210C", "y c #111008", "z c #D8CD46", "A c #C9C497", "B c #BDBDBD", "C c #2D2D2D", "D c #9F9E87", "E c #FFFDCF", "F c #FFFCC5", "G c #B29B68", "H c #86827C", "I c #484848", "J c #6B481E", "K c #F2E456", "L c #3F3E17", "M c #030301", "N c #0E0D01", "O c #706A57", "P c #BCBCBC", "Q c #1E1E1E", "R c #8B7D59", "S c #FFFCB8", "T c #FFFCB1", "U c #FFFBA5", "V c #E5D16E", "W c #E5D061", "X c #E0B538", "Y c #D7970C", "Z c #392900", "` c #494949", " . c #838383", ".. c #E1E1E1", "+. c #D8D8D8", "@. c #2B2B2B", "#. c #54493C", "$. c #604B30", "%. c #BB9F57", "&. c #FFFBA2", "*. c #FFFB9D", "=. c #F7E478", "-. c #E9B93C", ";. c #D98E08", ">. c #CC7300", ",. c #CF8900", "'. c #3B2C00", "). c #696969", "!. c #969696", "~. c #C9C9C9", "{. c #CCCCCC", "]. c #DBDBDB", "^. c #D5D5D5", "/. c #D6D6D6", "(. c #DEDEDE", "_. c #998A40", ":. c #EDC551", "<. c #E5AC2E", "[. c #E4A609", "}. c #D79D00", "|. c #CB9900", "1. c #E09C00", "2. c #D48100", "3. c #DA9000", "4. c #F5F5F5", "5. c #D0D0D0", "6. c #747474", "7. c #B6B6B6", "8. c #DCDCDC", "9. c #DDDDDD", "0. c #DFDFDF", "a. c #E0E0E0", "b. c #E5E5E5", "c. c #E4E4E4", "d. c #9C8B14", "e. c #FBDF00", "f. c #9A8300", "g. c #0A0500", "h. c #C59508", "i. c #D88A00", "j. c #DD9400", "k. c #3D3D3D", "l. c #F9F9F9", "m. c #F2F2F2", "n. c #ACACAC", "o. c #9D9D9D", "p. c #858585", "q. c #E6E6E6", "r. c #E8E8E8", "s. c #E9E9E9", "t. c #EAEAEA", "u. c #EEEEEE", "v. c #EDEDED", "w. c #4F4F4F", "x. c #5E5300", "y. c #1E1100", "z. c #CA9F14", "A. c #D98C00", "B. c #DC9300", "C. c #F0F0F0", "D. c #C3C3C3", "E. c #EFEFEF", "F. c #F1F1F1", "G. c #F3F3F3", "H. c #F7F7F7", "I. c #FFFFFF", "J. c #433900", "K. c #9D8A25", "L. c #E6AB04", "M. c #D48200", "N. c #D98F00", "O. c #F6F6F6", "P. c #F8F8F8", "Q. c #FAFAFA", "R. c #FBFBFB", "S. c #FEFEFE", "T. c #C5C5C5", "U. c #3D3400", "V. c #1F1100", "W. c #C5A91B", "X. c #DD9600", "Y. c #C97000", "Z. c #D69400", "`. c #D3D3D3", " + c #D2D2D2", ".+ c #D7D7D7", "++ c #FCFCFC", "@+ c #B7B7B7", "#+ c #ADADAD", "$+ c #B8B8B8", "%+ c #1A1A1A", "&+ c #9D7D00", "*+ c #D69E05", "=+ c #D28000", "-+ c #DC9A00", ";+ c #AE8000", ">+ c #7C7C7C", ",+ c #CFCFCF", "'+ c #CECECE", ")+ c #CDCDCD", "!+ c #B2B2B2", "~+ c #A7A7A7", "{+ c #AFAFAF", "]+ c #B0B0B0", "^+ c #BBBBBB", "/+ c #4E4E4E", "(+ c #9F7800", "_+ c #D79E00", ":+ c #936F00", "<+ c #2C2100", "[+ c #808080", "}+ c #CBCBCB", "|+ c #959595", "1+ c #AAAAAA", "2+ c #A9A9A9", "3+ c #A8A8A8", "4+ c #828282", "5+ c #191300", "6+ c #C7C7C7", "7+ c #C2C2C2", "8+ c #A2A2A2", "9+ c #A1A1A1", "0+ c #A0A0A0", "a+ c #B5B5B5", "b+ c #BFBFBF", "c+ c #7A7A7A", "d+ c #9B9B9B", "e+ c #9F9F9F", "f+ c #595959", "g+ c #8C8C8C", "h+ c #949494", "i+ c #8E8E8E", "j+ c #434343", "k+ c #818181", "l+ c #1C1C1C", "m+ c #0C0C0C", "n+ c #151515", " . + @ . . ", " . # $ % & * = . ", " . - ; > - , ' ) ! ", " . ~ { ] ^ / / / ( _ . ", " : { < [ } | 1 2 3 4 . ", " 5 6 7 8 9 . 0 a b c . ", " . ' { d e f g h i j k l . ", " m n o p q r s t u c v w x ", " y z A B C D E F G H I J K L ", " . M N O P Q R S T U V W X Y Z ", " . . + ` .B ..+.@.#.$.%.&.*.=.-.;.>.,.'.", " C ).!.~.{...].^./.].(.C _.:.<.[.}.|.1.2.3.'.", " . (.4.5.6. .7.8.9.0.a.b.c.p d.e.f.. g.h.i.j.'.", " k.l.4.m.n.o.p.^.q.r.s.t.u.v.w.x.. . y.z.A.B.'.", ". < C.t.s.4.D.v.u.E.C.F.G.H.I.I.7 J.g.K.L.M.N.'.", ". 9.c.].+...H.O.H.P.Q.R.S.P.0.T.a U.V.W.X.Y.Z.'.", "@.c./.`. +5..+++S.I.b.{.@+a #+$+D.%+&+*+=+-+;+. ", ". >+ +,+'+)+)+@+!+~+~+{+; ]+]+]+^+/+(+_+:+<+. ", " . [+{.}+~.~.a |+1+2+2+2+2+3+3+@+4+5+. . ", " . 2 6+i 7+< < 8+8+9+9+9+0+a a+b+. ", " . c+7+{ < |+% % < < d+9+e+] f+. ", " . c+b+g+$ h+!.i+) j+Q . . ", " . k+] ) _ l+. . ", " m+n+. "}; xpn-1.2.6/pixmaps/conf.xpm0000644000175000017500000000375411141275756013631 0ustar antant/* XPM */ static char * conf_xpm[] = { "24 24 87 1", " c None", ". c #000000", "+ c #BAB5AB", "@ c #D0CDC6", "# c #88857D", "$ c #C9C6BE", "% c #CCC8C1", "& c #E5E3E0", "* c #FFFFFF", "= c #757575", "- c #2E2E2E", "; c #F6F5F5", "> c #CCCCCC", ", c #AFAFAF", "' c #D3D1CB", ") c #C1C0BF", "! c #F0EFED", "~ c #797772", "{ c #DCDCDC", "] c #A5A19C", "^ c #EAE9E5", "/ c #F3F1F0", "( c #EDEDED", "_ c #A19D96", ": c #C1BDB4", "< c #DBD8D3", "[ c #D9D6D1", "} c #89857E", "| c #FCFCFC", "1 c #EAE9E6", "2 c #F5F4F3", "3 c #C6C2BA", "4 c #F0EFEE", "5 c #F4F4F3", "6 c #CBC7C0", "7 c #ECECEB", "8 c #676560", "9 c #54524D", "0 c #777676", "a c #797978", "b c #85827E", "c c #79756F", "d c #7590AE", "e c #A4BAD0", "f c #90A6BE", "g c #9F9F9E", "h c #BEBDBC", "i c #B8B4AD", "j c #87837C", "k c #D3DFEA", "l c #A2AEBC", "m c #9DB6CE", "n c #637B95", "o c #E2E2E2", "p c #EEEEED", "q c #849CB6", "r c #D7E2ED", "s c #8D98A5", "t c #9DB8D2", "u c #607791", "v c #EDEDEC", "w c #99ADC3", "x c #DFE7F0", "y c #8193A9", "z c #586D84", "A c #5B7189", "B c #F1F1F1", "C c #EEEDEB", "D c #A7A6A5", "E c #726F6A", "F c #A1B4C8", "G c #EEF3F6", "H c #60768F", "I c #DEDDDC", "J c #787776", "K c #4E4E4D", "L c #91A6BE", "M c #F0F4F7", "N c #97A5B6", "O c #BFBEBD", "P c #AAAAA9", "Q c #ACACAB", "R c #B0C6DB", "S c #EDF2F6", "T c #818A95", "U c #6C85A1", "V c #C0D1E2", " .. ", " .+@#. ", " .$%+. .. ", " .&$. .*=. ", " .. -;$. .*>,. ", " .' ..)!+~. .{,. ", " .]%%^/+++. .(.. ", " ._:%$<[+}. .|. ", " .....123}..>. ", " .456.,. ", " .7.,.. ", " .,.89. ", " ....,.0abc. ", " .def.. .ghij. ", " .dklmn. .op6}. ", " .qrsntu. .v/$}. ", " .wxyztdA. .BCDE..", " .FGyHtdA. .IJK,.", " .LMNHtdA. .OPQ.", " .RSTtdA.. ... ", " .UtVLA.. ", " .UUn.. ", " ... ", " "}; xpn-1.2.6/pixmaps/followup.xpm0000644000175000017500000000777011141275756014555 0ustar antant/* XPM */ static char * followup_xpm[] = { "24 24 174 2", " c None", ". c #000000", "+ c #E2E2E2", "@ c #F2F2F2", "# c #F3F3F3", "$ c #F4F4F4", "% c #F5F5F5", "& c #F6F6F6", "* c #F7F7F7", "= c #EAEAEA", "- c #F0F0F0", "; c #E0E0E0", "> c #E1E1E1", ", c #E3E3E3", "' c #E4E4E4", ") c #E5E5E5", "! c #E6E6E6", "~ c #E7E7E7", "{ c #E8E8E8", "] c #E9E9E9", "^ c #EBEBEB", "/ c #ECECEC", "( c #FBE73B", "_ c #F2B64D", ": c #868686", "< c #878787", "[ c #888888", "} c #898989", "| c #8A8A8A", "1 c #8B8B8B", "2 c #8C8C8C", "3 c #FCEB3D", "4 c #F7B544", "5 c #5D502C", "6 c #EBEAE8", "7 c #ECEBE9", "8 c #FCE93B", "9 c #F7B545", "0 c #6C5F34", "a c #FAE43A", "b c #F4B244", "c c #605737", "d c #F9DF39", "e c #F3AF42", "f c #625637", "g c #F9DC38", "h c #EFB44D", "i c #665A32", "j c #DFDFDF", "k c #B4B4B4", "l c #696969", "m c #CCCCCC", "n c #F5D536", "o c #F0A93F", "p c #655930", "q c #737373", "r c #363932", "s c #545E46", "t c #2B2E26", "u c #ECC933", "v c #E9A13D", "w c #5B502F", "x c #989794", "y c #929292", "z c #2D2F2A", "A c #6E7C5D", "B c #566049", "C c #747471", "D c #CFA76F", "E c #5F542E", "F c #F8F8F8", "G c #626262", "H c #2B3024", "I c #72805F", "J c #3A3A3A", "K c #483B13", "L c #8F8F8F", "M c #919191", "N c #939393", "O c #F9F9F9", "P c #EDEDED", "Q c #262626", "R c #7A8A64", "S c #627347", "T c #5A5A5A", "U c #A2A2A2", "V c #DEDEDE", "W c #FAFAFA", "X c #8D8D8D", "Y c #161616", "Z c #A2B783", "` c #586C33", " . c #282828", ".. c #6C6C6C", "+. c #7C7C7C", "@. c #0A0A0A", "#. c #545454", "$. c #7F7F7F", "%. c #858585", "&. c #FBFBFB", "*. c #FCFCFC", "=. c #EEEEEE", "-. c #EFEFEF", ";. c #B0C78E", ">. c #6B8637", ",. c #374026", "'. c #C6C6C6", "). c #0A0C05", "!. c #3F492B", "~. c #D4D4D4", "{. c #FDFDFD", "]. c #8E8E8E", "^. c #171717", "/. c #A5B98B", "(. c #8CA85B", "_. c #627B32", ":. c #252B19", "<. c #131313", "[. c #14190A", "}. c #668034", "|. c #2C351B", "1. c #585858", "2. c #FEFEFE", "3. c #F1F1F1", "4. c #3E3E3E", "5. c #798668", "6. c #B4C896", "7. c #89A553", "8. c #7D9C42", "9. c #7C9B40", "0. c #283214", "a. c #929291", "b. c #FFFFFF", "c. c #909090", "d. c #757575", "e. c #1C1E1A", "f. c #B6C4A9", "g. c #BECFA4", "h. c #9DB672", "i. c #93AE63", "j. c #91AD5F", "k. c #819A57", "l. c #3F4733", "m. c #5F5F5F", "n. c #515250", "o. c #6E7867", "p. c #C9D7BC", "q. c #D1DEBF", "r. c #CADAB4", "s. c #BFD3A4", "t. c #BAD09D", "u. c #ACBD96", "v. c #5C6551", "w. c #C9C9C9", "x. c #C8C8C8", "y. c #5D5F5C", "z. c #6B7562", "A. c #AFBEA0", "B. c #C5D6B0", "C. c #CADAB5", "D. c #BCD1A0", "E. c #AFC198", "F. c #575D50", "G. c #878786", "H. c #BDBDBD", "I. c #0A0B09", "J. c #1A1D18", "K. c #20231C", "L. c #3C4235", "M. c #AFC199", "N. c #595F53", "O. c #080807", "P. c #141514", "Q. c #545851", " . . . . . . . . . . . . . . . . . . . . ", ". + @ @ @ @ # # # $ $ $ % % % & & * = = . . ", ". - ; ; > + , ' ) ! ~ { { ] = ^ / = = . ( _ . ", ". @ > : : < < [ } } | | 1 1 2 2 2 2 . 3 4 5 . ", ". @ + , , ' ) ! ~ { ] = ^ / = 6 7 . 8 9 0 . ", ". # , < [ [ } } | | 1 2 2 2 2 2 . a b c . . ", ". # ' ) ! ~ ~ { ] = ^ = = = = . d e f . = . ", ". # ) } } | | | 1 2 2 2 2 2 . g h i . $ % . ", ". $ ! ~ { ] ] ~ j k l } m . n o p . = % & . ", ". $ ~ | | 1 | [ q r s t . u v w . x y & * . ", ". % { ] = ^ ] > z A B C . D E . $ & * * F . ", ". % ] 1 2 2 } G H I J . K . . 2 L M N F O . ", ". % = ^ / P ~ Q R S T . . U V , ^ # F W W . ", ". & ^ 2 X X | Y Z ` ...+.@.#.$.%.X y &.*.. ", ". * P P =.-.] Q ;.>.,.L '.).!.} ~.+ - *.{.. ", ". * =.].].L 1 ^./.(._.:.<.[.}.|.1.$.} {.2.. ", ". F - 3.@ @ -.4.5.6.7.8.9.9.9.>.0.a.V b.b.. ", ". F 3.c.c.M L d.e.f.g.h.i.j.j.j.k.l.m.b.b.. ", ". @ @ # $ % % @ n.o.p.q.r.s.t.t.u.v.< b./ . ", ". w.P F % & * * x.y.z.A.B.C.D.E.F.G.=.=.H.. ", " . . . . . . . . . I.J.K.L.M.N.O.. . . . ", " P.Q.. ", " . . ", " "}; xpn-1.2.6/pixmaps/en.xpm0000644000175000017500000000606211141275756013301 0ustar antant/* XPM */ static char * en_xpm[] = { "18 12 162 2", " c None", ". c #000000", "+ c #FFFFFF", "@ c #BC6263", "# c #BA6264", "$ c #B97273", "% c #EC9698", "& c #F2BABB", "* c #AE2B30", "= c #AF2F33", "- c #B13A3F", "; c #B8474B", "> c #D66468", ", c #E16D71", "' c #E57378", ") c #E07075", "! c #D98386", "~ c #AD6C6E", "{ c #C29294", "] c #DCA8AA", "^ c #D2A7A9", "/ c #C9A9AA", "( c #F9DBDC", "_ c #F5DBDC", ": c #A72830", "< c #A72E36", "[ c #A83C43", "} c #BE454D", "| c #AF4148", "1 c #B9464E", "2 c #B1434A", "3 c #B0464B", "4 c #6C2B2F", "5 c #C04E55", "6 c #C4535A", "7 c #D15B62", "8 c #D45D65", "9 c #D15D65", "0 c #CE5B63", "a c #934A4F", "b c #D77178", "c c #DD767D", "d c #D37176", "e c #CA7D81", "f c #E69DA1", "g c #CEA2A5", "h c #E6C5C7", "i c #C8B8B9", "j c #9A0E18", "k c #9C111C", "l c #9B111B", "m c #9E131D", "n c #9C131D", "o c #9D1721", "p c #A51B25", "q c #A81F29", "r c #A3232C", "s c #9F222B", "t c #A62731", "u c #B12B35", "v c #B52F39", "w c #A82C35", "x c #C03C46", "y c #B33942", "z c #C4454E", "A c #CE4F58", "B c #D0545D", "C c #C04F57", "D c #A7454C", "E c #C3525A", "F c #D45C65", "G c #D1636B", "H c #D66A72", "I c #C1A0A3", "J c #EEC9CC", "K c #E3C2C5", "L c #C4A7AA", "M c #EACACD", "N c #9D4A56", "O c #965C65", "P c #C47A86", "Q c #724049", "R c #B0989D", "S c #CDB3B8", "T c #EBD3D8", "U c #9D6371", "V c #A8707E", "W c #978287", "X c #C0ABB0", "Y c #C0A5AC", "Z c #B69FA5", "` c #D5BBC2", " . c #DAC0C7", ".. c #E6CCD3", "+. c #C6B3B8", "@. c #ECD8DE", "#. c #7E5870", "$. c #9A8091", "%. c #8F6D86", "&. c #B5A1B1", "*. c #4D4F7B", "=. c #A2A3B4", "-. c #525574", ";. c #1D2970", ">. c #46508C", ",. c #292E4A", "'. c #57609A", "). c #646B95", "!. c #A9ACBD", "~. c #05135C", "{. c #686F90", "]. c #A6ACC8", "^. c #A2A9C7", "/. c #516095", "(. c #636D90", "_. c #8890AE", ":. c #36477D", "<. c #5C6CA1", "[. c #6D7799", "}. c #8993B4", "|. c #203776", "1. c #263C7A", "2. c #6A7BAE", "3. c #7582A6", "4. c #103074", "5. c #4E669C", "6. c #546CA1", "7. c #516796", "8. c #7384A9", "9. c #687798", "0. c #8E9FC4", "a. c #D3D9E7", "b. c #E9ECF3", "c. c #0D2E72", "d. c #0E234E", "e. c #2B4373", "f. c #758BB8", "g. c #717F9C", "h. c #909296", "i. c #4D648C", "j. c #B8BDC6", "k. c #445A7E", "l. c #ADB8CA", "m. c #9FA8B7", "n. c #C8D2E2", "o. c #ADB1B6", "p. c #9AADBF", "q. c #D1E2F1", "r. c #C1CBD3", "s. c #E4EFF7", "t. c #E7C3C2", "u. c #7A5252", "v. c #C58C8C", "w. c #AD8383", "x. c #CCA5A5", "y. c #C5A1A1", "z. c #F0CECE", "A. c #EFD0D0", "B. c #D2C0C0", "C. c #CFBEBE", "D. c #FCE9E9", "E. c #F4E3E3", ". . . . . . . . . . . . . . . . . . ", ". 4 u.h.g.2.'._.; = {.~.4.).P % D.. ", ". ,.Q ~ E.n./.[.- * (.|.%.d & b.0.. ", ". d.k.&.f t.r.m.< : =.V ! E.q.f.5.. ", ". W X @.h g / y.s r ^ ] M _ .. .S . ", ". D c G 1 t n j m q v z B F 0 C | . ", ". b H 5 w o l k p u x A 8 9 E 2 [ . ", ". T ` Y L I { x.y } z.( J K +.Z R . ", ". 6.7.p.i # U !.6 7 a.s.A.e $.i.e.. ", ". 8.j.v.3 #.1.3.> , ^.<.l.C.$ O -.. ", ". B.@ N *.c.;.}.) ' ].>.:.9.o.w.a . ", ". . . . . . . . . . . . . . . . . . "}; xpn-1.2.6/pixmaps/receive_headers.xpm0000644000175000017500000000631711141275756016017 0ustar antant/* XPM */ static char * receive_headers_xpm[] = { "24 24 123 2", " c None", ". c #000000", "+ c #E2E2E2", "@ c #F2F2F2", "# c #F3F3F3", "$ c #F4F4F4", "% c #F5F5F5", "& c #F6F6F6", "* c #F7F7F7", "= c #DBDBDB", "- c #F0F0F0", "; c #E0E0E0", "> c #E1E1E1", ", c #E3E3E3", "' c #E4E4E4", ") c #E5E5E5", "! c #E6E6E6", "~ c #E7E7E7", "{ c #E8E8E8", "] c #E9E9E9", "^ c #EAEAEA", "/ c #EBEBEB", "( c #ECECEC", "_ c #EDEDED", ": c #EEEEEE", "< c #EFEFEF", "[ c #314E6C", "} c #304D6B", "| c #F1F1F1", "1 c #304C6A", "2 c #2E4A66", "3 c #2D4965", "4 c #DADADA", "5 c #CACACA", "6 c #C0C0C0", "7 c #C1C1C1", "8 c #C2C2C2", "9 c #C3C3C3", "0 c #C4C4C4", "a c #C6C6C6", "b c #D0D0D0", "c c #353535", "d c #1C1C1C", "e c #43543D", "f c #4D6146", "g c #4D6247", "h c #5A7257", "i c #71916E", "j c #748A72", "k c #8DB389", "l c #3D4E39", "m c #5E7656", "n c #607857", "o c #93B690", "p c #AECBAD", "q c #AFCCAE", "r c #C0D9BF", "s c #F8F8F8", "t c #1B1B1B", "u c #5E7756", "v c #617A59", "w c #99BC97", "x c #B1CEB0", "y c #B4D2B3", "z c #C5DFC4", "A c #0B0B0B", "B c #607858", "C c #637C5B", "D c #9CBF99", "E c #B5D3B4", "F c #C6E0C5", "G c #647D5B", "H c #9DC19B", "I c #B5D2B4", "J c #B6D4B5", "K c #C7E1C6", "L c #607958", "M c #657F5C", "N c #A0C39D", "O c #D0E7D0", "P c #627B59", "Q c #67815E", "R c #A1C69E", "S c #FBFBFB", "T c #FDFDFD", "U c #0E0E0E", "V c #4C6046", "W c #4D6246", "X c #68835F", "Y c #A1C69F", "Z c #B8D7B7", "` c #B9D7B8", " . c #C0D5C0", ".. c #BFD4BF", "+. c #D6EAD6", "@. c #080808", "#. c #FEFEFE", "$. c #010101", "%. c #3E4F39", "&. c #5D7555", "*. c #617959", "=. c #657E5C", "-. c #6A8561", ";. c #B7D5B6", ">. c #F0FEEF", ",. c #FFFFFF", "'. c #A2C7A0", "). c #F1FFF0", "!. c #303030", "~. c #3F5239", "{. c #637D5B", "]. c #C9C9C9", "^. c #5C5C5C", "/. c #41533C", "(. c #66815E", "_. c #9FC49D", ":. c #B8D6B7", "<. c #434343", "[. c #BDBDBD", "}. c #96B892", "|. c #E8F4E6", "1. c #070707", "2. c #A5B4A4", " . . . . . . . . . . . . . . . . . . . . ", ". + @ @ @ @ # # # $ $ $ % % % & & * * $ = . ", ". - ; ; > + , ' ) ! ~ { { ] ^ / ( _ : < _ . ", ". @ > [ [ [ [ } } } } } } } } } [ [ [ - | . ", ". @ + [ [ [ 1 2 3 3 3 3 3 3 3 2 1 [ [ | @ . ", ". # , , , + 4 5 6 6 7 8 9 0 a b + : | @ # . ", ". # ' [ [ [ [ } [ [ [ [ } [ [ [ [ } [ # $ . ", ". # ) [ [ [ 1 2 [ [ [ 1 2 [ [ [ 1 2 [ $ % . ", ". $ ! & & ) ) c . . . . . . . . & ) ) % & . ", ". $ & & & & & d e f g h i j k . & & & & * . ", ". % & & & & & d l m n o p q r . & & & & s . ", ". % & & & & & t l u v w x y z . & & & & $ . ", ". $ & & & & & A l B C D y E F . & & & & | . ", ". % & & & & & . l B G H I J K . & & & & & . ", ". & & & & & & . l L M N E J O . & & & & & . ", ". * & ) . . . . l P Q R J J K . . . . S T . ", ". * & ) U V V V W C X Y Z Z ` ...+.@.T #.. ", ". s & | / $.%.&.*.=.-.Y ` ;.` Z >.. T ,.,.. ", ". s | & & ) U %.*.M -.'.` J Z ).. | ,.,.,.. ", ". @ @ # $ % # !.~.{.X Y ` J ).A T ,.,.,.( . ", ". ]._ s % & * * ^./.(._.:.).<.#.,.,.,.: [.. ", " . . . . . . . . . /.}.|.. 1.. . . . . . ", " t 2.t ", " t "}; xpn-1.2.6/pixmaps/fr.xpm0000644000175000017500000000554211141275756013310 0ustar antant/* XPM */ static char * fr_xpm[] = { "18 12 149 2", " c None", ". c #000000", "+ c #FFFFFF", "@ c #D03536", "# c #EEEDF1", "$ c #0000C7", "% c #0000C6", "& c #00007C", "* c #0303C9", "= c #0303C6", "- c #0505C7", "; c #0909C8", "> c #0D0DC9", ", c #0A0A88", "' c #1212CA", ") c #1818CD", "! c #111190", "~ c #1F20D0", "{ c #191999", "] c #2727D3", "^ c #2424C4", "/ c #2525C3", "( c #2121A4", "_ c #2929C7", ": c #3030D8", "< c #2B2BC4", "[ c #3030CD", "} c #2A2AAE", "| c #3838DD", "1 c #3838DC", "2 c #3232B8", "3 c #3939CA", "4 c #4141E2", "5 c #3A3BC3", "6 c #3B3AC3", "7 c #4848E8", "8 c #4646D1", "9 c #5050ED", "0 c #5757F1", "a c #4E4ED5", "b c #5E5EF5", "c c #5959E5", "d c #6464F9", "e c #6464F8", "f c #6867FA", "g c #6565F3", "h c #6665F3", "i c #6A6AFA", "j c #6565E5", "k c #7979F3", "l c #8484F8", "m c #C7C7CB", "n c #C3C3C7", "o c #C2C2C6", "p c #D7D7DB", "q c #CFCFD3", "r c #CECED2", "s c #DEDEE1", "t c #C6C6C9", "u c #EFEFF0", "v c #DBDBDC", "w c #FAFDFE", "x c #CED3D3", "y c #C8CDCD", "z c #C6CBCB", "A c #E9EEEE", "B c #F9FDFD", "C c #F5F9F9", "D c #F3F7F7", "E c #DFE3E3", "F c #D6DADA", "G c #E5E6E6", "H c #D2D2CF", "I c #D1D1CE", "J c #CBCBC8", "K c #C9C9C6", "L c #ECECEA", "M c #E1E1DF", "N c #D8D8D6", "O c #CBCBC9", "P c #DEDEDD", "Q c #D9D9D8", "R c #D21818", "S c #DF2121", "T c #DB2424", "U c #A41B1B", "V c #AC2121", "W c #E92F2F", "X c #AF2323", "Y c #B52626", "Z c #E53332", "` c #B82828", " . c #EC3535", ".. c #BB2A2A", "+. c #BD2C2C", "@. c #C32E2E", "#. c #C02D2D", "$. c #C73030", "%. c #C93231", "&. c #C63030", "*. c #CE3434", "=. c #CB3333", "-. c #F33E3E", ";. c #F54242", ">. c #EF4141", ",. c #D53A3A", "'. c #F74646", "). c #DB3F3E", "!. c #D03C3C", "~. c #E14242", "{. c #F94A4A", "]. c #FA4D4D", "^. c #E54646", "/. c #EA4949", "(. c #FA4F4F", "_. c #F74E4E", ":. c #FA5050", "<. c #EE4C4C", "[. c #F14E4E", "}. c #E04848", "|. c #F85151", "1. c #F75151", "2. c #F45050", "3. c #F95656", "4. c #ED5353", "5. c #F65858", "6. c #C7B0B0", "7. c #CDB6B6", "8. c #D5BFBF", "9. c #DFC9C9", "0. c #E9D4D4", "a. c #F2DDDD", "b. c #EFDBDB", "c. c #E3D0D0", "d. c #F7E3E3", "e. c #F6E2E2", "f. c #C8C7C7", "g. c #FBFBFB", "h. c #F7F7F7", "i. c #F6F6F6", "j. c #ECECEC", "k. c #E2E2E2", "l. c #D3D3D3", "m. c #D0D0D0", "n. c #CDCDCD", "o. c #CCCCCC", "p. c #CACACA", "q. c #C8C8C8", "r. c #C7C7C7", ". . . . . . . . . . . . . . . . . . ", ". & & { 5 l # P n.r.z 6.R S .'.:.. ", ". & ! 2 g k s H f.r.y 7.T W ;.(.2.. ", ". , } c e j q O r.q.x 8.Z -.].1./.. ", ". ( 8 f 9 a t K r.o.F 9.>.{.|.<.).. ", ". 6 i 0 | 3 o K p.l.E 0._.:.[.~.*.. ", ". h b 4 ~ < o J m.v A a.3.2.^.@ &.. ", ". d 7 ] > / n I Q G D d.5./.,.%.+.. ", ". 9 : ' = ^ m N k.u B e.4.).=.#.Y . ", ". 1 ) - % _ r M j.h.w b.}.*.@.` V . ", ". ~ ; $ * [ p L i.g.C c.!.$...X U . ", ". . . . . . . . . . . . . . . . . . "}; xpn-1.2.6/pixmaps/supersede.xpm0000644000175000017500000000641111141275756014674 0ustar antant/* XPM */ static char * supersede_xpm[] = { "24 24 127 2", " c None", ". c #000000", "+ c #FEFEFE", "@ c #FDFDFD", "# c #E0E0E0", "$ c #C1C1C1", "% c #3B2929", "& c #2C1E1D", "* c #5A5A5A", "= c #F1F1F1", "- c #E2E2E2", "; c #242424", "> c #392120", ", c #2B1817", "' c #C3C3C3", ") c #FBFBFB", "! c #A8A8A8", "~ c #593C3B", "{ c #EF7C7A", "] c #F15756", "^ c #5B1817", "/ c #2D2D2D", "( c #8F504F", "_ c #E66563", ": c #E54947", "< c #2A0A09", "[ c #ADADAD", "} c #767676", "| c #5D5D5D", "1 c #404040", "2 c #664140", "3 c #F24544", "4 c #F2403E", "5 c #F13F3E", "6 c #591616", "7 c #8E4B4A", "8 c #E35F5D", "9 c #E13533", "0 c #DD3230", "a c #360C0B", "b c #F0F0F0", "c c #858585", "d c #4B4B49", "e c #161616", "f c #0E0808", "g c #C33736", "h c #EE3C3B", "i c #E93A38", "j c #E53736", "k c #E04B49", "l c #D82F2D", "m c #851C1B", "n c #313131", "o c #EFEFEF", "p c #EEEEEE", "q c #C5C5C5", "r c #1D1212", "s c #BA2D2B", "t c #E03432", "u c #DC3230", "v c #D42D2A", "w c #831B19", "x c #2C2C2C", "y c #B8B8B8", "z c #ECECEC", "A c #C4C4C4", "B c #2F2F2F", "C c #8B3A37", "D c #D93532", "E c #D42C2A", "F c #CF2A27", "G c #CC2725", "H c #4A0D0C", "I c #585858", "J c #C0C0C0", "K c #EBEBEB", "L c #EAEAEA", "M c #8A3835", "N c #D84844", "O c #CB2725", "P c #C82522", "Q c #C42220", "R c #C0201D", "S c #460B0A", "T c #474747", "U c #E9E9E9", "V c #E8E8E8", "W c #BFBFBF", "X c #5F2422", "Y c #D5423E", "Z c #CB2724", "` c #C72522", " . c #7B1614", ".. c #9C1A18", "+. c #BC1E1B", "@. c #B91C18", "#. c #B61A16", "$. c #210403", "%. c #E6E6E6", "&. c #E5E5E5", "*. c #BEBEBE", "=. c #5E1F1D", "-. c #C82724", ";. c #C3221F", ">. c #781412", ",. c #2B2B2B", "'. c #190F0F", "). c #931512", "!. c #B21814", "~. c #AF1612", "{. c #200403", "]. c #E7E7E7", "^. c #E4E4E4", "/. c #BDBDBD", "(. c #55100E", "_. c #470B0A", ":. c #D6D6D6", "<. c #B9B9B9", "[. c #180F0F", "}. c #4C0907", "|. c #350605", "1. c #464646", "2. c #E3E3E3", "3. c #BBBBBB", "4. c #C2C2C2", "5. c #BCBCBC", "6. c #A0A0A0", " ", " ", " ", " ", " ", " . . . . . . . . . . . . . . ", ". + + + + @ # $ . . + + + + @ # $ . ", ". % & * = - ; > , . . + = = = = ' ) ! . ", "~ { ] ^ * / ( _ : < . . + = = = = [ } | 1 . ", "2 3 4 5 6 7 8 9 0 a . . + = = = b - c d e . ", "f g h i j k 0 l m n . . + = o o o o p p q . ", ". r s t u l v w x y . . + o o p p p p z A . ", ". B C D E F G H I J . . @ K L L L L L L J . ", ". M N F O P Q R S T . . @ L L U U U V V W . ", "X Y Z ` ...+.@.#.$.. . @ V %.%.%.%.%.&.*.. ", "=.-.;.>.,.'.).!.~.{.. . @ ].].%.&.&.^.^./.. ", ". (._.,.:.<.[.}.|.1.. . @ %.&.^.^.2.2.2.3.. ", ". 4././.5.3.3.3.3.6.. . 4././.5.3.3.3.3.6.. ", " . . . . . . . . . . . . . . . . . . ", " ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/config-display.png0000644000175000017500000000674411141275756015576 0ustar antantPNG  IHDR00WbKGD IDATxYM\Uvν離qi2"Hh)IfUv !}&YΖ YdMlR"!A<nn޽Wq6dV^swιvP?ivx|9g9Y\&":3#v̺9-P$d3L[U⋪~rԩg^{^u'"^U+UKj3S3)%%EEz!ߨД5oϪAx7Vyc-s>̼JDn0]Շ~'d˗/*7PǮ^P3zLNUU_- "9+X Ȧiclc^3jf z{{:D"D*B iA1235[̒v 6ɹMx3[N){{{˗!e\_T1jiimooƍ]^в%X!bfL֎s Tu0Nz.~p8Xm7M):)HL#3sx5`%SUfU$*gm"j7~fN @w7n?'*3M &l)ĈB!%a$fpJb$fFu1 ƈT.U> Ŀ CY__O/$Um8@#r XBb̺Y`q4!%FL 12XB!`29B:tv1= Srޘ*rjP3Tu5uyc*"s䚺nHTIU@jH̘v12BJ躈!$RDBLHyrpC`H RHZ/|+ h *-UL7w'nжDD0" Uxݽ= @DB(WsUU 07WGr NR`͌s6-T̈́{|Kp ]_8 a# IrD3sN G";` rR7 c{2U%g@ JE ̜wB  o)!$(!X%f(I_ !u!NgK2 D f3ìԠf؟tXB3E.??8RH)"a C? )5jW8VWz((%AbE*&.C=D* AH>N`"繨TwhQ"-ω 9RͺȂ.D -F6/T@" Ą;ĸ?AׅSD ^G]{0sDzT1<\ -7ʩGfZ`,Lgf1Se*MpQE72VFCGCHNZ"fjBXJ-YW6N싩f] NKRXAEAy Q;{ft6éPUm-Qh|!"-9LHBU`0Q(sEB1hjx"L3D3#'34ÁzyPk|'lf1QBT!ȘUS'&愖̱ݼl82rMdھ3g ~C0뎶vvtyyyFD f._ܜ?^o߾kkkgj[ ݺuR)( Tes`kۖx G]/~Ei֟ 04M6reʹs瘙@4gf?޶+W {饗`flnn?O??q{ɓzyF'O^[neL+++i}}/]fY7nO9w @`f13uLS\v 9]^^Ƨ~J.f zxxh.\{g.\gϪsNo|SNٹsʕ+n{{677m4͛B U5"l_|Gd2I<#Ϟ}tiJXsfF=gR*.ٝzʽpxnxLo&f6t;;;/RxO=駟nT/sT՘9#"DĊ5lFD׺#%E;w'kmll_sΎN&,//k^Ԉ1f#"R'vf̽$"}BEF-x񢥔Ǭcuugȇg^q47?1Dd8]<\ c #D5D5D5", ", c #F1F1F1", "' c #F2F2F2", ") c #F3F3F3", "! c #ECECEC", "~ c #F4F4F4", "{ c #F5F5F5", "] c #DBDBDB", "^ c #F6F6F6", "/ c #F7F7F7", "( c #F8F8F8", "_ c #DCDCDC", ": c #DDDDDD", "< c #F9F9F9", "[ c #FAFAFA", "} c #DEDEDE", "| c #DFDFDF", "1 c #D6D6D6", "2 c #D7D7D7", "3 c #D8D8D8", "4 c #D9D9D9", "5 c #DADADA", "6 c #E0E0E0", " ", " ", " ", " ", " ", " ....... ", " .++++@. ", " .+#.$%. ", " .+..&%. ", " .+$.*=. ", " ......+&.-;. ", " .++++++...>...... ", " .+...$&*,')+++++. ", " .+#!.&*-,)~{...]. ", " .+...*-,'){^/(._. ", " .+.&*-,')~{/(..:. ", " .+...,')~{^/<[.}. ", " .+*-,')~{^/(...|. ", " .@=;>123445]_:|6. ", " ................. ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/it.xpm0000644000175000017500000000532211141275756013311 0ustar antant/* XPM */ static char * it_xpm[] = { "18 12 140 2", " c None", ". c #000000", "+ c #FFFFFF", "@ c #D03536", "# c #E8D5D6", "$ c #007000", "% c #006E00", "& c #004600", "* c #037103", "= c #037003", "- c #057305", "; c #097409", "> c #0D750D", ", c #0A510A", "' c #0F770F", ") c #107710", "! c #127A12", "~ c #137B13", "{ c #177B17", "] c #187E18", "^ c #115911", "/ c #1B811B", "( c #1F831F", "_ c #1F8220", ": c #196219", "< c #258425", "[ c #278827", "} c #216A21", "| c #2A752A", "1 c #389538", "2 c #389338", "3 c #327E32", "4 c #3A863B", "5 c #3B873B", "6 c #48A248", "7 c #50A950", "8 c #469446", "9 c #50A750", "0 c #57AE57", "a c #54A754", "b c #5EB35E", "c c #59A859", "d c #64B864", "e c #64B664", "f c #68BA68", "g c #65B465", "h c #6ABB6A", "i c #69B869", "j c #74C074", "k c #C2CAC2", "l c #C1C9C1", "m c #BEC6BE", "n c #BDC5BD", "o c #D2DAD2", "p c #C9D1C9", "q c #BEC5BE", "r c #CBD2CB", "s c #DAE1DA", "t c #EAF0EA", "u c #308F2F", "v c #3C943B", "w c #419C40", "x c #66B565", "y c #CDCDCC", "z c #EADBDA", "A c #D21B1B", "B c #DE2121", "C c #A31B1B", "D c #DB2727", "E c #AB2121", "F c #E82F2F", "G c #AE2323", "H c #B52626", "I c #B72828", "J c #EC3535", "K c #BA2A2A", "L c #E53635", "M c #BD2C2C", "N c #C32E2E", "O c #C02D2D", "P c #C83231", "Q c #C53030", "R c #CE3434", "S c #CD3434", "T c #CA3333", "U c #F23E3E", "V c #F44242", "W c #D53A3A", "X c #F74646", "Y c #EF4444", "Z c #DB3F3E", "` c #E04242", " . c #F84A4A", ".. c #D03F3E", "+. c #E44646", "@. c #F94D4D", "#. c #E94949", "$. c #F94F4F", "%. c #F95050", "&. c #F75050", "*. c #F14E4E", "=. c #ED4C4C", "-. c #F85151", ";. c #F45050", ">. c #F65151", ",. c #E04B4B", "'. c #F95958", "). c #ED5555", "!. c #F65B5B", "~. c #D0BDBD", "{. c #D6C3C3", "]. c #DECBCB", "^. c #F2E0E0", "/. c #FFEEEE", "(. c #FAE9E9", "_. c #FDEDED", ":. c #F6E6E6", "<. c #FEFEFE", "[. c #FCFCFC", "}. c #FAFAFA", "|. c #F9F9F9", "1. c #F8F8F8", "2. c #F5F5F5", "3. c #F2F2F2", "4. c #EEEEEE", "5. c #EBEBEB", "6. c #E8E8E8", "7. c #E4E4E4", "8. c #E1E1E1", "9. c #DEDEDE", "0. c #DBDBDB", "a. c #D8D8D8", "b. c #D6D6D6", "c. c #D4D4D4", "d. c #D2D2D2", "e. c #D1D1D1", "f. c #D0D0D0", "g. c #CECECE", "h. c #CDCDCD", "i. c #CCCCCC", ". . . . . . . . . . . . . . . . . . ", ". & & : 4 j t 8.d.i.i.~.A B J X %.. ", ". & ^ 3 g i s c.h.i.g.{.D F V $.;.. ", ". , | c e a r g.i.h.c.].L U @.>.#.. ", ". } 8 f 9 v l i.y e.0.# Y .-.=.Z . ", ". 5 h 0 2 < q i.f.a.7.^.&.%.*.` S . ", ". x b w _ { n g.b.8.4.(.'.;.+.@ Q . ", ". d 6 [ > ) m c.9.5.1./.!.#.W P M . ", ". 7 u ! = ' k 0.6.2.<._.).Z T O H . ", ". 1 ] - % ~ p 7.3.[.<.:.,.R N I E . ", ". ( ; $ * / o 4.}.+ |.z ..Q K G C . ", ". . . . . . . . . . . . . . . . . . "}; xpn-1.2.6/pixmaps/expand_all.xpm0000644000175000017500000000210111141275756014774 0ustar antant/* XPM */ static char * expand_all_xpm[] = { "24 24 24 1", " c None", ". c #000000", "+ c #D0D9E3", "@ c #B9C6D5", "# c #909DAC", "$ c #7590AE", "% c #5E738B", "& c #ADBCCE", "* c #9DB0C5", "= c #93A6BD", "- c #C4CEDC", "; c #7589A0", "> c #B6C4D3", ", c #93A0AD", "' c #617891", ") c #5A6F86", "! c #839BB5", "~ c #A5B6C9", "{ c #B8C5D4", "] c #6883A1", "^ c #869DB8", "/ c #A2B3C7", "( c #A5B2C0", "_ c #4E6074", " ... ", " .+@#. ", " .@$%. ", " .@$%... ", " .@$.+@#. ", " .@$.@$%. ", " ......@$.@$%... ", ".&*****=$.@$.+@#. ", ".-$$$$$$$.@$.@$%. ", ".;%%......@$.@$%... ", " ...&*****=$.@$%.>,. ", " .-$$$$$$$.@$%.$'. ", " .;%%......@$)...... ", " ...&*****=$!~{>>>,. ", " .-$$$$$$$$$$$$$'. ", " .;%%%%%$$]%%%%%%. ", " ......^$%....... ", " .>$./$%. ", " .(%.>$%. ", " ...>$%. ", " .>$%. ", " .(%_. ", " .... ", " "}; xpn-1.2.6/pixmaps/art_read.xpm0000644000175000017500000000074111141275756014456 0ustar antant/* XPM */ static char * art_read_xpm[] = { "18 16 5 1", " c None", ". c #000000", "+ c #E0E0E0", "@ c #FFFFFF", "# c #999999", " ....... ", " .+++++++. ", " .++++++++@. ", " .++++++++@@@. ", ".++++++++@@@@@. ", "..@@@@@@@@@@@.. ", ".@.@@@@@@@@@.@. ", ".@@.@@@@@@@.@@. ", ".@@@.@...@.@@@. ", ".@@@@.@@@.@@@@.# ", ".@@@.@@@@@.@@@.###", ".@@.@@@@@@@.@@.###", ".@.@@@@@@@@@.@.## ", "..@@@@@@@@@@@..## ", "...............# ", " ############### "}; xpn-1.2.6/pixmaps/config-misc.png0000644000175000017500000000661011141275756015054 0ustar antantPNG  IHDR00WbKGD =IDATx{pU_;NB7`eK 0c9:U(ʸ]QY nA.B1\LrNw.wg9C)-Oթ}>9|7١|ovkk%M\f b`?0]11}(S) >6 0zY+qI3W@qAN7.qnq~8_{H +uW^b ϋɓ*"WbzGJ bvO8:; CmjWb1`xrH~/}^&"~KB lz1ٱ.O@@5MJ 0"?=1jh8qjB̸H52 0 ϴV,Vt: !;>3=W}b@ѨN'li'{7mt4 Oe+d0a `7+>SimmWLVM-GŢBUTKH,;b?A4~q >6끇4NP"0"v?z稡Qчx5d쬫1AUՕ+qP,e%͢R}p@o֝m-Mƒ" KX0xqtu`ЛY||^w^esR;.}J  >"UxJ GoЗgڒϜ"d2)- 9QРAsB2˖khm95cyN@e vUJe2^9q-ngGՖmׇG5b"DC zPUABB2K'ia{cV_@FP\Xā q4 A2{TO?y96 ȴ1.' FHeG Y|"?=5t=hL*rś 49z+R\3&=C":xUٖV%'FvvV&ٌOWW+,(--mk)"^ QrO%i5:GKfO$$ݲSBD.m*g[ۆ? J zQON^k:&Io{DM;F5r}?K$&賿,JJJZp=ŷ/Mҙ<دI8/~LҮR[)SIАX4BiҬV:޴'~Ϋ)EFz~7]`}I>@ ͚̦qFB!gRSHfκ!W_Tl;8o!a@QI9j4B(bѢE} W ?t)Gyi s}h E`D_,XL`x/̝=7FАK(gמ=>/|R Su ~ PGM| K+2LOf3*P \<_n,6DBA?38)eS- F G@kzUqsU c'ќM*d]^:{:KDUF?ctѶZ/qt$ +啕D#1纘mg>/7l9S0qͧn_D{sseB0}8|ǎ D 8W=A|;וQ!)ǚےkN(eew/pxŶۅPcn_TZC~Q19ya ru\)'vԂ۴/U?.!#u=v"àSwmmF=C;SҗE< Ǜ lÆk/.#+;`8D@^[)(/Ğw^=EP(z7;{}Q%-rܛ*k[$}zK-D`MUTMUAi$rr Q4P2 xYx} UWC芋mc*(Ozy۠VRVD{a/DaY %eA"L+H#7M/psyNەPT,P()ed#;S^C &Q=GxF.m6r3ԣ -]j,Tؔx.Lq6qAp3Ot`K10qt}^IM01AFA.RDX42_nP;ƢըocZ rxO^6D>Go?ջ:&e1bv/_ww1ΔM) "$ dSJFvY3nY #\/\%^. @U#j``hh$BM(h$7NJB{&6~< GW#S#^xٽ>=8]81^ =9;F/Qc~^﷤Y4w3w04݇P/b>4us 9r3?lr{mnEasߍPIENDB`xpn-1.2.6/pixmaps/lower_score.xpm0000644000175000017500000000155511141275756015224 0ustar antant/* XPM */ static char * collapse_xpm[] = { "24 24 10 1", " c None", ". c #000000", "+ c #ADBCCE", "@ c #B6C4D3", "# c #93A0AD", "$ c #C4CEDC", "% c #7590AE", "& c #617891", "* c #7589A0", "= c #5E738B", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ............... ", " .+@@@@@@@@@@@@@#. ", " .$%%%%%%%%%%%%%&. ", " .*==============. ", " ................ ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/folder.xpm0000644000175000017500000000214311141275756014146 0ustar antant/* XPM */ static char * folder_xpm[] = { "16 16 50 1", " c None", ". c #000000", "+ c #E4E5DE", "@ c #D3D5CA", "# c #A5A797", "$ c #F3F4F0", "% c #ABAE99", "& c #BDC0AD", "* c #BCBEAA", "= c #B1B49F", "- c #6E715C", "; c #E6E7DD", "> c #F5F6F3", ", c #E4E5DB", "' c #E2E4D9", ") c #E1E3D8", "! c #DFE1D6", "~ c #C4C6B6", "{ c #F7F7F6", "] c #D3D6C5", "^ c #D3D6C4", "/ c #D2D4C2", "( c #D0D2C0", "_ c #CED1BD", ": c #CCCEBA", "< c #CACDB9", "[ c #C8CBB6", "} c #C6C9B3", "| c #C4C8B1", "1 c #93967C", "2 c #F0F0EB", "3 c #F0F1EC", "4 c #C3C6AF", "5 c #C1C4AD", "6 c #909478", "7 c #EFF0EB", "8 c #BFC2AB", "9 c #BDC1A8", "0 c #8E9175", "a c #EDEEE8", "b c #BBBEA5", "c c #BABDA3", "d c #8B8F72", "e c #ECEEE7", "f c #B7BAA0", "g c #E8E8E0", "h c #C6C9BA", "i c #8E9276", "j c #8C9073", "k c #646751", " ", " ", " .... ", " .+@@#. ", " .$%&*=-....... ", " .;>;;;,;''))!~.", " .{]^/(_:<<[}|1.", " .2]^/(_:<<[}|1.", " .3/(_:<[}}|456.", " .7_:<[}|445890.", " .a<[}|45889bcd.", " .e}|4589bbcffd.", " .g4589bcfffffd.", " .h6i0jdddddddk.", " ............. ", " "}; xpn-1.2.6/pixmaps/global_search.xpm0000644000175000017500000001351511141275756015465 0ustar antant/* XPM */ static char * global_search_xpm[] = { "24 24 291 2", " c None", ". c #32383C", "+ c #6F7980", "@ c #BCC5CB", "# c #D2D8DC", "$ c #DFE6EB", "% c #E8EFF4", "& c #CCD7DE", "* c #BDCBD5", "= c #A3B1BC", "- c #010305", "; c #B8BEC2", "> c #DFE8EF", ", c #DAE5ED", "' c #DCE7EE", ") c #E4EDF3", "! c #D9E4EC", "~ c #CCDBE5", "{ c #C2D3E0", "] c #C4D3DF", "^ c #D8E3EA", "/ c #A5B1BC", "( c #B8C3CA", "_ c #CFDBE5", ": c #C5D6E3", "< c #D3E2EC", "[ c #C7D9E5", "} c #C5D8E5", "| c #C2D4E1", "1 c #C4D6E2", "2 c #D4E1EA", "3 c #CDDAE4", "4 c #D4E1E9", "5 c #A9B6BF", "6 c #BDC8CE", "7 c #DAE6ED", "8 c #DDE8EF", "9 c #E1ECF3", "0 c #D1E1EB", "a c #C4DAE8", "b c #C1D7E6", "c c #BDD3E2", "d c #D9E5ED", "e c #D5E2EA", "f c #D0DEE7", "g c #CBD9E4", "h c #98ACB9", "i c #97A7B1", "j c #D6E2EB", "k c #DBE8EF", "l c #C6D7E3", "m c #C3D7E4", "n c #C0D9E8", "o c #C2DBEA", "p c #BCD5E5", "q c #B7D0E0", "r c #C7D8E3", "s c #D3E1EA", "t c #D0DFE9", "u c #CBDAE5", "v c #C6D6E1", "w c #B6CAD8", "x c #7B8F9F", "y c #60727F", "z c #C5D5E1", "A c #D1DFE8", "B c #D4E2EB", "C c #ACC2D3", "D c #AAC5D7", "E c #B4CEE0", "F c #B9D4E5", "G c #BAD5E6", "H c #B5D0E2", "I c #B6CFDF", "J c #D0E0EA", "K c #A2BACC", "L c #B8CBD9", "M c #BBCDDB", "N c #C0D2DE", "O c #B4C8D6", "P c #9AB3C6", "Q c #8498A7", "R c #A2B8C9", "S c #9EBACE", "T c #A5C1D5", "U c #A9C6DA", "V c #ACCADD", "W c #A8C6DB", "X c #ADC8DA", "Y c #CBDCE7", "Z c #B4C9D8", "` c #A3BACB", " . c #A3B9C9", ".. c #ABC1D1", "+. c #99B3C6", "@. c #728A9A", "#. c #070D13", "$. c #181E23", "%. c #899FAE", "&. c #7E98AD", "*. c #96AEC1", "=. c #87A5BB", "-. c #93B1C7", ";. c #97B6CD", ">. c #9BBBD1", ",. c #9DBDD4", "'. c #9DBDD3", "). c #C9DCE8", "!. c #C9DBE6", "~. c #C4D6E3", "{. c #BED2DF", "]. c #B8CDDA", "^. c #AAC0D0", "/. c #9FB8CB", "(. c #90AABE", "_. c #7990A1", ":. c #070D14", "<. c #141A20", "[. c #98B0C3", "}. c #86A2B8", "|. c #7292AB", "1. c #7E9EB7", "2. c #83A4BD", "3. c #88A9C2", "4. c #8BADC6", "5. c #8CAFC8", "6. c #9CBACF", "7. c #C4D8E5", "8. c #C1D4E2", "9. c #BCD0DE", "0. c #B6CBDA", "a. c #AFC5D5", "b. c #A4BDCE", "c. c #94AEC1", "d. c #95AFC2", "e. c #4E6A83", "f. c #070E14", "g. c #0A1117", "h. c #51718D", "i. c #87A2B7", "j. c #85A3B9", "k. c #95B0C5", "l. c #89A8BF", "m. c #7A9EB8", "n. c #799DB9", "o. c #7A9FBA", "p. c #799EBA", "q. c #8AAAC2", "r. c #BBD0DE", "s. c #B7CDDC", "t. c #B2C9D8", "u. c #ACC4D4", "v. c #A5BDCF", "w. c #9FB8CA", "x. c #91ABBF", "y. c #7691A8", "z. c #284969", "A. c #060C11", "B. c #080E14", "C. c #395C7B", "D. c #416686", "E. c #7895AD", "F. c #A8C0D1", "G. c #ADC5D5", "H. c #98B3C8", "I. c #6990AD", "J. c #668DAC", "K. c #6289A8", "L. c #8CA9BF", "M. c #A6BECF", "N. c #A0B9CC", "O. c #9BB4C7", "P. c #94AFC2", "Q. c #66839B", "R. c #264665", "S. c #050B10", "T. c #060A0E", "U. c #2D4C67", "V. c #3D6282", "W. c #708FA8", "X. c #A2BBCD", "Y. c #A6BED0", "Z. c #A9C2D2", "`. c #96B2C6", " + c #6F92AD", ".+ c #5A81A0", "++ c #59809F", "@+ c #537998", "#+ c #4A7090", "$+ c #587B98", "%+ c #A0B9CB", "&+ c #96B0C3", "*+ c #88A3B8", "=+ c #2A4967", "-+ c #1D3955", ";+ c #020609", ">+ c #25415A", ",+ c #365A7A", "'+ c #7492A9", ")+ c #9CB5C8", "!+ c #A3BBCD", "~+ c #4A708F", "{+ c #4F7595", "]+ c #4C7292", "^+ c #496E8F", "/+ c #436888", "(+ c #95AFC3", "_+ c #8FABBF", ":+ c #708DA4", "<+ c #254666", "[+ c #17314B", "}+ c #000000", "|+ c #2E5172", "1+ c #3D5F7D", "2+ c #8FA9BD", "3+ c #99B2C6", "4+ c #9DB7C9", "5+ c #748FA7", "6+ c #426787", "7+ c #446A8A", "8+ c #426788", "9+ c #3F6485", "0+ c #3B6080", "a+ c #809CB2", "b+ c #8EAABE", "c+ c #89A5BA", "d+ c #6A879F", "e+ c #1F3F5F", "f+ c #0B1824", "g+ c #1F3A53", "h+ c #2C4F6F", "i+ c #4A6A86", "j+ c #91ACC0", "k+ c #94AEC2", "l+ c #617E96", "m+ c #3B5F7F", "n+ c #395D7D", "o+ c #325676", "p+ c #7F9BB1", "q+ c #87A3B8", "r+ c #819FB5", "s+ c #25425E", "t+ c #102438", "u+ c #000103", "v+ c #020407", "w+ c #1F3C58", "x+ c #335473", "y+ c #8CA7BC", "z+ c #728DA4", "A+ c #2B4C6B", "B+ c #315575", "C+ c #315474", "D+ c #2F5273", "E+ c #2D5070", "F+ c #2A4C6C", "G+ c #587790", "H+ c #7E9DB3", "I+ c #5F7E95", "J+ c #132D47", "K+ c #04080D", "L+ c #25405B", "M+ c #7F9EB4", "N+ c #7B98AE", "O+ c #3D5A74", "P+ c #284A6A", "Q+ c #264868", "R+ c #244565", "S+ c #214262", "T+ c #33526E", "U+ c #48657C", "V+ c #192F46", "W+ c #03070C", "X+ c #2D4050", "Y+ c #3F5B75", "Z+ c #1D3C5C", "`+ c #1F405F", " @ c #1E3E5D", ".@ c #1C3B5B", "+@ c #1A3958", "@@ c #163554", "#@ c #0A1B2B", "$@ c #010204", "%@ c #060C15", "&@ c #0D2032", "*@ c #112941", "=@ c #163351", "-@ c #173554", ";@ c #15314F", ">@ c #102A44", ",@ c #0A1C2E", "'@ c #030A10", " ", " . . . . . . . . . ", " . + @ # $ % & * = . - ", " . ; > , ' ) ! ~ { ] ^ / - ", " . ( _ ' : < [ } | 1 2 3 4 5 - ", " . 6 7 8 9 0 a a b c d e 2 f g h - ", " . i j d k l m n o p q r s t u v w x - ", " . y z A B C D E F G H I J K L M N O P - ", " - Q N u R S T U V V W X J Y Z ` ...+.@.#. ", " $.%.&.*.=.-.;.>.,.,.'.).!.~.{.].^./.(._.:. ", " <.[.}.|.1.2.3.4.5.5.6.7.8.9.0.a.b.c.d.e.f. ", " g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.A. ", " B.C.D.E.F.G.H.I.J.J.K.L.w.c.M.N.O.P.Q.R.S. ", " T.U.V.W.X.Y.Z.`. +.+++@+#+$+%+O.&+*+=+-+;+ ", " . >+,+'+)+%+!+v.M.~+{+]+^+/+c.(+_+:+<+[+}+ ", " - |+1+2+3+)+4+5+6+7+8+9+0+a+b+c+d+e+f+}+ ", " - g+h+i+j+k+&+l+0+m+n+,+o+p+q+r+s+t+u+ ", " v+w+x+c+y+z+A+B+C+D+E+F+G+H+I+J+- }+ ", " K+L+M+N+O+P+P+P+Q+R+S+T+U+V+W+}+ ", " - X+Y+Z+e+`+e+ @.@+@@@#@$@}+ ", " }+%@&@*@=@-@;@>@,@'@}+}+ ", " }+}+}+}+}+}+}+}+ ", " ", " "}; xpn-1.2.6/pixmaps/config-servers.png0000644000175000017500000000374211141275756015615 0ustar antantPNG  IHDR00WbKGDIDATxKl~cbm$bD` j(D-«X "Y`E؁"5HL&hCv7[upUe7G{ν****w"omo^999) ÐaH]e>/lrqqQɞ hg'Oaض흻 k.__"d!IJk0hjjbbbnmUeI˲B ! r2l6+GFFHBt:-ވ:CCCRu955UNO>EQ AwY)) He d_av˗ɧkO֬Auhmm:l6[btI ,85!:7&&}K)P0JV dYRrP\.rxUQB! ,R i^Ϳam Jݼ{cBBmW4=WUuY߷hRFzP(H1:pˍ`0Xl3C7l,wkZZZ0Mb4McvvvE1޶mEh  ISXykP˃rSUKB`KI@UAQ@J,v.B}|m0 7PHt*߯^ogΔ.?| /rbYOJ299IKKKISa6r߻wSN]=}BH$4!٦p8L*bϞ=e }=3M$c\4 e-yJ?€bDKmZ 4(;ގ߷o芭F`0ay,"xmB;yH$7iCqjBaZDIe|s 1:V1R)BMx V}d従e@*_ IENDB`xpn-1.2.6/pixmaps/send.xpm0000644000175000017500000000145411141275756013630 0ustar antant/* XPM */ static char * send_xpm[] = { "24 24 6 1", " c None", ". c #000000", "+ c #FFFFFF", "@ c #FF9966", "# c #FF6633", "$ c #999999", " ", " .. ", " .+.. ", " .@+.. ", " ......@++. ", " .......#####@@@#...... ", " ..++++......@##.++++.. ", " .+.++++++++.@#.++++.+. ", " .++.+++++++.#.++++.++. ", " .+++.++++++..++++.+++. ", " .++++.++++++++++.++++. ", " .+++++.++++++++.+++++. ", " .++++++.++++++.++++++. ", " .++++++..++++..++++++. ", " .+++++.++.++.++.+++++.$", " .++++.++++..++++.++++.$", " .+++.++++++++++++.+++.$", " .++.++++++++++++++.++.$", " .+.++++++++++++++++.+.$", " ..++++++++++++++++++..$", " ...................... ", "$$$$$$$$$$$$$$$$$$$$$$$ ", "$$$$$$$$$$$$$$$$$$$$$$$ ", " "}; xpn-1.2.6/pixmaps/art_unread.xpm0000644000175000017500000000067311141275756015025 0ustar antant/* XPM */ static char * art_unread_xpm[] = { "18 16 1 1", " c None", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/about.xpm0000644000175000017500000000166511141275756014015 0ustar antant/* XPM */ static char * about_xpm[] = { "24 24 15 1", " c None", ". c #000000", "+ c #EEF63E", "@ c #EAF13D", "# c #F0F83F", "$ c #C9D034", "% c #E9F03D", "& c #E5EC3C", "* c #E8F03D", "= c #A9AE2C", "- c #ECF33E", "; c #EFF73F", "> c #CED636", ", c #B1B72E", "' c #CCD334", " ", " . . ", " .+. .+. ", " ..@#$.. ..@#$.. ", " .######%. .######%. ", " .####&. .####&. ", " .*###=. .*###=. ", " .#-.;>. .#-.;>. ", " .,. .'. .,. .'. ", " . . . . ", " ", " ", " ", " . . ", " .+. .+. ", " ..@#$.. ..@#$.. ", " .######%. .######%. ", " .####&. .####&. ", " .*###=. .*###=. ", " .#-.;>. .#-.;>. ", " .,. .'. .,. .'. ", " . . . . ", " ", " "}; xpn-1.2.6/pixmaps/search.xpm0000644000175000017500000001100411141275756014134 0ustar antant/* XPM */ static char * find_xpm[] = { "24 24 207 2", " c None", ". c #000000", "+ c #D3D3D3", "@ c #F6F6F6", "# c #FFFFFF", "$ c #F9F9F9", "% c #DADADA", "& c #585858", "* c #C7C7C7", "= c #D1D1D1", "- c #D6D6D6", "; c #FEFEFE", "> c #FDFDFD", ", c #C0C0C0", "' c #E1E1E1", ") c #F0F0F0", "! c #9B9B9B", "~ c #FCFCFB", "{ c #FBFBFB", "] c #AFAFAE", "^ c #E9E9E9", "/ c #DFDFDF", "( c #8F8F8F", "_ c #FAFAF9", ": c #F9F9F8", "< c #A4A4A3", "[ c #F4F4F4", "} c #CFCFCF", "| c #A2A2A2", "1 c #B8B8B8", "2 c #47473F", "3 c #0A0A09", "4 c #4B4B43", "5 c #B4B4B3", "6 c #F7F6F5", "7 c #9E9E9E", "8 c #A9A9A8", "9 c #34342E", "0 c #9D9D8D", "a c #CFCFB9", "b c #C4C4AF", "c c #8D8D7F", "d c #353530", "e c #ACACAA", "f c #F1F0EF", "g c #DEDDDC", "h c #D3D2D0", "i c #B7B7B5", "j c #9F9E9D", "k c #706F6F", "l c #65625A", "m c #46463F", "n c #9C9C8C", "o c #E2E2D0", "p c #EDEDE7", "q c #C0C0AC", "r c #B2B29F", "s c #828274", "t c #4C4C44", "u c #E4E4E2", "v c #E1E1DF", "w c #DAD9D7", "x c #D8D8D6", "y c #CDCCCA", "z c #AFAEAC", "A c #88847B", "B c #F8F8F7", "C c #090908", "D c #D5D5BF", "E c #FBFBFA", "F c #C3C3AE", "G c #B5B5A2", "H c #A6A695", "I c #9C9C8F", "J c #080807", "K c #CFCFCD", "L c #E3E2E0", "M c #ECEBE9", "N c #E9E8E6", "O c #D5D4D3", "P c #C4C3C2", "Q c #8F8A81", "R c #F6F5F4", "S c #F3F3F1", "T c #090909", "U c #CACAB5", "V c #DDDDD0", "W c #B7B7A4", "X c #AAAA98", "Y c #9B9B8B", "Z c #AEAEA3", "` c #BBBAB9", " . c #E8E7E5", ".. c #E5E4E2", "+. c #E4E3E0", "@. c #D2D1CE", "#. c #8D887E", "$. c #F4F3F2", "%. c #F0EFEE", "&. c #474740", "*. c #929283", "=. c #BABAA7", "-. c #ADAD9B", ";. c #9F9F8E", ">. c #ACACA1", ",. c #CFCFCB", "'. c #4C4C45", "). c #B3B2B1", "!. c #E2E1DE", "~. c #E1DFDC", "{. c #979288", "]. c #949493", "^. c #34342F", "/. c #878779", "(. c #A0A090", "_. c #AEAEA2", ":. c #C3C3BE", "<. c #010101", "[. c #B1B0AF", "}. c #D2D1CF", "|. c #A49E93", "1. c #F0F0EE", "2. c #EDEDEB", "3. c #DDDDDB", "4. c #898988", "5. c #414141", "6. c #737271", "7. c #A4A3A1", "8. c #DFDEDB", "9. c #E2E0DD", "0. c #E1E0DC", "a. c #E0DFDB", "b. c #A19C90", "c. c #E1E0DE", "d. c #CBCAC9", "e. c #B2B1B0", "f. c #A3A2A1", "g. c #9D9C9A", "h. c #9E9D9C", "i. c #9F9F9D", "j. c #ABAAA7", "k. c #DCDBD7", "l. c #DEDDD9", "m. c #DDDCD8", "n. c #A19B90", "o. c #EBEAE8", "p. c #E6E5E3", "q. c #C8C7C4", "r. c #B6B6B3", "s. c #B0AFAD", "t. c #B3B2B0", "u. c #747371", "v. c #9D9C99", "w. c #DAD9D5", "x. c #E7E6E3", "y. c #E6E5E2", "z. c #E3E2DF", "A. c #DBDAD7", "B. c #D4D3D0", "C. c #D0CFCB", "D. c #D1CFCC", "E. c #D1D0CC", "F. c #C9C8C4", "G. c #6B6B69", "H. c #CECDC9", "I. c #D6D4D0", "J. c #9F998D", "K. c #E3E2DE", "L. c #E4E2DF", "M. c #DFDEDA", "N. c #D5D4D0", "O. c #C0BFBC", "P. c #7B7A78", "Q. c #BCBAB6", "R. c #CECCC8", "S. c #9D978C", "T. c #EDEDED", "U. c #E1E0DD", "V. c #E2E1DD", "W. c #DBDAD6", "X. c #BBB9B6", "Y. c #A6A4A1", "Z. c #9E9C99", "`. c #ACABA7", " + c #C7C5C2", ".+ c #9B9589", "++ c #E1DFDB", "@+ c #E0DEDA", "#+ c #DEDCD8", "$+ c #DAD8D4", "%+ c #BDBCB8", "&+ c #ACABA8", "*+ c #B2B1AD", "=+ c #C6C4C0", "-+ c #999388", ";+ c #999891", ">+ c #A39E92", ",+ c #A39D92", "'+ c #A39D91", ")+ c #A29C90", "!+ c #A19B8F", "~+ c #9D978B", "{+ c #989286", "]+ c #918C82", "^+ c #938D83", "/+ c #979286", "(+ c #666258", " ", " . . . . . . . . . . . . . ", " . + @ # # # # # # # # $ % & . ", " . @ # # # # # # # # # # * = - . ", " . # # # # # # # ; # ; > , ' ) ! . ", " . # # # # # ; > ~ > ~ { ] ^ # / ( . ", " . # # # ; > ~ { _ { _ : < ) # [ } | . ", " . # ; > ~ 1 2 3 3 4 5 6 7 . . . . . . . ", " . # ~ { 8 9 0 a b c d e f g h i j k l . ", " . # _ : m n o p q r s t u v w x y z A . ", " . # B 6 C D E F G H I J K L M N O P Q . ", " . # R S T U V W X Y Z 3 ` w ...+.@.#.. ", " . # $.%.&.*.=.-.;.>.,.'.).h !.+.!.~.{.. ", " . # $.%.].^./.(._.:.<.<.[.}.!.+.!.~.|.. ", " . # 1.2.3.4.4 3 3 5.6.<.<.7.8.9.0.a.b.. ", " . # 2.M c.d.e.f.g.h.i.<.<.<.j.k.l.m.n.. ", " . # o.N p.w q.r.z s.t.u.. <.<.v.w.k.n.. ", " . # x.y.y.z.A.B.C.D.E.F.G.<.<.<.H.I.J.. ", " . $ +.z.K.L.K.a.a.M.M.N.O.P.<.<.Q.R.S.. ", " . T.U.~.0.a.V.a.0.a.0.W.E.X.Y.Z.`. +.+. ", " . = ++@+M.l.a.l.@+l.@+#+$+R.%+&+*+=+-+. ", " . ;+>+|.,+'+,+b.)+b.)+!+n.~+{+]+^+/+(+. ", " . . . . . . . . . . . . . . . . . . ", " "}; xpn-1.2.6/pixmaps/collapse.xpm0000644000175000017500000000155511141275756014503 0ustar antant/* XPM */ static char * collapse_xpm[] = { "24 24 10 1", " c None", ". c #000000", "+ c #ADBCCE", "@ c #B6C4D3", "# c #93A0AD", "$ c #C4CEDC", "% c #7590AE", "& c #617891", "* c #7589A0", "= c #5E738B", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ............... ", " .+@@@@@@@@@@@@@#. ", " .$%%%%%%%%%%%%%&. ", " .*==============. ", " ................ ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/dialog-error.xpm0000644000175000017500000001017411141275756015264 0ustar antant/* XPM */ static char * dialog_error_xpm[] = { "24 24 182 2", " c None", ". c #000000", "+ c #3F1106", "@ c #BE3A1C", "# c #E95327", "$ c #F45C2C", "% c #F7612E", "& c #F35A2A", "* c #E74C23", "= c #B93217", "- c #3B0B03", "; c #CB411E", "> c #F86731", ", c #F2602D", "' c #E65025", ") c #DC421F", "! c #D63A1A", "~ c #D33718", "{ c #D33719", "] c #D83C1C", "^ c #E0441F", "/ c #BB3016", "( c #290A04", "_ c #EA5729", ": c #F96731", "< c #E64E25", "[ c #D93B1B", "} c #D83C1B", "| c #D73B1B", "1 c #D6391A", "2 c #D43819", "3 c #D23618", "4 c #D03418", "5 c #CE3316", "6 c #CC3116", "7 c #CC3218", "8 c #240601", "9 c #EA5727", "0 c #F56330", "a c #E04620", "b c #DA3D1C", "c c #DB3E1C", "d c #D93C1B", "e c #D73B1A", "f c #D53819", "g c #D13518", "h c #CF3317", "i c #CD3116", "j c #CB2F16", "k c #C02A12", "l c #CA401E", "m c #DF4620", "n c #DC401C", "o c #DD401D", "p c #DC3F1D", "q c #D83B1B", "r c #D43719", "s c #D23519", "t c #D03318", "u c #CE3116", "v c #C92D14", "w c #9D1E0C", "x c #3E0E06", "y c #F86431", "z c #E44D24", "A c #DF421E", "B c #DA3E1C", "C c #D13618", "D c #CF3318", "E c #CC2F16", "F c #C22712", "G c #330802", "H c #BC3719", "I c #F25D2C", "J c #DC3F1C", "K c #CE3117", "L c #CB2F15", "M c #C92E15", "N c #C42913", "O c #89180A", "P c #E85025", "Q c #E44C22", "R c #D5391A", "S c #CE3818", "T c #BF3518", "U c #C13618", "V c #C23618", "W c #BE3417", "X c #BD3217", "Y c #BB2F16", "Z c #C03016", "` c #BD2F15", " . c #BC2D14", ".. c #CA2F16", "+. c #C52A12", "@. c #AE1E0D", "#. c #DA3F1E", "$. c #FFFFFF", "%. c #D7614D", "&. c #C92C15", "*. c #C62A13", "=. c #B8200D", "-. c #F65C2E", ";. c #D23719", ">. c #BB3116", ",. c #D6604D", "'. c #C82C13", "). c #C42912", "!. c #B8200E", "~. c #F15428", "{. c #BA2E16", "]. c #D5604D", "^. c #C62B13", "/. c #C22711", "(. c #B71E0D", "_. c #E44922", ":. c #D03417", "<. c #CF3418", "[. c #D64E35", "}. c #DC6650", "|. c #DB6550", "1. c #DA644F", "2. c #D9634F", "3. c #D8624E", "4. c #CE4632", "5. c #BF2411", "6. c #AB1C0C", "7. c #B62F14", "8. c #CE3217", "9. c #D03317", "0. c #CD3217", "a. c #CD3016", "b. c #C92D15", "c. c #C82C14", "d. c #C62B14", "e. c #B9200E", "f. c #851508", "g. c #3A0A03", "h. c #DF401E", "i. c #CC3016", "j. c #CC3017", "k. c #CA2F15", "l. c #C62A14", "m. c #C52913", "n. c #BE2410", "o. c #B61E0D", "p. c #2F0602", "q. c #B92C13", "r. c #C92E14", "s. c #CA2E15", "t. c #C82C15", "u. c #C82B14", "v. c #C02511", "w. c #B61E0E", "x. c #8E1609", "y. c #CA3016", "z. c #C82D14", "A. c #C72C14", "B. c #C52A13", "C. c #C52912", "D. c #BF2511", "E. c #B81F0D", "F. c #A91A0B", "G. c #240401", "H. c #BE2811", "I. c #C72C13", "J. c #C72B13", "K. c #C42812", "L. c #BD2310", "M. c #200300", "N. c #9B1D0C", "O. c #C12812", "P. c #C02611", "Q. c #BC2310", "R. c #B71F0E", "S. c #B51D0D", "T. c #330702", "U. c #871609", "V. c #B61D0D", "W. c #AA1B0B", "X. c #851308", "Y. c #2F0502", " ", " . . . . . . . ", " . + @ # $ % & * = - . ", " . ; > , ' ) ! ~ { ] ^ / . ", " ( _ : < [ } | 1 2 3 4 5 6 7 8 ", " . 9 0 a b c b d e f ~ g h i j k . ", " . l > m b n o p b q ! r s t u j v w . ", " x y z d c o A o B ] ! 2 C D u E v F G ", " . H I ! q c p o J b } ! r g h K L M N O . ", " . P Q R S T U V U T W X Y Z ` ...v +.@.. ", " . & #.2 X $.$.$.$.$.$.$.$.$.$.$.%.&.*.=.. ", " . -.;.{ >.$.$.$.$.$.$.$.$.$.$.$.,.'.).!.. ", " . ~.t g {.$.$.$.$.$.$.$.$.$.$.$.].^./.(.. ", " . _.:.<.[.}.}.}.}.}.|.1.2.3.%.,.4.*.5.6.. ", " . 7.R i 8.h D 9.9.h 8.0.a.L b.c.d.N e.f.. ", " g.h.E i.i i K 0.j.i.j k.b.c.l.m.n.o.p. ", " . q.r.k.j j L L ..s.b.t.u.^.m.v.w.x.. ", " . y.c.v b.b.b.z.c.A.^.B.C.D.E.F.. ", " G.H.^.d.I.J.J.^.B.C.K.L.(.F.M.. ", " . N.D.O.K.m.F P.Q.R.S.x.. . ", " . T.U.6.o.w.V.W.X.Y.. ", " . . . . . . . ", " ", " "}; xpn-1.2.6/pixmaps/layout_1.xpm0000644000175000017500000000140211141275756014425 0ustar antant/* XPM */ static char * layout1_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".+++...++++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++++++.+++.+++.+++.", ".++.++..+++.+++.....+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".+++...++++.+++.+++.+++.", ".++++++++++.+++++++++++.", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".++++++++++.+++++++++++.", ".+++++++++...++++++++++.", ".++++++++..+..+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.....+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_2.xpm0000644000175000017500000000140211141275756014426 0ustar antant/* XPM */ static char * layout2_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".++.+++.+++.++++...++++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++++++.", ".++.....+++.+++.++..+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.++++...++++.", ".++++++++++.+++++++++++.", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".++++++++++.+++++++++++.", ".+++++++++...++++++++++.", ".++++++++..+..+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.....+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_3.xpm0000644000175000017500000000140211141275756014427 0ustar antant/* XPM */ static char * layout3_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".++++.+++++.++++...++++.", ".+++...++++.+++.+++.+++.", ".++..+..+++.+++.+++++++.", ".++.+++.+++.+++.++..+++.", ".++.....+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.++++...++++.", ".++++++++++.+++++++++++.", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.....+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_4.xpm0000644000175000017500000000140211141275756014430 0ustar antant/* XPM */ static char * layout4_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".+++...++++.+++++.+++++.", ".++.+++.+++.++++...++++.", ".++.+++++++.+++..+..+++.", ".++.++..+++.+++.+++.+++.", ".++.+++.+++.+++.....+++.", ".++.+++.+++.+++.+++.+++.", ".+++...++++.+++.+++.+++.", ".++++++++++.+++++++++++.", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.....+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_5.xpm0000644000175000017500000000140211141275756014431 0ustar antant/* XPM */ static char * layout5_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".++.+++.+++.+++++.+++++.", ".++.+++.+++.++++...++++.", ".++.+++.+++.+++..+..+++.", ".++.....+++.+++.+++.+++.", ".++.+++.+++.+++.....+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++++++++++.+++++++++++.", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".+++++++++...++++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++++++++++++.", ".++++++++.++..+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".+++++++++...++++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_6.xpm0000644000175000017500000000140211141275756014432 0ustar antant/* XPM */ static char * layout6_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".++++.+++++.+++.+++.+++.", ".+++...++++.+++.+++.+++.", ".++..+..+++.+++.+++.+++.", ".++.+++.+++.+++.....+++.", ".++.....+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++++++++++.+++++++++++.", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".+++++++++...++++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++++++++++++.", ".++++++++.++..+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".+++++++++...++++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_7.xpm0000644000175000017500000000140211141275756014433 0ustar antant/* XPM */ static char * layout7_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".+++...++++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++++++.+++++++++++.", ".++.++..+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++.+++++.", ".+++...++++.++++...++++.", ".++++++++++.+++..+..+++.", "............+++.+++.+++.", ".++++++++++.+++.....+++.", ".++++++++++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.....+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_8.xpm0000644000175000017500000000140211141275756014434 0ustar antant/* XPM */ static char * layout8_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".+++...++++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++++++.+++++++++++.", ".++.++..+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++.+++.+++.", ".+++...++++.+++.+++.+++.", ".++++++++++.+++.+++.+++.", "............+++.....+++.", ".++++++++++.+++.+++.+++.", ".++++++++++.+++.+++.+++.", ".++++.+++++.+++.+++.+++.", ".+++...++++.+++++++++++.", ".++..+..+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.....+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/next.xpm0000644000175000017500000000247211141275756013656 0ustar antant/* XPM */ static char * next_xpm[] = { "24 24 41 1", " c None", ". c #000000", "+ c #8CA782", "@ c #B1CDAE", "# c #77A16E", "$ c #B4CEB1", "% c #ACC8A9", "& c #709867", "* c #C1D6BD", "= c #BDD3B8", "- c #BFD4BB", "; c #C2D7BE", "> c #B0CAAD", ", c #B2CBB0", "' c #AAC7A8", ") c #0F1308", "! c #AEC5A8", "~ c #AEC8AD", "{ c #ABC7A8", "] c #AAC6A7", "^ c #A8C6A5", "/ c #ADC8AD", "( c #A8C7A8", "_ c #A5C4A3", ": c #7F9F76", "< c #A6BFA0", "[ c #ABC7AA", "} c #A7C5A4", "| c #A9C7A6", "1 c #AFC8AD", "2 c #A4C3A2", "3 c #6B9060", "4 c #778E6F", "5 c #698D60", "6 c #6B9063", "7 c #445B2C", "8 c #6B8661", "9 c #5B7950", "0 c #6C8562", "a c #65815C", "b c #506B46", " ", " ", " ", " . ", " .. ", " .+. ", " .@#. ", " ........$%&. ", " .*=-;;;;>,'&) ", " .!~{{{]^'/(_:. ", " .<[^}^|{%'{123. ", " .45666666666657. ", " .8999999999997. ", " .099999999997. ", " .abbbbbb9997. ", " ........b97. ", " .b7. ", " .7. ", " .. ", " . ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/layout_9.xpm0000644000175000017500000000140211141275756014435 0ustar antant/* XPM */ static char * layout9_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".++++.+++++.+++++++++++.", ".+++...++++.+++++++++++.", ".++..+..+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.....+++.+++++++++++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++++++++++.+++.+++.+++.", "............+++.....+++.", ".++++++++++.+++.+++.+++.", ".++++++++++.+++.+++.+++.", ".+++...++++.+++.+++.+++.", ".++.+++.+++.+++++++++++.", ".++.+++++++.+++++++++++.", ".++.++..+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".+++...++++.+++++++++++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/collapse_all.xpm0000644000175000017500000000156111141275756015330 0ustar antant/* XPM */ static char * collpase_all_xpm[] = { "24 24 10 1", " c None", ". c #000000", "+ c #ADBCCE", "@ c #B6C4D3", "# c #93A0AD", "$ c #C4CEDC", "% c #7590AE", "& c #617891", "* c #7589A0", "= c #5E738B", " ", " ", " ", " ", " ", " ............... ", ".+@@@@@@@@@@@@@#. ", ".$%%%%%%%%%%%%%&. ", ".*==============. ", " .................. ", " .+@@@@@@@@@@@@@#. ", " .$%%%%%%%%%%%%%&. ", " .*==============. ", " .................. ", " .+@@@@@@@@@@@@@#. ", " .$%%%%%%%%%%%%%&. ", " .*==============. ", " ................ ", " ", " ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/expand.xpm0000644000175000017500000000207411141275756014155 0ustar antant/* XPM */ static char * exand_xpm[] = { "24 24 24 1", " c None", ". c #000000", "+ c #D0D9E3", "@ c #B9C6D5", "# c #909DAC", "$ c #7590AE", "% c #5E738B", "& c #5A6F86", "* c #ADBCCE", "= c #9DB0C5", "- c #93A6BD", "; c #839BB5", "> c #A5B6C9", ", c #B8C5D4", "' c #B6C4D3", ") c #93A0AD", "! c #C4CEDC", "~ c #617891", "{ c #7589A0", "] c #6883A1", "^ c #869DB8", "/ c #A2B3C7", "( c #A5B2C0", "_ c #4E6074", " ", " ", " ", " ... ", " .+@#. ", " .@$%. ", " .@$%. ", " .@$%. ", " .@$%. ", " ......@$&...... ", " .*=====-$;>,'''). ", " .!$$$$$$$$$$$$$~. ", " .{%%%%%$$]%%%%%%. ", " ......^$%....... ", " ./$%. ", " .'$%. ", " .'$%. ", " .'$%. ", " .(%_. ", " .... ", " ", " ", " ", " "}; xpn-1.2.6/pixmaps/delete.xpm0000644000175000017500000001210611141275756014135 0ustar antant/* XPM */ static char * delete_xpm[] = { "24 24 243 2", " c None", ". c #000000", "+ c #1C1C1C", "@ c #767676", "# c #E6E6E6", "$ c #D3D3D3", "% c #C3C3C3", "& c #909090", "* c #494949", "= c #48473D", "- c #BAB8A6", "; c #E2E2DF", "> c #F1F1F0", ", c #EAE9E6", "' c #F2F2EE", ") c #EBEAE5", "! c #C1C0B5", "~ c #57564A", "{ c #525146", "] c #A8A68F", "^ c #BDBBA1", "/ c #C0BEA3", "( c #A3A18A", "_ c #6D6C5C", ": c #7C7C72", "< c #4C4C49", "[ c #45453F", "} c #44433A", "| c #6F6F67", "1 c #C6C5B9", "2 c #B6B59B", "3 c #6D6C5D", "4 c #B3B19B", "5 c #A7A68E", "6 c #908F7A", "7 c #AAA993", "8 c #CCCBB5", "9 c #D0CEBA", "0 c #D5D3C1", "a c #AEADA3", "b c #94938A", "c c #454442", "d c #232321", "e c #353431", "f c #292823", "g c #1E1E1A", "h c #535246", "i c #ADAC93", "j c #929189", "k c #C2C1AF", "l c #B1AF96", "m c #ACAA92", "n c #93927D", "o c #080808", "p c #D1D0C1", "q c #D6D5C4", "r c #DFDED1", "s c #CECDC0", "t c #ACACA6", "u c #908F8A", "v c #7E7D77", "w c #5C5C55", "x c #47463E", "y c #656456", "z c #777665", "A c #807E6F", "B c #BEBDA7", "C c #B5B39A", "D c #A19F88", "E c #D9D8CC", "F c #F6F5F2", "G c #DBDAD1", "H c #DAD9CE", "I c #E5E4D9", "J c #D0CFC3", "K c #D3D3C9", "L c #CAC9BC", "M c #B7B6A6", "N c #B8B6A1", "O c #B0AF96", "P c #B9B89D", "Q c #B9B79D", "R c #B8B69C", "S c #C4C2A9", "T c #AFAD97", "U c #8B8976", "V c #AAA998", "W c #B6B6B2", "X c #F9F9F7", "Y c #FAFAF8", "Z c #F4F4F0", "` c #E2E1DA", " . c #D9D9CE", ".. c #DBDACF", "+. c #D3D1BE", "@. c #C5C4AC", "#. c #D6D5C3", "$. c #CDCCBF", "%. c #BBBAAD", "&. c #7C7A69", "*. c #717060", "=. c #131313", "-. c #999882", ";. c #AFAE9D", ">. c #C3C3BE", ",. c #DEDEDC", "'. c #E9E9E8", "). c #FBFBFA", "!. c #FDFDFC", "~. c #FDFDFD", "{. c #FCFBFA", "]. c #F2F2EF", "^. c #EAE9E3", "/. c #C0BFB1", "(. c #959484", "_. c #787766", ":. c #6E6D5D", "<. c #5B5B4D", "[. c #5D5C4F", "}. c #A3A293", "|. c #B8B7A6", "1. c #D8D7D0", "2. c #DBDBD4", "3. c #D3D2CA", "4. c #C8C8C3", "5. c #C6C5BD", "6. c #BDBCAD", "7. c #BAB8A8", "8. c #9F9E8B", "9. c #8E8C78", "0. c #8C8B77", "a. c #7A7968", "b. c #6C6B5D", "c. c #4E4D45", "d. c #424242", "e. c #7B7B73", "f. c #9F9F96", "g. c #D2D1C7", "h. c #DCDBD2", "i. c #CCCBBE", "j. c #D1D0C2", "k. c #C4C3B6", "l. c #9A9883", "m. c #807F6D", "n. c #7D7C6B", "o. c #6A695E", "p. c #40403E", "q. c #37372D", "r. c #0F0F0F", "s. c #383734", "t. c #787875", "u. c #999893", "v. c #8A897E", "w. c #B3B2A4", "x. c #AAAA9E", "y. c #878673", "z. c #8F8D79", "A. c #626155", "B. c #545451", "C. c #31312E", "D. c #2B2B23", "E. c #71715D", "F. c #57574B", "G. c #42423A", "H. c #262620", "I. c #212121", "J. c #1B1B1B", "K. c #242424", "L. c #161613", "M. c #2A2A22", "N. c #303027", "O. c #3F3F34", "P. c #7A7A65", "Q. c #5B5B51", "R. c #858576", "S. c #76766B", "T. c #98988E", "U. c #75756B", "V. c #515146", "W. c #7F7F74", "X. c #6A6A58", "Y. c #404035", "Z. c #626251", "`. c #545445", " + c #3E3E33", ".+ c #555546", "++ c #34342B", "@+ c #515143", "#+ c #85856E", "$+ c #5D5D54", "%+ c #919182", "&+ c #828278", "*+ c #AAAAA3", "=+ c #7A7A71", "-+ c #4E4E45", ";+ c #8A8A80", ">+ c #7C7C6D", ",+ c #424237", "'+ c #606052", ")+ c #5A5A4A", "!+ c #3C3C32", "~+ c #4E4E41", "{+ c #35352C", "]+ c #ACAC9C", "^+ c #85857B", "/+ c #BBBBB3", "(+ c #A3A39A", "_+ c #54544B", ":+ c #93938A", "<+ c #919185", "[+ c #686856", "}+ c #414136", "|+ c #434337", "1+ c #A4A493", "2+ c #C1C1B6", "3+ c #B1B1A2", "4+ c #6B6B5F", "5+ c #9D9D8B", "6+ c #848470", "7+ c #71715E", "8+ c #A5A594", "9+ c #C2C2B7", "0+ c #7B7B65", "a+ c #5F5F4F", "b+ c #666654", "c+ c #49493C", "d+ c #575748", "e+ c #57574A", "f+ c #7D7D6D", "g+ c #767669", "h+ c #B3B3A8", "i+ c #A1A194", "j+ c #6D6D61", "k+ c #B3B3A5", "l+ c #696957", "m+ c #414135", "n+ c #565647", "o+ c #444438", "p+ c #595951", "q+ c #585849", "r+ c #4E4E40", "s+ c #747467", "t+ c #616153", " . . . . . . ", " . + @ # $ % & * . . ", " . . . = - ; > , ' ) ! ~ { . . . ", " . ] ^ / ( _ : < [ } | 1 2 3 4 5 6 . ", " . 7 8 9 0 a b c d e f g h i j k l m n . ", " o p 8 q r s t u v w x y z A B C 2 C D . ", " . E F G H I J K L M N O D P Q R S T U . ", " . V W X Y Z ` ...0 +.S / @.#.$.%.&.*.. ", " =.-.;.>.,.'.).!.~.{.X ].^.G /.(._.:.<.. ", " . [.n }.|.1.2.3.4.5.6.7.8.9.0.9.a.b.c. ", " . d.e.f.g.h.i.j.k.l l l l.m.n.o.p.. ", " . q.r.s.t.u.v.w.x.( y.z.A.B.C.. D.. ", " . E.F.G.H.I.J.. K.. . . . L.M.N.O.. ", " . P.Q.R.S.T.U.V.W.X.Y.Z.`. +.+++@+. ", " . #+$+%+&+*+=+-+;+>+,+'+)+!+~+{+`.. ", " . #+Q.]+^+/+(+_+:+<+,+'+[+}+X.|+X.. ", " . #+Q.1+^+2+3+4+3+5+`.6+7+|+X.|+X.. ", " . #+Q.8+^+9+3+4+3+5+`.6+7+|+X.|+X.. ", " . #+Q.5+^+2+3+4+3+5+`.6+7+|+X.|+X.. ", " . 0+Q.1+^+2+3+4+3+5+`.6+7+|+X.|+a+. ", " . b+Q.1+&+2+3+4+3+5+`.6+7+|+X.c+d+. ", " . e+f+g+h+i+j+k+5+`.6+l+m+n+o+. . ", " . . . p+q+r+s+t+~+c+c+. . . ", " . . . . . . . . . . "}; xpn-1.2.6/pixmaps/xpn-logo-small.png0000644000175000017500000004635311141275756015537 0ustar antantPNG  IHDRQ@sBIT|dtEXtSoftwarewww.inkscape.org< IDATxweU[{sK:R%Р1|8AL4YHc 5X0H`aF h|x0(gjuW{9g5nzUuIauߺq3CD:?o4O/#ѰOV } 3 ¿6? |) 8osww1V3?J;#vn{08!4E]9:Kr'FEK1!0CbaLH#.0p`@Qe}?\c< x׺]?śF G뿛L:S潗}gA0VIPTuOtW.$ "{H(HEE:8 (&גBl[5G&V#P9&gO3h]/cԏcbjq>zв,0jvf*%6לm1wW+oV1$n=q=w>呷kȩ\a)CyH2_"A38I3r$˔I~Yi%DƄ}?EZrG}XHJHw-dVX, 1 HiY!# cK%dtl6{z0*Wd%plÒFʹ  d&ZhhqIcl /Ǫ~NL"nl3=̂ƯIčHH["-I$ -@Zk!/~ltؒ[UgUGЂŸZj/,nh. 71sH.<8&)ΔjǤFxPEZz,U͜W8L`ԤtX:aj&~\"aV.i}/jNI%WwzyK }sxk!^uwW}&e:o+7O ns/`*>[#;qJ2QubbD +Hd(rK :9k+' n;9ZлԐh foR8G+=p4 J?LŅ]bb皮NrYdS?W>Ng;KN(BD(ƆZ $&EeBq Yb>:(YTp<?|pſxϱb4Gx9#$Q ":D!ZF4#J-*D&ig=n9hOHP*ع/10[ֶX}C';`7ݐqgݠ:Bb!%Ւ JRM5EWZ IQK} /ǿ\c뿛.D$O_oޛ4~<ܫ V@29bʛWOBUw4*NFt!(rQ;C༑tAPB(dAQ ԚK\{:=RoR6cݱΏR k{lˏ{T{ѓ-cTr17"X\Z.mH4S>Co?JU|@;ղUY:ugw%WdRxpB.Qwf4zxdW7`prפsqF7ݓT=NIr fIAHLs oC_5wu"83%9yE`8J\!?&\3t4J.PV@  i@T"ᔀQx%x"14 H7w 2B͢7&d0Kxgs,/LJEaS;N4Ӓ\r(PI@$G$Zm[TiLտCDܸvg'/|hY.&b&&.\3g\ )Љ#b${i/;i?w#k:ƺf2&Xi#1X"F2C}kM,BJI( 9''5S3sQsG1JPsMǤKY>2KHz8;-¯O?Ծ<6ͅ o;e_ΥlYkRKgm9O-I;0WgUU6dQbO\X8#lPQ/8s8r/ѧ \z '.a-<?'Gr|\e xSL:\,e :pHK%RWD|@]J±#RJ X,:9lּHqG=@n=o#Inmq>' ^Jt[;ĝbI -+ji9} ?ş,w/8 #0ȿ5ξo8Dpm hn.h{PYWF)[Knp (ĈeiT3#jNW II1$E#jH)r%GQ8Te5!='hf <zbmJFA QEGz|GR5㱠J(=E28Iɥ;8! VJ-/nOBIk'a[cEMV[V~&=٭gꉍ_3G%Xeo+`^s5&YN|.J.xLn7+\Ws]8w N,A 8c%q.\tX%R2}5 T{eÞ&ŖOt}~Χ..Sdu=V' efk|-&Tm{ʉ{nDB'tw3"D %M t!Rwzke -`7oϚLrzAB$KA91 /u93Q-xiTd[[?^~_7a_t3Ic9 EC%¨.Qu4Nrv}?f}ej:Å#h +tǡyuEsBi8( !Nӝ |lj?ϻϜ9n7>O?"Ɛo|5^vsIU\g!Ad1xz$\LfnY ċC14rc€`Hlt0>zջv`mcp"V16,TWiH;F>;qv1bGKr@n1bWz+h 05mr ]dW&ew0\z8▇ Ndf jc .h^&M yM:I W~n";yr;Mmvo;wynĺI)B(pitXqt|c>c^?3c*]GDFn,E_1h(PШ8t'\|*Cdi?">c8FiAA&Sr 쾧"B).W{nF[?ýtO6!E8el*_$VP) ׄG*`q}Ar2[2b!+ :q8s[:[;~vz!lVuV\^7ťcNr5V+B-K>pAb4YlSDrSH6{CrJ $ޕ@КVszZ'^q'1{g_u/CŸSenr}?37ɝoEDNgч`v2q~v2#,bUʜ4$8J+Q-d>a99yw1iMXڿF/#$y!2 {# 1C!U(]nILU~ >4'z67 W )N T-d瘄sa?!9޵< W{?xsI_64G&*fIjReWJvJC0VY80\8 Z-\&DUτ|㝰vOQ=w1ݡa_j;o~N:s< >Hnr}-!VHUn@ŕ Oh6,x$rҒ=|K\w$ą^Op#q@9z:{}glJ[~)ڧ=:VY.-bZ!@3# ЕKs;kI*-͋ ѝD0\8"iFW˫&ʾM;$EӓLN[pVrarᒺZިŕm@IN54Ѕ&I 1'A p4C+ /.!h `wT(.1cwMv IDAT%6$X_8.u?ҵDz.ET鈗$1ҁb9IOez:۟ӟm"Idv{hՉ}fV'}%tT2~z%!KS ͭhcJ.l5P84ךkgn)rX_åx\z.|6MiJބR~$ѺWbgFZO37bh((gl?b[=V[ ,MKfZnnZe td# irb=We<6FCi<jy!V;Ӆ:gO]G2Isi]8’+}'H.J@p; NT֊׌}{}QǍ"`kyOosO~V!f%}υ 9Z 2J͒kAlVft)U>:&Q;磭lC!BM.)Ivډ}sb'u6uАR9ɇ{$HBu:Sxg숫CrF؃=J"f YQH aZY)kkc:!!G:jb|u{6UڨXrB3_@Wne/9藝X+26z<4bk];l%di`/ kE )3cG$㭼7sƩO?w ֩*HVCU@/ȼ0/BtR(>ۗO!p9\տxM-\k~O%kL,~/Y\YTg3$ᠳh i1buHnJMlvf)xh˩L2ݶH K"iKфt7%']‚,z+$ٺ.,-~L.%c[vđB# (YH IXɘdtF:Kn]#7KNrfO+WK+A[ y.].-@D*v{&)tfLs5 >RK₣}VÀ$Or=MJczukۍ?q5?";nXL^\PBE:MAjWr/l ~GO}ԋgtiuj/I(rG2Z.%Gm|:dGz]1 ]qvy:[d{<1)7E 9-Dz@(4L9Lm iD!E c Y-䎵Ϻw(I;PfǙ+,}FeY֤:%Aw}]' Ky^JvRN6 yoeFw_/s9>؅t =EZ>$|K`*1Z"[m![ˤ!q.eXrɜ/6w-C(>-$?=m#d_to9A(HZ;ljcD/1IsQr aZl(˩$Wo] EդNgD=]RDwg}Jr u0…1~L`۹8Jqud_)URrm"μ9n&Ý,=8bdWkHY>n#n*[rƛ}"O.|jm<ۻX?߽ܗrs鮒+k3Ʈ<]2ǵ-V#k!xcun׎h&1op,:`< {^C3)xL| b2 G|!G.'tF5[WcCcr|9Z4l-]x(U : > \dF`3K;ZT:,FBQD2jyw7KL)wAkȥӼdE7Qӈ߯zXXዸԳqE ]?mC?AТJ mWH%sF))#\Bmٴh|J q b^&S[ !P&)D)wKՙ \嫅ƹ+ʮE#W2N+c/xVX̌@A0' {@ޑ3;r-\ +TMɆRQoZm4!p.ŠFr'uob L"05Hiޫ`v?b^zē̓_}St&l(GhZ} } jQI](,tiiF#|ǂ$@:zH[ܓmWVSsh,ңNR 'ǫ4Hv`;."IyLIOHIXRz1hb+!ȱ'P\&+ `*g^D4L3~ɠgb]gN씭(+ٝGv6L =yvr{ H3 Mb0CvK< ˸wH j'͛ 2YMg yۜyxs߬ {8y#>]wԾ}i'+j4,(3˅gͅ&jp-t1(Fp9 t:m 4oqv_z|"72jqZӬ;`4\pDJu`pZ!!SH͕6@v.S{;EI:U-bk$8Wz8Fx H$Hsb ։o'M[_.?lqmdpxB5 Th[.Y.th?~4|r .>-uS;F0L ZrHSyZ仢w@\1Y`IO>k./w,[ǵyd RX4]XpCMܬ+rGNĤY`YF@v:$GۑpyN \ERby_sŕˆj@ܮqz&bFq8qz?l{'ˁ<OKi?A򲟝:uq^!p և QSJ ț#ݟ y<;HWPrQuW)CjMG~N2ncG\eLkbPtr0CCܒ*n q椴cզ A%c1o}H\j(g`|ԓBQ(!s9(E& ݑNcgo'R%Uk|r.cZPzbT/8,7nryɏpތ?3.^ Ab.?sWԅ#Mu9wj7u̾bq1\ĝ0qj95fږ-'_=z={"[ܕզ~E#nND/I@ؤTJ?oy+3;yo*#ųT<^Q/t:n&tSaita?޺ƻt0`逯Ԥq6l,"OBw͛s^a8ΟR'fCy| 'hӞ8H n*؄X.z/U9\ b|‡"- O!S+u3$\y4PuUo $ ,^a V|+ 9 lyhƧE墁]p[@Syj47s/M|xC&9hIڦ=힔ɦyS!~\z7Ot x+$"{o ɯ ka.*"TZE'WKТk_g<=OϞwD#dپlRמVT'RBlLgIE)&#LC>c{@UƩi 'Qd"+Cz"v.m 3-"(.Q\ǐD%MI : jzOLE5m]xHvBkϋ> 5m>6pyfd1 ݾ_=5RCDL ɯJZ5ҥZbŲ,%/Cgu0! @}chVrjvS-7Jj$Zufr ItX"1rJ#-< ,I߿bBQׂB$.U\Rԯ' js|ϣ;E^5w>B_Nߜ|}3_v3-WNVd !0Lsa+_̅ .v;'MG6ĢU21˅QT)}A`ozO*\-_x+(c֊8ѨC"eFssqa* ,HQy/X!2bDph%6Zh_I.<=4qg_J TkQ:0ZB Ї?][R >Bt@ty#3?eu qau{˿}v+ \u}f'Wc02 2l>UYuɘ0JÅ+PXuS!f,͘RMAԠbuLB)}b%8+)M37e h#z-L1n ZL,z[P1]lR%eelC{~sicqϯW4}Gp8h۪E=ov&^u>(?3d|Sy7_|rs!QrJ/n%WfB)$ DVߝ4%t DMh_<5GǪ Jıh DPnz$TܸYGn('fu]9%\ׁA.;7w ^,䑉h.D Zх| F7k?STbt+-PʼU +q?|̦)tG>"{Q M'8^ݲ[БiDZQ$8! E&qeQ֓#vq9U@nG,AsGZ/e?7"| p$Q*kxf*%ʻ>w3j8Lx˿kaȳDͨc!+|_{} '"7# N1g1 p[d-"yȤM슒"٧ʓ&0v$P̗ܡ9@[.$ZmUm]1Jy3 ǭ̘ܲr-k-u뿭U**CggL꧂eNsR$- ds48L P?;׍oz OY_q>hgiܜ<]xni]siP2VoT늈b. sS/jTHq >" NzwC\*ܜI%=Qo 17ׄ|OtzԪĘZ5n5d^ۄx$sYXWo1WTc2D+$JwyZYpl~.L#~Mr'}q;7EczJ/F0( ˅9W{MZB /Wg)t9iٻ"'کT dM]MeU`o ^S$O(uS34͵!5\f\1ʪD3 ׋FZ4T 'P;H]%S:-DEQdoZ:."8yjdZ9Lo!{~ ȉ׿+}x`pysJ]+(Y\S5a@mAt 7\W&[Ǣ8k%z v<0MpFw2> dܶËQʨU0hW~겦&q뭔6{GA+仞|(V4B[Y6n/-뺧f~8{dkCw=Ş': 1RJ>rw3NNS,iXl@pkگ=a݊X@~?r{+x|K#QJKCef}ao;O4FtoT[ںA;UK`(]8ԮZkj"H?n02btkAbҹH(3MD,mVqn{]Yk]aX~SLVV"e}5|EE|J;(A myC\*)`b$\&Xk0KS4M[g3xC@}I~ ?^H;_~o{kgQo+--[m(1M@|#jh@#⃢ ­⣔ȥv\ϥЮ.럙5kYkL{tx)p'7ŪLoR940\8;IS& MR*H#C:91 }#VV16޳bvʟ-3X#WYUwՈ׍<8[$DBx*Tgx[X* xHrp+i ֢# eIDATW. f b q@'~)t5ܝ+:ao݈}Nspۣ5JUy@ZZV$97Aܮ6Me|[1Q1tf,?: KNGMW?FS$SQэ4$m;Df޺3rȀT3//5K'̞h.k~B=ʜٻeoQ;>33 |g &`fhKt:¸ :]~8m9 0bHO;Ga* =T漟iq( HMytgB7n4 MLMVr5]lm"cׄ M<4 07[П*!0翷E [sJVv}c_|t^z╵$c\xMHCp#`V2;K@?Ɓ=ѹ.$G6|+\bv…kw\9 !_p"ڙ\g;ϵZTO Δ2ZvtduN;IZ_\|.s~9nN8 H_ }G ?IS$`D@@T͔ausbqɹpZɵzHǞ Ӈ>̜5oY 8y|5;?K0$ӻpsK+hBjn>Hˑ%/U aR'lIYN}>ؾDLj6tC] ?m"f{fUrO ŵ| ^uD{~΅6KC>ghI_[s"&@%FDGrjuN.+\8D숋 hGXUn5ִN3F.~[;ļTh< 9g l=G`0[mIc3;鏍[E X ֧{ W|.ҥ KΈF~hYJY[5KY8o`爔|5Iy:bK|SP eA|z" wi=Bk*[Džpja\=>V}=*#؁ĉ+]W~}Vxʨw?Պь86F*u)e[j V(߹c>]C|+2h IY_^KmXOm, {E?~T+=cTψ/ٷfy]GWJ nP\#cycYc17R,6.nywύ{nqSTualͦ+oh8fZ2?ANj%P iZ}S*]ɒZ"yյ؆kxoLYq'GYy}U6oڨ2haE (M@&2q zhU -y.x$~שpY4n)};=rx̯-uVؕ<jI un$N*qǹ]&d y=Sj%y D8U]rk_T c #7C7A72", ", c #DDDCDB", "' c #9A9992", ") c #53524E", "! c #171614", "~ c #767573", "{ c #9B9993", "] c #52504A", "^ c #7A7974", "/ c #86847D", "( c #9A9996", "_ c #B7B6B3", ": c #7D7B75", "< c #8A8883", "[ c #6B6964", "} c #78756C", "| c #5F5D56", "1 c #54534D", "2 c #403F3A", "3 c #E4E3E1", "4 c #E2E2E2", "5 c #B3B3B1", "6 c #484641", "7 c #9F9D96", "8 c #888781", "9 c #B0AFAD", "0 c #A8A7A1", "a c #908E86", "b c #97958E", "c c #807D74", "d c #595854", "e c #605E57", "f c #898883", "g c #76746B", "h c #43423F", "i c #282724", "j c #363430", "k c #6D6B63", "l c #E2E2E1", "m c #B6B5AF", "n c #21201E", "o c #0A0908", "p c #181816", "q c #E6E6E4", "r c #65635C", "s c #161614", "t c #8C8B89", "u c #DFDEDC", "v c #B0AFA9", "w c #D5D4D1", "x c #93918B", "y c #D6D5D2", "z c #ABA9A3", "A c #5D5C55", "B c #494943", "C c #42413C", " ... ", " ...+... ", " .@#$%&. ", " ..*=-;>.. ", " .,')!~{]. ", " ..^/(_:.. ", " .<[}|1.. ", " ...2... ... ", " ... .. .3. .. ", " .45.676.8.. ", " .90777abc6. ", " .77defcg. ", " ..67ehij7k6.. ", " ... .lm7dnopqcre. ", " ...+.....67fjstur6.. ", " .@#$%&. .vcmqwxr.. ", " ..*=-;>...yz7ccggA6. ", " .,')!~{]...d.6g6.B.. ", " ..^/(_:.. .. .C.... ", " .<[}|1.. ... ", " ...2... ", " ... ", " ", " "}; xpn-1.2.6/pixmaps/config-posting.png0000644000175000017500000000512211141275756015601 0ustar antantPNG  IHDR00WbKGD pHYs  tIME  !A+5tEXtComment(c) 2004 Jakub Steiner Created with The GIMPًo IDATx[l\}8qxR'ńBġQh_PՄFE*Ui()*-} @U6@ * @!1!$Ĺe>=3xI\^cieNy{/4@S2ox(3;^<>99I(7 9yo~x_v.{tw x;;;}jo̟Ξ>}]v{nz)g'A^xmƼybϞ=<#455΁}^E ^z%6oL,aσ>H0$sNE(.;bT*ŽK-a;DQք++ٰaht:M2DD"FD*4P>n*֤)ϟo˧f;u2B5tN!Hbr`Y2ҒFk!LЀd"haňx'IףFkM2dQ]iђqYR1њ[n(g+\w'mܸ[֬azwTx$7~ DTl޻#cc_HeXXSSugOxa Fp,T>֔eZ[5G7/ Εf2C"djj*M `SLC|*s0<xg?d3˴3J%~+;&~ rn^!顓E!_Lڵksר\MY9i1`(s|(>HsK >\!1>{dUyϻ3|P j D]QgQtdd[iSrG|Ͽ­4{ +FT-e+L'*C8T&O#},>:G!NqKE =9;:DDq=߽ljmصP @,'|<>Hss|/:1NB/'d)-[.O?MÒ&'&*(C;{ٺu+?UY1 -nSZk.M_bE vtu292D_ %p @)zb$IR6k)l!+\TVVfhPPh._̊4.o{]m-<|wc4* qy$   hq]RR,F34FHeWLBVCAOOOܷ֕i1cմf\ p  BKY(c2_0a,F Xzʕv\uJKkrZq Q0irp8 T6d[FQsSѮLlPJ8T+XP^˵24FrTvNS̀(e2*Ցjt^:b]X,ب_~_P8(%q"8(DuU'rQѤ^OX]ѾcVUޫe0l0NLp6|qӶSN8&L}5sQ$h_旞%))g˻S!4΄2]p/Μ PslYS(i$gRPБX<աd6:Wg(.OZ^:VT*GF hVYaRIENDB`xpn-1.2.6/pixmaps/art_delete.xpm0000700000175000017500000000620311141275756014775 0ustar antant/* XPM */ static char * art_delete_xpm[] = { "16 16 150 2", " c None", ". c #343434", "+ c #484848", "@ c #3B3B3B", "# c #202020", "$ c #000000", "% c #151411", "& c #69685E", "* c #CECECC", "= c #E6E6E4", "- c #DBDBD8", "; c #AAAAA4", "> c #393830", ", c #171714", "' c #626155", ") c #BEBCA5", "! c #BCBAA4", "~ c #898878", "{ c #5B5B55", "] c #3F3F3B", "^ c #43433B", "/ c #86867C", "( c #A09F89", "_ c #A3A290", ": c #A5A38C", "< c #545347", "[ c #050505", "} c #C7C6B3", "| c #D1D0BD", "1 c #D4D2C5", "2 c #AEAEA5", "3 c #6F6E6A", "4 c #55544F", "5 c #424239", "6 c #616052", "7 c #9A9886", "8 c #B6B5A0", "9 c #B4B299", "0 c #A4A28B", "a c #D1D0C6", "b c #E4E3DD", "c c #E6E6DE", "d c #DDDCD2", "e c #D3D3C8", "f c #C6C5B5", "g c #BEBCA6", "h c #AFAD95", "i c #BFBEA5", "j c #C0BFA8", "k c #B5B49F", "l c #8C8A77", "m c #0D0D0D", "n c #A5A492", "o c #C9C9C2", "p c #E9E9E7", "q c #F1F0EE", "r c #F1F1ED", "s c #F0EFE9", "t c #E9E8E0", "u c #DEDDD1", "v c #D0CFC0", "w c #B2B1A2", "x c #858474", "y c #686758", "z c #515146", "A c #8C8B7E", "B c #BCBCAF", "C c #DAD9D1", "D c #CFCEC5", "E c #C7C6BD", "F c #B8B7A4", "G c #ABA995", "H c #8F8D79", "I c #888774", "J c #6D6C5F", "K c #42413A", "L c #141411", "M c #363632", "N c #6E6E69", "O c #A7A6A0", "P c #AAA99C", "Q c #B6B6A9", "R c #A1A089", "S c #999781", "T c #6F6E61", "U c #52524A", "V c #282824", "W c #11110F", "X c #272720", "Y c #626253", "Z c #505047", "` c #464641", " . c #2F2F2C", ".. c #353532", "+. c #1F1F19", "@. c #1D1D18", "#. c #1E1E19", "$. c #313129", "%. c #38382E", "&. c #171713", "*. c #2B2B24", "=. c #69695B", "-. c #88887B", ";. c #97978F", ">. c #6B6B61", ",. c #74746A", "'. c #646456", "). c #565649", "!. c #4F4F41", "~. c #4A4A3D", "{. c #3F3F34", "]. c #1C1C17", "^. c #2C2C25", "/. c #9D9D8F", "(. c #AAAAA1", "_. c #8E8E84", ":. c #87877D", "<. c #7B7B6E", "[. c #606051", "}. c #5D5D4D", "|. c #505042", "1. c #23231D", "2. c #9A9A8B", "3. c #ADADA3", "4. c #9A9A8C", "5. c #858574", "6. c #747462", "7. c #626251", "8. c #68685A", "9. c #979787", "0. c #ADADA2", "a. c #22221C", "b. c #24241E", "c. c #616154", "d. c #99998A", "e. c #ACACA2", "f. c #4D4D40", "g. c #2B2B25", "h. c #525248", "i. c #7E7E74", "j. c #7C7C6F", "k. c #8A8A7D", "l. c #777767", "m. c #666656", "n. c #35352B", "o. c #141412", "p. c #22221E", "q. c #1E1E1A", "r. c #191915", "s. c #10100D", " . + @ # ", " $ % & * = - ; > , $ ", " ' ) ! ~ { ] ^ / ( _ : < ", " [ } | 1 2 3 4 5 6 7 8 9 0 $ ", " $ a b c d e f g h i j k l $ ", " m n o p q r s t u v w x y $ ", " z A B C D E F G H I J K ", " L M N O P Q R S T U V W ", " X Y Z ` ...+.@.#.$.%.&. ", " *.=.-.;.>.,.'.).!.~.{.]. ", " ^.=./.(._.:.<.[.}.}.|.1. ", " ^.=.2.3.4.4.5.6.7.}.|.1. ", " *.8.9.0.4.4.5.6.7.}.!.a. ", " b.c.d.e.4.4.5.6.7.}.f.#. ", " g.h.i.j.k.l.m.f.n.a.$ ", " $ o.].p.q.r.s.$ "}; xpn-1.2.6/pixmaps/art_ignore.xpm0000644000175000017500000000471211141275756015030 0ustar antant/* XPM */ static char * art_ignore_xpm[] = { "16 16 117 2", " c None", ". c #000000", "+ c #67331A", "@ c #B14F1F", "# c #D35213", "$ c #CC4C10", "% c #A03B0B", "& c #571F06", "* c #180B04", "= c #B75727", "- c #E75D17", "; c #E55913", "> c #E05713", ", c #D75112", "' c #CE4D10", ") c #C4480F", "! c #95360B", "~ c #130601", "{ c #B45525", "] c #E15914", "^ c #CE4F21", "/ c #CA4B1E", "( c #DD4D17", "_ c #DB4B17", ": c #CD4C1F", "< c #C64B23", "[ c #BB4512", "} c #8F320B", "| c #643119", "1 c #E15B19", "2 c #D85323", "3 c #EEE6E2", "4 c #EFE5E0", "5 c #CF5328", "6 c #CE5023", "7 c #EAE1DC", "8 c #F8F3F1", "9 c #D64F2A", "0 c #B43F0E", "a c #4E1A05", "b c #AA4516", "c c #DD4D16", "d c #D65320", "e c #F0E3DD", "f c #FFFFFF", "g c #F5EAE5", "h c #F0EBE8", "i c #FCFCFC", "j c #FAF3EF", "k c #D9522D", "l c #B33F0D", "m c #882E0A", "n c #CA4B0F", "o c #D84D14", "p c #D65223", "q c #F5F0EE", "r c #F5DED3", "s c #D95C37", "t c #D5461F", "u c #B13D0D", "v c #A5370B", "w c #C3470E", "x c #CD4C10", "y c #CE4E11", "z c #D25225", "A c #F2EDEA", "B c #F6E3DB", "C c #D15C35", "D c #C64115", "E c #AD3B0D", "F c #A1360B", "G c #99370B", "H c #C6480F", "I c #CD461E", "J c #EADDD7", "K c #FDFDFD", "L c #F4DDD3", "M c #F8EEEA", "N c #D44A25", "O c #A9390D", "P c #7A2807", "Q c #54200A", "R c #BC440F", "S c #C8441F", "T c #F2D9D2", "U c #F5E5DE", "V c #D25E36", "W c #C96A41", "X c #F5E8E2", "Y c #F7EDE9", "Z c #D84723", "` c #9F350B", " . c #3A1303", ".. c #923A13", "+. c #C24014", "@. c #D24A25", "#. c #D64B25", "$. c #C74316", "%. c #BF471B", "&. c #D04F2A", "*. c #D24C28", "=. c #CD421C", "-. c #712407", ";. c #120703", ">. c #8E3A17", ",. c #AF3E0F", "'. c #AE3C0D", "). c #A93A0D", "!. c #A6380C", "~. c #9E350B", "{. c #6D2307", "]. c #0C0300", "^. c #4B1906", "/. c #842C09", "(. c #9E340A", "_. c #752707", ":. c #361103", " ", " . . . . . . ", " . + @ # $ % & . ", " * = - ; > , ' ) ! ~ ", " . { ] ^ / ( _ : < [ } . ", " . | 1 2 3 4 5 6 7 8 9 0 a . ", " . b c d e f g h i j k l m . ", " . n o _ p q f f r s t u v . ", " . w x y z A f f B C D E F . ", " . G H I J K L L f M N O P . ", " . Q R S T U V W X Y Z ` .. ", " . ..+.@.#.$.%.&.*.=.-.. ", " ;.>.,.'.E ).!.~.{.]. ", " . ^./.F (._.:.. ", " . . . . . . ", " "}; xpn-1.2.6/pixmaps/receive_bodies_selected.xpm0000644000175000017500000001046711141275756017522 0ustar antant/* XPM */ static char * receive_bodies_selected_xpm[] = { "24 24 193 2", " c None", ". c #000000", "+ c #2A2A2A", "@ c #0F0F0F", "# c #080808", "$ c #E2E2E2", "% c #C1C1C1", "& c #9B9B9B", "* c #070400", "= c #B6B6B6", "- c #F3F3F3", "; c #F4F4F4", "> c #F5F5F5", ", c #F6F6F6", "' c #F7F7F7", ") c #DBDBDB", "! c #F0F0F0", "~ c #E4E4E4", "{ c #3A3535", "] c #FDFDFC", "^ c #070707", "/ c #E3E3E3", "( c #E5E5E5", "_ c #E6E6E6", ": c #E7E7E7", "< c #E8E8E8", "[ c #E9E9E9", "} c #EAEAEA", "| c #EBEBEB", "1 c #ECECEC", "2 c #EDEDED", "3 c #EEEEEE", "4 c #EFEFEF", "5 c #F2F2F2", "6 c #2D2929", "7 c #FDFAF8", "8 c #929292", "9 c #888888", "0 c #898989", "a c #8A8A8A", "b c #8B8B8B", "c c #8C8C8C", "d c #8D8D8D", "e c #8E8E8E", "f c #F1F1F1", "g c #D9D9D9", "h c #3A3636", "i c #F9F1EA", "j c #D0D0D0", "k c #353131", "l c #F9EEE4", "m c #4F4D4A", "n c #3F3F3F", "o c #808080", "p c #8F8F8F", "q c #131313", "r c #4E4A4A", "s c #F9F0E4", "t c #746C67", "u c #FEFDFC", "v c #EAE9E8", "w c #0B0A09", "x c #C7C7C7", "y c #F3F2F2", "z c #98948F", "A c #F9EFE3", "B c #A09489", "C c #FEFDFD", "D c #766D68", "E c #736961", "F c #A3A3A2", "G c #0C0C0C", "H c #909090", "I c #E8E5E2", "J c #97938E", "K c #F6E9D8", "L c #84817A", "M c #FBF3EA", "N c #908C86", "O c #F1EDE7", "P c #7B7975", "Q c #878786", "R c #060000", "S c #E2DFDC", "T c #A8A199", "U c #F0E0CE", "V c #C8BFB4", "W c #D5CCBF", "X c #DFD7CD", "Y c #DAD3C9", "Z c #DDCFC4", "` c #928C84", " . c #050000", ".. c #6B8661", "+. c #6C8562", "@. c #65815C", "#. c #919191", "$. c #030000", "%. c #D9D5D2", "&. c #D9CABB", "*. c #D7C8B8", "=. c #DECFBF", "-. c #D8C9B9", ";. c #E3D3C2", ">. c #C9BBAC", ",. c #D9CEC2", "'. c #7B7269", "). c #5B7950", "!. c #506B46", "~. c #F8F8F8", "{. c #B9B7B4", "]. c #8C8782", "^. c #C2B5A7", "/. c #BFB4A6", "(. c #B8AB9D", "_. c #BAAD9E", ":. c #BEB0A2", "<. c #948A7F", "[. c #56504A", "}. c #1D261A", "|. c #939393", "1. c #F9F9F9", "2. c #BDBDBD", "3. c #221D1C", "4. c #5D5954", "5. c #79736C", "6. c #958C80", "7. c #8D8379", "8. c #988D82", "9. c #625B55", "0. c #3F553A", "a. c #FAFAFA", "b. c #A8A8A8", "c. c #120F0F", "d. c #494442", "e. c #625C59", "f. c #625A53", "g. c #6B625A", "h. c #4F4A49", "i. c #212120", "j. c #688C60", "k. c #959595", "l. c #FBFBFB", "m. c #FCFCFC", "n. c #BCBCBC", "o. c #040000", "p. c #0C0303", "q. c #080000", "r. c #070000", "s. c #24211F", "t. c #859C82", "u. c #6B9063", "v. c #FDFDFD", "w. c #010000", "x. c #ECE4E2", "y. c #DED7D5", "z. c #D8D1D0", "A. c #E0DBD7", "B. c #E9E6E3", "C. c #FCFBFA", "D. c #030500", "E. c #FEFEFE", "F. c #201D1D", "G. c #0B0505", "H. c #14100F", "I. c #090806", "J. c #040503", "K. c #445B2C", "L. c #FFFFFF", "M. c #858585", "N. c #7A7A7A", "O. c #77A16E", "P. c #ACC8A9", "Q. c #B2CBB0", "R. c #ADC8AD", "S. c #AAC7A8", "T. c #818181", "U. c #DFDFDF", "V. c #CDCDCD", "W. c #709867", "X. c #A8C7A8", "Y. c #ABC7A8", "Z. c #D6D6D6", "`. c #C9C9C9", " + c #E1E1E1", ".+ c #CFCFCF", "++ c #A5C4A3", "@+ c #AFC8AD", "#+ c #0F1308", "$+ c #7F9F76", "%+ c #A4C3A2", "&+ c #6B9060", "*+ c #698D60", " . . + @ # . . . . . . . . . . . . . . . ", ". $ % & * = - - - ; ; ; > > > , , ' ' ; ) . ", ". ! ~ { ] ^ / ~ ( _ : < < [ } | 1 2 3 4 2 . ", ". 5 _ 6 7 . 8 9 0 0 a a b b c c d d e ! f . ", ". 5 g h i . j _ : < [ } | 1 1 2 3 4 ! f 5 . ", ". - / k l m . n # o b c c d d d e p p 5 - . ", ". = q r s t u . v w . x 2 3 4 4 ! f 5 - ; . ", ". . y z A B C D u E F G d e p p p H H ; > . ", ". . I J K L M N O P Q R . . . . 3 - ; > , . ", ". . S T U V W X Y Z ` ...+.@.. a #.8 , ' . ", ". $.%.&.*.=.-.;.>.,.'. .).).!.. ( ; ' ' ~.. ", ". $.{.].^./.(._.:.<.[.}.).).!.. 9 #.|.~.1.. ", ". 2.3.4.5.6.7.<.8.9.. 0.).).!.. _ , 1.a.a.. ", ". , b.c.d.e.f.g.h.i.$.j.).).!.. 0 8 k.l.m.. ", ". ' 2 n.o.p.q.r.. s.t.u.).).!.. _ , 1.l.v.. ", ". ' 3 w.x.y.z.A.B.C.D.u.).).!.. . . . . E.. ", ". ~.! F.G. .H.$.I.. J.u.).).).!.!.K.. : L.. ", ". ~.f M.N.. O.P.Q.R.S.u.).).).).K.. T.1 L.. ", ". 5 5 1 U.V.. W.S.X.Y.u.).).).K.. Z.} ~.1 . ", ". `.2 ' 3 +.+. W.++@+u.).).K.. Z.} ~.2 2.. ", " . . . . . . . #+$+%+u.).K.. . . . . . . ", " . &+*+K.. ", " . K.. ", " . "}; xpn-1.2.6/pixmaps/config-groups.png0000644000175000017500000000414311141275756015437 0ustar antantPNG  IHDR00WbKGD pHYs  ~tIME  ~{>tEXtCommentCreated with The GIMP (c) 2003 Jakub 'jimmac' Steiner'3XIDATx]LS[=0t(>DRRT`2pdcb|'abL&~\ 6(B&Ə8 ={8xz +9{Zk`GvdGvdGvdG~9?='*n|/h) @yk׮ }x{"Å<S.#ֆgoof~~KO%Gؘ=zyy666Ru\xsm׮]|>NN>͡Cx)P[[NbuuK.ihhΝ;8N;F<jCFGG,..&Fuu5}0kS<mMM9???j֭[tvvfIVWWinnB!\.x^LQplYdzyKKK1 }SN===n1|2.\Hc_N__,..244n!6 z>R^^N<x<H3(@n߂~8ѣ;wVWWٿ?}}}paCCCܽ{8TdH$-I)Xkccobbƍ)={pq={ŋߌ`CLYںZRRճٳgss]MyUkR1Mr4L&HZ!(((pf3>`|yyի{}kIJɪǽq EQhjjbee o 0`<@  8qDVTUE!D)%ccc)  KLcMMMh čC4/7/^`وb?9ާrՅbP]]>Fϐ*P7uttwvvZl6RJ{K4M co'ri~k~~7/5#F<طo`}}0Lahoo'fU^UՌ/L9NR#S]]MAAEEE&yjvvZ6BI?BD8NJBHgC>Ӹb?9իWWxb @c]]XV` 1ufΥlx]~Џ!v;p9JJJBIfD" <'mVH4Bii)_-//C۽v[Mf3X5jkk*INqqq?O +**XXXH;::PntS}}}#}糲ݻ),,۟zB(o?9PD"CT gkɓHUUm͛̀1c&ciy $x^*,,.%^?VTVV'5ƨQ ÇNNNO-DI,?+W,{ޓXBz E-K/lii+okkk|><877x< dk)P]%P!7sRC\k!d B/_|? `įVLkgNluRҖFB9B|)?5kiaߑM[ɠH!jy5{aN5(3"2ґm?ƀ\5V=U!cQKC^lSR^'U3ԃ䧔׳UMWKjwgZC<5J;#;#_@IENDB`xpn-1.2.6/pixmaps/receive_headers_selected.xpm0000644000175000017500000001107011141275756017657 0ustar antant/* XPM */ static char * receive_headers_selected_xpm[] = { "24 24 209 2", " c None", ". c #000000", "+ c #2A2A2A", "@ c #0F0F0F", "# c #080808", "$ c #E2E2E2", "% c #C1C1C1", "& c #9B9B9B", "* c #070400", "= c #B6B6B6", "- c #F3F3F3", "; c #F4F4F4", "> c #F5F5F5", ", c #F6F6F6", "' c #F7F7F7", ") c #DBDBDB", "! c #F0F0F0", "~ c #E4E4E4", "{ c #3A3535", "] c #FDFDFC", "^ c #070707", "/ c #E3E3E3", "( c #E5E5E5", "_ c #E6E6E6", ": c #E7E7E7", "< c #E8E8E8", "[ c #E9E9E9", "} c #EAEAEA", "| c #EBEBEB", "1 c #ECECEC", "2 c #EDEDED", "3 c #EEEEEE", "4 c #EFEFEF", "5 c #F2F2F2", "6 c #2D2929", "7 c #FDFAF8", "8 c #445E79", "9 c #304D6B", "0 c #314E6C", "a c #F1F1F1", "b c #D9D9D9", "c c #3A3636", "d c #F9F1EA", "e c #4D6177", "f c #2E4A66", "g c #2D4965", "h c #304C6A", "i c #353131", "j c #F9EEE4", "k c #4F4D4A", "l c #5E5E5E", "m c #0C0C0C", "n c #B2B2B2", "o c #C2C2C2", "p c #C3C3C3", "q c #C4C4C4", "r c #C6C6C6", "s c #D0D0D0", "t c #131313", "u c #4E4A4A", "v c #F9F0E4", "w c #746C67", "x c #FEFDFC", "y c #EAE9E8", "z c #0B0A09", "A c #29425B", "B c #F3F2F2", "C c #98948F", "D c #F9EFE3", "E c #A09489", "F c #FEFDFD", "G c #766D68", "H c #736961", "I c #A3A3A2", "J c #040609", "K c #E8E5E2", "L c #97938E", "M c #F6E9D8", "N c #84817A", "O c #FBF3EA", "P c #908C86", "Q c #F1EDE7", "R c #7B7975", "S c #878786", "T c #060000", "U c #E2DFDC", "V c #A8A199", "W c #F0E0CE", "X c #C8BFB4", "Y c #D5CCBF", "Z c #DFD7CD", "` c #DAD3C9", " . c #DDCFC4", ".. c #928C84", "+. c #050000", "@. c #71916E", "#. c #748A72", "$. c #8DB389", "%. c #030000", "&. c #D9D5D2", "*. c #D9CABB", "=. c #D7C8B8", "-. c #DECFBF", ";. c #D8C9B9", ">. c #E3D3C2", ",. c #C9BBAC", "'. c #D9CEC2", "). c #7B7269", "!. c #AECBAD", "~. c #AFCCAE", "{. c #C0D9BF", "]. c #F8F8F8", "^. c #B9B7B4", "/. c #8C8782", "(. c #C2B5A7", "_. c #BFB4A6", ":. c #B8AB9D", "<. c #BAAD9E", "[. c #BEB0A2", "}. c #948A7F", "|. c #56504A", "1. c #293228", "2. c #B1CEB0", "3. c #B4D2B3", "4. c #C5DFC4", "5. c #BCBCBC", "6. c #221D1C", "7. c #5D5954", "8. c #79736C", "9. c #958C80", "0. c #8D8379", "a. c #988D82", "b. c #625B55", "c. c #5C715A", "d. c #B5D3B4", "e. c #C6E0C5", "f. c #B0B0B0", "g. c #120F0F", "h. c #494442", "i. c #625C59", "j. c #625A53", "k. c #6B625A", "l. c #4F4A49", "m. c #212120", "n. c #99BC97", "o. c #B5D2B4", "p. c #B6D4B5", "q. c #C7E1C6", "r. c #040000", "s. c #0C0303", "t. c #080000", "u. c #070000", "v. c #24211F", "w. c #4F6448", "x. c #A0C39D", "y. c #D0E7D0", "z. c #0E0C0C", "A. c #ECE4E2", "B. c #DED7D5", "C. c #D8D1D0", "D. c #E0DBD7", "E. c #E9E6E3", "F. c #FCFBFA", "G. c #030500", "H. c #A1C69E", "I. c #FBFBFB", "J. c #FDFDFD", "K. c #221E1E", "L. c #0B0505", "M. c #14100F", "N. c #090806", "O. c #020402", "P. c #A1C69F", "Q. c #B8D7B7", "R. c #B9D7B8", "S. c #C0D5C0", "T. c #BFD4BF", "U. c #D6EAD6", "V. c #FEFEFE", "W. c #010101", "X. c #3E4F39", "Y. c #5D7555", "Z. c #617959", "`. c #657E5C", " + c #6A8561", ".+ c #B7D5B6", "++ c #F0FEEF", "@+ c #FFFFFF", "#+ c #0E0E0E", "$+ c #657F5C", "%+ c #A2C7A0", "&+ c #F1FFF0", "*+ c #303030", "=+ c #3F5239", "-+ c #637D5B", ";+ c #68835F", ">+ c #0B0B0B", ",+ c #C9C9C9", "'+ c #5C5C5C", ")+ c #41533C", "!+ c #66815E", "~+ c #9FC49D", "{+ c #B8D6B7", "]+ c #434343", "^+ c #BDBDBD", "/+ c #96B892", "(+ c #E8F4E6", "_+ c #1B1B1B", ":+ c #A5B4A4", " . . + @ # . . . . . . . . . . . . . . . ", ". $ % & * = - - - ; ; ; > > > , , ' ' ; ) . ", ". ! ~ { ] ^ / ~ ( _ : < < [ } | 1 2 3 4 2 . ", ". 5 _ 6 7 . 8 9 9 9 9 9 9 9 9 9 0 0 0 ! a . ", ". 5 b c d . e f g g g g g g g f h 0 0 a 5 . ", ". - / i j k . l m n % o p q r s $ 3 a 5 - . ", ". = t u v w x . y z . A 9 0 0 0 0 9 0 - ; . ", ". . B C D E F G x H I J f 0 0 0 h f 0 ; > . ", ". . K L M N O P Q R S T . . . . , ( ( > , . ", ". . U V W X Y Z ` ...+.@.#.$.. , , , , ' . ", ". %.&.*.=.-.;.>.,.'.).+.!.~.{.. , , , , ].. ", ". %.^./.(._.:.<.[.}.|.1.2.3.4.. , , , , ; . ", ". 5.6.7.8.9.0.}.a.b.. c.3.d.e.. , , , , a . ", ". > f.g.h.i.j.k.l.m.%.n.o.p.q.. , , , , , . ", ". , , q r.s.t.u.. v.w.x.d.p.y.. , , , , , . ", ". ' , z.A.B.C.D.E.F.G.H.p.p.q.. . . . I.J.. ", ". ' , K.L.+.M.%.N.. O.P.Q.Q.R.S.T.U.# J.V.. ", ". ]., a | W.X.Y.Z.`. +P.R..+R.Q.++. J.@+@+. ", ". ].a , , ( #+X.Z.$+ +%+R.p.Q.&+. a @+@+@+. ", ". 5 5 - ; > - *+=+-+;+P.R.p.&+>+J.@+@+@+1 . ", ". ,+2 ].> , ' ' '+)+!+~+{+&+]+V.@+@+@+3 ^+. ", " . . . . . . . . . )+/+(+. ^ . . . . . . ", " _+:+_+ ", " _+ "}; xpn-1.2.6/pixmaps/send_queued_mail.xpm0000644000175000017500000000216411141275756016201 0ustar antant/* XPM */ static char * send_queued_mail_xpm[] = { "24 24 27 1", " c None", ". c #000000", "+ c #C4D4E3", "@ c #2A435B", "# c #A6BED5", "$ c #3F6588", "% c #A3BCD4", "& c #AAC1D7", "* c #ABC2D8", "= c #29425A", "- c #FFFFFF", "; c #F2F2F2", "> c #E0E0E0", ", c #AEC4D9", "' c #C8C8C8", ") c #D1D1D1", "! c #FAFAFA", "~ c #CFCFCF", "{ c #E3E3E3", "] c #FCFCFC", "^ c #FBFBFB", "/ c #6892B9", "( c #2D4760", "_ c #D3D3D3", ": c #EDEDED", "< c #FDFDFD", "[ c #EFEFEF", " ", " ", " .. ", " .+@. ", " .+#$@. ", " .+%&$$@. ", "......*=....... .. ", "..-;>.,=.')--...+@. ", ".-.!;.%=.~{-.].+#$@. ", ".--.^./(._:.-.+%&$$@. ", ".---............*=......", ".----.---..--;>.,=.')-..", ".---.-.-..-.-!;.%=.~{.-.", ".--.---.-.--.-^./(._.--.", ".-.------.---.<.....[--.", "..-------.----.---.----.", "..........---.-.-.-.---.", " .--.---.---.--.", " .-.---------.-.", " ..-----------..", " ...............", " ", " ", " "}; xpn-1.2.6/pixmaps/exit.xpm0000644000175000017500000000672411141275756013655 0ustar antant/* XPM */ static char * exit_xpm[] = { "24 24 140 2", " c None", ". c #000000", "+ c #D6D6D4", "@ c #BDBDBC", "# c #A8A8A4", "$ c #92928F", "% c #727370", "& c #61615E", "* c #20201F", "= c #F1F1EF", "- c #E6E6E4", "; c #DADAD7", "> c #CFCFCD", ", c #C4C4C1", "' c #A8A8A5", ") c #767674", "! c #777774", "~ c #1E1E1D", "{ c #B9B9B7", "] c #AEAEAC", "^ c #8F8F8D", "/ c #262626", "( c #414140", "_ c #E9836C", ": c #DEDEDC", "< c #C5C5C2", "[ c #636362", "} c #040504", "| c #040604", "1 c #050705", "2 c #E87B62", "3 c #E67056", "4 c #D5D5D3", "5 c #DBDBD8", "6 c #D0D0CE", "7 c #080A07", "8 c #0A0C09", "9 c #0A0D09", "0 c #0B0E0A", "a c #F0B0A1", "b c #EB8D77", "c c #DF421E", "d c #E97E66", "e c #CBCBC8", "f c #0C0F0B", "g c #0F130D", "h c #10140E", "i c #11150F", "j c #EFA392", "k c #BFBFBD", "l c #5D5D5C", "m c #10150F", "n c #141912", "o c #161C14", "p c #171D15", "q c #B7B7B4", "r c #0C0C0C", "s c #192017", "t c #1C2319", "u c #1D241A", "v c #CD8484", "w c #990000", "x c #701616", "y c #A6A6A5", "z c #181E16", "A c #1E261B", "B c #212A1E", "C c #222B1F", "D c #4F0000", "E c #AEAEAB", "F c #1D261B", "G c #242E21", "H c #273224", "I c #283325", "J c #580000", "K c #B5B5B3", "L c #293426", "M c #2D3929", "N c #2E3A2A", "O c #7C4343", "P c #6A0000", "Q c #720000", "R c #BDBDBB", "S c #232C20", "T c #2A3526", "U c #303C2B", "V c #33402E", "W c #C5C5C3", "X c #1E261C", "Y c #303D2C", "Z c #374532", "` c #394834", " . c #500000", ".. c #CDCDCB", "+. c #1B2319", "@. c #253022", "#. c #303E2D", "$. c #394934", "%. c #3D4E38", "&. c #9D9D9B", "*. c #565655", "=. c #2C3828", "-. c #40503A", ";. c #43553E", ">. c #BABAB7", ",. c #777776", "'. c #323830", "). c #232C1F", "!. c #313E2D", "~. c #3B4A36", "{. c #43553D", "]. c #485B42", "^. c #4A5E44", "/. c #F0F0EE", "(. c #E5E5E3", "_. c #C6C6C3", ":. c #ACACAB", "<. c #8B8B8A", "[. c #32392F", "}. c #2C3728", "|. c #3F503A", "1. c #465840", "2. c #4B5E44", "3. c #4E6347", "4. c #506549", "5. c #DADAD8", "6. c #7A7D78", "7. c #333C30", "8. c #475A41", "9. c #4F6348", "0. c #53694C", "a. c #566C4E", "b. c #576D4F", "c. c #91968F", "d. c #3B4736", "e. c #42543C", "f. c #51674A", "g. c #586F50", "h. c #5B7353", "i. c #5C7454", " ", " . . . . . . . . . . . . . . . . ", " . + @ # $ % & & & * . . . . . . ", " . = - ; > , ' ) ! ~ . . . . . . ", " . . = - ; > , { ] ^ / . . . . . . ", " . . . = - ; > , { { { ( . . . . . . ", " . _ . : - ; > < { { { [ } | 1 1 1 . ", ". . . . . . 2 3 . 4 5 6 < { { { [ 7 8 9 0 0 . ", ". a 2 2 2 2 b c d . e 6 < { { { [ f g h i i . ", ". j c c c c c c c 3 . k < { l { [ m n o p p . ", ". j c c c c c c c c 3 . q { l r [ n s t u u . ", ". v w w w w w w w w w x . y r { [ z A B C C . ", ". v w w w w w w w w D . E { { { [ F G H I I . ", ". v w w w w w w w J . K < { { { [ C L M N N . ", ". O P P P P Q w J . R 6 < { { { [ S T U V V . ", ". . . . . . Q J . W 5 6 < { { { [ X H Y Z ` . ", " . .. ..- 5 6 < { { { [ +.@.#.$.%.. ", " . . . = - 5 6 < { ] &.*.B =.Z -.;.. ", " . . = - 5 6 >.&.,.'.).!.~.{.].^.. ", " . /.(._.:.<.[.}.Z |.1.2.3.4.4.. ", " . 5.k 6.7.Z -.8.9.0.a.a.b.b.b.. ", " . c.d.e.^.f.g.h.i.i.i.i.i.i.i.. ", " . . . . . . . . . . . . . . . . ", " "}; xpn-1.2.6/pixmaps/folder_open.xpm0000644000175000017500000000247211141275756015174 0ustar antant/* XPM */ static char * folder_open_xpm[] = { "16 16 64 1", " c None", ". c #000000", "+ c #E4E5DF", "@ c #D5D6CB", "# c #D6D7CA", "$ c #A3A39D", "% c #F5F6F0", "& c #8D907B", "* c #92957E", "= c #90937D", "- c #979B84", "; c #6D705F", "> c #EAECDB", ", c #8A8C7D", "' c #8E917B", ") c #91947F", "! c #8B8E7A", "~ c #999B87", "{ c #919480", "] c #989B86", "^ c #B1B4A2", "/ c #A2A394", "( c #F7F7F7", "_ c #878A75", ": c #666858", "< c #4B4D3F", "[ c #4D4F40", "} c #404135", "| c #424337", "1 c #434437", "2 c #404236", "3 c #3C3D32", "4 c #48493C", "5 c #1A1A16", "6 c #C6C6BE", "7 c #848672", "8 c #25261F", "9 c #F1F2E9", "0 c #DDE0C7", "a c #D6DABB", "b c #CDD2AC", "c c #C7CCA7", "d c #989C80", "e c #C6C7BE", "f c #5F6152", "g c #888980", "h c #A7AB8C", "i c #878A70", "j c #9FA19A", "k c #EFF0E5", "l c #9EA284", "m c #80817B", "n c #96968D", "o c #E3E5D1", "p c #83866D", "q c #97998D", "r c #EDEFE2", "s c #A2A688", "t c #767671", "u c #E7E9DA", "v c #D1D3BD", "w c #BBBF9D", "x c #989B80", "y c #6E715C", " ", " ", " .... ", " .+@#$. ", " .%&*=-;..... ", " .>,')!~{]{^/. ", " .(_:<[}||12345 ", " .67890abbbbbcd.", " .efg0bbbbbbbhi.", " .j8kabbbbbbbl. ", " .mnobbbbbbbbp. ", " .qrbbbbbbbbs. ", " .tuvwwwwwwxy. ", " ........... ", " ", " "}; xpn-1.2.6/pixmaps/rot13.xpm0000644000175000017500000001104311141275756013642 0ustar antant/* XPM */ static char * rot13_xpm[] = { "24 24 195 2", " c None", ". c #000000", "+ c #636024", "@ c #ADA93F", "# c #73702A", "$ c #E3D151", "% c #CE9141", "& c #786927", "* c #FACB53", "= c #FF924A", "- c #F68245", "; c #CFB147", "> c #896A29", ", c #E8A245", "' c #FD8646", ") c #FF7845", "! c #FF7B45", "~ c #FF8848", "{ c #DD8140", "] c #220B04", "^ c #9A3414", "/ c #D9552A", "( c #F6713F", "_ c #F4713E", ": c #FB7542", "< c #FE7745", "[ c #BD5933", "} c #7B1A09", "| c #CB4621", "1 c #F06A3A", "2 c #C34E23", "3 c #9F4319", "4 c #A84E1E", "5 c #D0672D", "6 c #FB7743", "7 c #72200C", "8 c #BE421D", "9 c #9C3B17", "0 c #EA753A", "a c #292827", "b c #262625", "c c #292929", "d c #2C2C2C", "e c #2B2B2B", "f c #2F2F2F", "g c #555555", "h c #373737", "i c #232323", "j c #222222", "k c #585959", "l c #363434", "m c #0F0402", "n c #1A0E0A", "o c #09090A", "p c #030506", "q c #020405", "r c #15100D", "s c #2C1912", "t c #0E0705", "u c #080808", "v c #DEDEDE", "w c #F6F6F6", "x c #B7B7B7", "y c #494949", "z c #111111", "A c #7F7F7F", "B c #434343", "C c #141515", "D c #161919", "E c #1F2021", "F c #101010", "G c #F0F0F0", "H c #A5A5A5", "I c #171717", "J c #1F1F1F", "K c #989898", "L c #191919", "M c #252525", "N c #797979", "O c #F4F4F4", "P c #3D3D3D", "Q c #1E1E1E", "R c #898989", "S c #FBFBFB", "T c #2E2E2E", "U c #0B0B0B", "V c #1B1D1E", "W c #1A1A1B", "X c #D9D9D9", "Y c #1D1B1A", "Z c #231A17", "` c #070403", " . c #E8E8E8", ".. c #9E9E9E", "+. c #1D1D1D", "@. c #8B8B8B", "#. c #08090A", "$. c #080809", "%. c #EBEBEB", "&. c #8A8A89", "*. c #3D3D3E", "=. c #9E9FA1", "-. c #151515", ";. c #101011", ">. c #332F2B", ",. c #0C0A08", "'. c #C8CBCC", "). c #280E06", "!. c #5D2815", "~. c #7E7975", "{. c #E4E4E4", "]. c #C6C6C6", "^. c #E0E0E0", "/. c #252524", "(. c #1E1914", "_. c #1C1C1B", ":. c #FFFFFF", "<. c #707171", "[. c #0F0F0A", "}. c #27221A", "|. c #080706", "1. c #A2A3A4", "2. c #020100", "3. c #AA6621", "4. c #49290B", "5. c #080504", "6. c #979491", "7. c #9C9C9C", "8. c #0E1010", "9. c #8E8E8E", "0. c #030201", "a. c #8E5922", "b. c #231B12", "c. c #F3F4F5", "d. c #7F8187", "e. c #544B17", "f. c #D18F41", "g. c #F2F3F4", "h. c #553212", "i. c #FF9C3D", "j. c #431904", "k. c #2A2A29", "l. c #0A0A0A", "m. c #EFEFEF", "n. c #939799", "o. c #270800", "p. c #1C0E0B", "q. c #DFE1E2", "r. c #828282", "s. c #0F0802", "t. c #0E0603", "u. c #9C9D9E", "v. c #E9EAEB", "w. c #322921", "x. c #2C1A09", "y. c #676869", "z. c #353C40", "A. c #982E08", "B. c #FC571B", "C. c #0E0200", "D. c #CBCBCB", "E. c #D6D7D8", "F. c #7C8589", "G. c #60230B", "H. c #74320E", "I. c #586063", "J. c #DBDDDE", "K. c #171718", "L. c #160C08", "M. c #151718", "N. c #B4B4B5", "O. c #DFDFDF", "P. c #6D6E70", "Q. c #2E1C0A", "R. c #6F3416", "S. c #441509", "T. c #0F0D0D", "U. c #B5B5B5", "V. c #2A2A2A", "W. c #010101", "X. c #181210", "Y. c #160E0B", "Z. c #6E2F18", "`. c #ED6A34", " + c #271109", ".+ c #1E1614", "++ c #120A08", "@+ c #673F1B", "#+ c #4E341C", "$+ c #100D08", "%+ c #343332", "&+ c #414141", "*+ c #2B1C0D", "=+ c #3B3B3C", "-+ c #343434", " . . ", " . + @ ", " . # $ % . . ", " . & * = - ; ; . . ", " . > , ' ) ! ~ ~ ~ { . ", " ] ^ / ) ) ( _ : ) < [ . ", " . } | 1 2 3 4 5 6 ) . ", " . 7 8 9 . . . 0 ) . ", "a b c d e f g h i j c k l m n o p q r s t ", "u v w v w x y y z A w v w B C D v w v w v v E ", "F G H I J K w L M N O P Q R S T U V W w X Y Z ` ", "F ...+.j @.v #.$.%.&.*.=.-.O v ;.>.,.v '.).!.~.", "F v {.].^.v /.(._.:.<.[.}.|.v 1.2.3.4.w v 5.6. ", "F .7.8.v 9.0.a.b.c.d.e.f.r g.v h.i.j.v v k. ", "l.m.n.o.p.q.r.s.t.u.v.w.x.y.:.z.A.B.C.w D.T ", "u E.F.G.H.I.J.K.L.M.N.v w O.P.Q.R.S.T.v U.V. ", "W.X.Y.Z.`. +.+++@+#+$+%+&+I . *+ =+-.I -+ ", ". ) 6 5 4 3 2 1 | } . ", ". [ < ) : _ ( ) ) / ^ ] ", " . { ~ ~ ~ ! ) ' , > . ", " . . ; ; - = * & . ", " . . % $ # . ", " @ + . ", " . . "}; xpn-1.2.6/pixmaps/mark_all.xpm0000644000175000017500000000613011141275756014455 0ustar antant/* XPM */ static char * mark_all_xpm[] = { "24 24 116 2", " c None", ". c #000000", "+ c #E4E5DE", "@ c #D3D5CA", "# c #A5A797", "$ c #F3F4F0", "% c #ABAE99", "& c #BDC0AD", "* c #BCBEAA", "= c #B1B49F", "- c #6E715C", "; c #0C100C", "> c #E6E7DD", ", c #F5F6F3", "' c #E4E5DB", ") c #E2E4D9", "! c #E1E3D8", "~ c #DFE1D6", "{ c #2424D9", "] c #F7F7F6", "^ c #D3D6C5", "/ c #D3D6C4", "( c #D2D4C2", "_ c #D0D2C0", ": c #CED1BD", "< c #CCCEBA", "[ c #CACDB9", "} c #C8CBB6", "| c #C6C9B3", "1 c #939685", "2 c #010109", "3 c #F0F0EB", "4 c #000001", "5 c #F0F1EC", "6 c #9C9F8F", "7 c #484940", "8 c #EFF0EB", "9 c #9B9D8D", "0 c #909284", "a c #EDEEE8", "b c #2828D9", "c c #022202", "d c #ECEEE7", "e c #C4C8B1", "f c #6E6F62", "g c #9E9F98", "h c #ADADA6", "i c #3233DA", "j c #2627D9", "k c #C4C6B6", "l c #E8E8E0", "m c #C3C6AF", "n c #C1C4AD", "o c #0F1018", "p c #7A82E4", "q c #B9BBAD", "r c #4446DD", "s c #3F41DD", "t c #3132DB", "u c #93967C", "v c #C6C9BA", "w c #909478", "x c #030305", "y c #7F87E5", "z c #909AE8", "A c #777EE4", "B c #010102", "C c #696B62", "D c #020205", "E c #5357DF", "F c #494CDE", "G c #3C3EDD", "H c #2E2FDA", "I c #11121C", "J c #8F9AE8", "K c #5F65E1", "L c #090A11", "M c #6970E2", "N c #6167E1", "O c #5358E0", "P c #4649DE", "Q c #3233DB", "R c #B8BCA6", "S c #020203", "T c #7881E4", "U c #8A93E7", "V c #6B72E3", "W c #7880E5", "X c #5E63E1", "Y c #484CDD", "Z c #ABAD99", "` c #BFC2AB", " . c #BDC1A8", ".. c #8E9175", "+. c #7B83E5", "@. c #8D98E7", "#. c #909BE8", "$. c #838BE6", "%. c #757DE4", "&. c #5F64E0", "*. c #05060E", "=. c #9B9E8B", "-. c #BBBEA5", ";. c #BABDA3", ">. c #8B8F72", ",. c #6D74E3", "'. c #8F99E7", "). c #6D75E3", "!. c #767969", "~. c #B7BAA0", "{. c #7880E4", "]. c #7A82E5", "^. c #757767", "/. c #63645D", "(. c #34362B", "_. c #646751", " ", " ", " . . . . ", " . + @ @ # . ", " . $ % & * = - . . . . . . . ; . ", " . > , > > > ' > ) ) ! ! ~ . { { . ", " . ] ^ / ( _ : < [ [ } | 1 2 { { . ", " . 3 ^ / ( _ : < [ [ } | . { { { { 4 ", " . 5 ( _ : < 6 . . . . 7 . { { { { { . ", " . 8 : < [ 9 . + @ @ 0 4 { { { { { { . ", " . a [ } | . $ % & * . b { { { { { c . ", " . d | e f . g , > h 4 i j { { { { . k . ", " . l m n o p . q / . r s t { { { . e u . ", " . v w x y z A B C D E F G H { . | e u . ", " . . I z J z K L M N O P Q . R m n w . ", " S T z J U V W V X Y . Z n ` .... ", " . B +.@.#.J $.%.&.*.=.` .-.;.>.. ", " . . ,.'.z @.).. !.-.-.;.~.~.>.. ", " . . {.'.].. ^.;.~.~.~.~.~.>.. ", " . /.S X . (.>.>.>.>.>.>.>._.. ", " . . . . . . . . . . . . . . ", " ", " ", " "}; xpn-1.2.6/pixmaps/layout_10.xpm0000644000175000017500000000140311141275756014506 0ustar antant/* XPM */ static char * layout10_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".++++.+++++.+++++++++++.", ".+++...++++.+++++++++++.", ".++..+..+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.....+++.+++++++++++.", ".++.+++.+++.++++...++++.", ".++.+++.+++.+++.+++.+++.", ".++++++++++.+++.+++++++.", "............+++.++..+++.", ".++++++++++.+++.+++.+++.", ".++++++++++.+++.+++.+++.", ".++.+++.+++.++++...++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.....+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_11.xpm0000644000175000017500000000140311141275756014507 0ustar antant/* XPM */ static char * layout11_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.....+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.++++...++++.", ".++.+++.+++.+++.+++.+++.", ".++++++++++.+++.+++++++.", "............+++.++..+++.", ".++++++++++.+++.+++.+++.", ".++++++++++.+++.+++.+++.", ".++++.+++++.++++...++++.", ".+++...++++.+++++++++++.", ".++..+..+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.....+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_12.xpm0000644000175000017500000000140311141275756014510 0ustar antant/* XPM */ static char * layout12_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.....+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++.+++++.", ".++.+++.+++.++++...++++.", ".++++++++++.+++..+..+++.", "............+++.+++.+++.", ".++++++++++.+++.....+++.", ".++++++++++.+++.+++.+++.", ".+++...++++.+++.+++.+++.", ".++.+++.+++.+++++++++++.", ".++.+++++++.+++++++++++.", ".++.++..+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".++.+++.+++.+++++++++++.", ".+++...++++.+++++++++++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_13.xpm0000644000175000017500000000140311141275756014511 0ustar antant/* XPM */ static char * layout13_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", ".+++++++++++.++++...+++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.++++++.", ".+++++++++++.+++.++..++.", ".+++++++++++.+++.+++.++.", ".+++++.+++++.+++.+++.++.", ".++++...++++.++++...+++.", ".+++..+..+++.++++++++++.", ".+++.+++.+++............", ".+++.....+++.++++++++++.", ".+++.+++.+++.++++++++++.", ".+++.+++.+++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.....++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_14.xpm0000644000175000017500000000140311141275756014512 0ustar antant/* XPM */ static char * layout14_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", ".+++++++++++.++++...+++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.++++++.", ".+++++++++++.+++.++..++.", ".+++++++++++.+++.+++.++.", ".+++.+++.+++.+++.+++.++.", ".+++.+++.+++.++++...+++.", ".+++.+++.+++.++++++++++.", ".+++.....+++............", ".+++.+++.+++.++++++++++.", ".+++.+++.+++.++++++++++.", ".+++.+++.+++.+++++.++++.", ".+++++++++++.++++...+++.", ".+++++++++++.+++..+..++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.....++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_15.xpm0000644000175000017500000000140311141275756014513 0ustar antant/* XPM */ static char * layout15_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", ".+++++++++++.+++++.++++.", ".+++++++++++.++++...+++.", ".+++++++++++.+++..+..++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.....++.", ".+++.+++.+++.+++.+++.++.", ".+++.+++.+++.+++.+++.++.", ".+++.+++.+++.++++++++++.", ".+++.....+++............", ".+++.+++.+++.++++++++++.", ".+++.+++.+++.++++++++++.", ".+++.+++.+++.++++...+++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.++++++.", ".+++++++++++.+++.++..++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.++++...+++.", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_16.xpm0000644000175000017500000000140311141275756014514 0ustar antant/* XPM */ static char * layout16_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", ".+++++++++++.+++++.++++.", ".+++++++++++.++++...+++.", ".+++++++++++.+++..+..++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.....++.", ".++++...++++.+++.+++.++.", ".+++.+++.+++.+++.+++.++.", ".+++.+++++++.++++++++++.", ".+++.++..+++............", ".+++.+++.+++.++++++++++.", ".+++.+++.+++.++++++++++.", ".++++...++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.....++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_17.xpm0000644000175000017500000000140311141275756014515 0ustar antant/* XPM */ static char * layout17_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.....++.", ".+++++++++++.+++.+++.++.", ".++++...++++.+++.+++.++.", ".+++.+++.+++.+++.+++.++.", ".+++.+++++++.++++++++++.", ".+++.++..+++............", ".+++.+++.+++.++++++++++.", ".+++.+++.+++.++++++++++.", ".++++...++++.+++++.++++.", ".+++++++++++.++++...+++.", ".+++++++++++.+++..+..++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.....++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_18.xpm0000644000175000017500000000140311141275756014516 0ustar antant/* XPM */ static char * layout18_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.....++.", ".+++++++++++.+++.+++.++.", ".+++++.+++++.+++.+++.++.", ".++++...++++.+++.+++.++.", ".+++..+..+++.++++++++++.", ".+++.+++.+++............", ".+++.....+++.++++++++++.", ".+++.+++.+++.++++++++++.", ".+++.+++.+++.++++...+++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.++++++.", ".+++++++++++.+++.++..++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.+++.+++.++.", ".+++++++++++.++++...+++.", ".+++++++++++.++++++++++.", ".+++++++++++.++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_19.xpm0000644000175000017500000000140311141275756014517 0ustar antant/* XPM */ static char * layout19_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".++++++++++.+++++++++++.", ".+++++++++...++++++++++.", ".++++++++..+..+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.....+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................", ".++++++++++.+++++++++++.", ".+++...++++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++++++.+++.+++.+++.", ".++.++..+++.+++.....+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".+++...++++.+++.+++.+++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_20.xpm0000644000175000017500000000140311141275756014507 0ustar antant/* XPM */ static char * layout20_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".++++++++++.+++++++++++.", ".+++++++++...++++++++++.", ".++++++++..+..+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.....+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................", ".++++++++++.+++++++++++.", ".++.+++.+++.++++...++++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++++++.", ".++.....+++.+++.++..+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.++++...++++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/art_fup.xpm0000644000175000017500000000075711141275756014344 0ustar antant/* XPM */ static char * art_fup_xpm[] = { "18 16 6 1", " c None", ". c #FF9966", "+ c #FF6633", "@ c #999999", "# c #000000", "$ c #FFFFFF", " ", " ## ", " #$# ", " ####.$# ", "#####+++..+#$## ", "##$$####.+#$$## ", "#$#$$$$#+#$$#$# ", "#$$#$$$##$$#$$# ", "#$$$#$$$$$#$$$# ", "#$$$$#$$$#$$$$#@ ", "#$$$#$#$#$#$$$#@@@", "#$$#$$$#$$$#$$#@@@", "#$#$$$$$$$$$#$#@@ ", "##$$$$$$$$$$$##@@ ", "###############@ ", " @@@@@@@@@@@@@@@ "}; xpn-1.2.6/pixmaps/layout_21.xpm0000644000175000017500000000140311141275756014510 0ustar antant/* XPM */ static char * layout21_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.....+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................", ".++++++++++.+++++++++++.", ".++++.+++++.++++...++++.", ".+++...++++.+++.+++.+++.", ".++..+..+++.+++.+++++++.", ".++.+++.+++.+++.++..+++.", ".++.....+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.++++...++++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_22.xpm0000644000175000017500000000140211141275756014510 0ustar antant/* XPM */ static char * layout4_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.....+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................", ".++++++++++.+++++++++++.", ".+++...++++.+++++.+++++.", ".++.+++.+++.++++...++++.", ".++.+++++++.+++..+..+++.", ".++.++..+++.+++.+++.+++.", ".++.+++.+++.+++.....+++.", ".++.+++.+++.+++.+++.+++.", ".+++...++++.+++.+++.+++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/cancel.xpm0000644000175000017500000000754611141275756014134 0ustar antant/* XPM */ static char * cancel_xpm[] = { "24 24 165 2", " c None", ". c #000000", "+ c #E2E2E2", "@ c #F2F2F2", "# c #F3F3F3", "$ c #F4F4F4", "% c #F5F5F5", "& c #F6F6F6", "* c #F7F7F7", "= c #DBDBDB", "- c #F0F0F0", "; c #E0E0E0", "> c #E1E1E1", ", c #E3E3E3", "' c #E4E4E4", ") c #E5E5E5", "! c #E6E6E6", "~ c #E7E7E7", "{ c #E8E8E8", "] c #E9E9E9", "^ c #EAEAEA", "/ c #EBEBEB", "( c #ECECEC", "_ c #EDEDED", ": c #EEEEEE", "< c #EFEFEF", "[ c #868686", "} c #878787", "| c #898989", "1 c #8A8A8A", "2 c #8B8B8B", "3 c #8C8C8C", "4 c #8D8D8D", "5 c #8E8E8E", "6 c #F1F1F1", "7 c #0F0B0A", "8 c #865C5B", "9 c #A36E6D", "0 c #3B2726", "a c #653A39", "b c #AD6260", "c c #562F2E", "d c #946362", "e c #EE8C8A", "f c #F15755", "g c #F15655", "h c #5A1D1C", "i c #8F504E", "j c #E57B78", "k c #E64E4C", "l c #E44746", "m c #380D0C", "n c #8F8F8F", "o c #B0716F", "p c #F24A49", "q c #F3403F", "r c #F23F3E", "s c #5A1716", "t c #8F4D4B", "u c #E47572", "v c #E44341", "w c #E13533", "x c #DE3331", "y c #6E1918", "z c #744746", "A c #F24443", "B c #F03E3D", "C c #ED3C3B", "D c #EA3A39", "E c #AB4140", "F c #E2706D", "G c #E1403E", "H c #DB312F", "I c #CB2C2A", "J c #1B0505", "K c #909090", "L c #952F2E", "M c #E73837", "N c #E43635", "O c #DE3A38", "P c #D82F2D", "Q c #C82A28", "R c #270808", "S c #902322", "T c #E33635", "U c #E03433", "V c #DA312F", "W c #D52D2B", "X c #C52826", "Y c #270807", "Z c #919191", "` c #929292", " . c #C23836", ".. c #DA302F", "+. c #D72F2D", "@. c #D42D2B", "#. c #D12B29", "$. c #CF2927", "%. c #661412", "&. c #F8F8F8", "*. c #8A3C39", "=. c #DD5B57", "-. c #D5302D", ";. c #CE2927", ">. c #CC2725", ",. c #C92623", "'. c #C62421", "). c #490C0B", "!. c #939393", "~. c #F9F9F9", "{. c #8A3835", "]. c #DB5551", "^. c #D33330", "/. c #CB2725", "(. c #C3221F", "_. c #C1211E", ":. c #BE1F1C", "<. c #460B09", "[. c #FAFAFA", "}. c #6D2A28", "|. c #DA504C", "1. c #D0302D", "2. c #C82523", "3. c #BA221F", "4. c #861716", "5. c #C1201E", "6. c #BC1D1A", "7. c #B91C18", "8. c #B71A17", "9. c #160302", "0. c #959595", "a. c #FBFBFB", "b. c #FCFCFC", "c. c #A33936", "d. c #CE302D", "e. c #B7201D", "f. c #240605", "g. c #751210", "h. c #B61A17", "i. c #B41915", "j. c #B21714", "k. c #580B09", "l. c #FDFDFD", "m. c #862A27", "n. c #C52321", "o. c #B41E1B", "p. c #710F0D", "q. c #B01612", "r. c #AE1511", "s. c #2B0504", "t. c #969696", "u. c #FEFEFE", "v. c #0F0403", "w. c #55100E", "x. c #5F0F0E", "y. c #230505", "z. c #410806", "A. c #560A08", "B. c #350604", "C. c #FFFFFF", "D. c #949494", "E. c #979797", "F. c #989898", "G. c #C9C9C9", "H. c #BDBDBD", " . . . . . . . . . . . . . . . . . . . . ", ". + @ @ @ @ # # # $ $ $ % % % & & * * $ = . ", ". - ; ; > + , ' ) ! ~ { { ] ^ / ( _ : < _ . ", ". @ > [ [ } . . | | 1 1 2 2 3 . 4 4 5 - 6 . ", ". @ + , , 7 8 9 0 . ] ^ / . a b c . - 6 @ . ", ". # , } . d e f g h . 3 . i j k l m n @ # . ", ". # ' ) . o p q q r s . t u v w x y @ # $ . ", ". # ) | | z A r B C D E F G x H I J K $ % . ", ". $ ! ~ { . L C D M N w O H P Q R # $ % & . ", ". $ ~ 1 1 2 . S T U x V P W X Y Z ` ` & * . ", ". % { ] ^ / ( . ...+.@.#.$.%.. % & * * &.. ", ". % ] 2 3 3 . *.=.-.#.;.>.,.'.).. !.!.&.~.. ", ". % ^ / ( . {.].^.;./.,.'.(._.:.<.. ~.[.[.. ", ". & / 3 4 }.|.1./.2.3.4.5.:.6.7.8.9.0.a.b.. ", ". * _ _ . c.d.2.'.e.f.. g.7.h.i.j.k.a.b.l.. ", ". * : 5 . m.n.(.o.f.` ` . p.j.q.r.s.t.l.u.. ", ". &.- 6 @ v.w.x.y.& * &.~.. z.A.B.. u.C.C.. ", ". &.6 K K Z Z . ` !.!.D.0.0.t.. t.E.F.C.C.. ", ". @ @ # $ % & & * &.~.[.a.b.l.u.C.C.C.C.( . ", ". G._ &.% & * &.&.~.[.a.b.l.u.C.C.C.C.: H.. ", " . . . . . . . . . . . . . . . . . . . . ", " ", " ", " "}; xpn-1.2.6/pixmaps/layout_23.xpm0000644000175000017500000000140311141275756014512 0ustar antant/* XPM */ static char * layout23_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".+++++++++...++++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++++++++++++.", ".++++++++.++..+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".+++++++++...++++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................", ".++++++++++.+++++++++++.", ".++.+++.+++.+++++.+++++.", ".++.+++.+++.++++...++++.", ".++.+++.+++.+++..+..+++.", ".++.....+++.+++.+++.+++.", ".++.+++.+++.+++.....+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/pixmaps/layout_24.xpm0000644000175000017500000000140311141275756014513 0ustar antant/* XPM */ static char * layout24_xpm[] = { "24 24 3 1", " c None", ". c #000000", "+ c #FFFFFF", "........................", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", ".+++++++++...++++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++++++++++++.", ".++++++++.++..+++++++++.", ".++++++++.+++.+++++++++.", ".++++++++.+++.+++++++++.", ".+++++++++...++++++++++.", ".++++++++++++++++++++++.", ".++++++++++++++++++++++.", "........................", ".++++++++++.+++++++++++.", ".++++.+++++.+++.+++.+++.", ".+++...++++.+++.+++.+++.", ".++..+..+++.+++.+++.+++.", ".++.+++.+++.+++.....+++.", ".++.....+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++.+++.+++.+++.+++.+++.", ".++++++++++.+++++++++++.", ".++++++++++.+++++++++++.", "........................"}; xpn-1.2.6/ChangeLog0000644000175000017500000004172611141275756012250 0ustar antantXPN - X Python Newsreader 2009-02-01 * v1.2.6: Now threads with unread watched articles are underlined * v1.2.6: added a visualization option that lets you hide threads without * v1.2.6: watched articles * v1.2.6: fixed a bug that caused XPN not to kill old articles reapplying rules * v1.2.6: fixed a bug that caused crashes when using ID with extended chars 2008-09-13 * v1.2.5: rewritten the articles management, now the articles are stored in a SQLite dB. Articles management now is faster and easier. Your xpn-1.0.0 groups and articles will be automatically imported and converted to the new format. * v1.2.5: added a filter toolbar that lets you filter the articles by Subject From and Body content. * v1.2.5: improved the algorithm used to build the discussion threads * v1.2.5: revisited the menus and some windows * v1.2.5: added automatic headers download every tot minutes * v1.2.5: some minor fixes and refinements. 2008-02-02 * v1.0.0: added multi-identity support * v1.0.0: added nineteen new layouts * v1.0.0: fixed a bug that made garbled the X-Faces in replies * v1.0.0: merged a patch from Facundo Batista that lets me work on Threads objects. Its first application is the 'View Option' 'Show All Read Threads' that lets you hide/show threads with all read articles. * v1.0.0: eventually GTK supports the long awaited set_enable_tree_lines property, that shows connecting lines between articles in the same thread * v1.0.0: some minor fixes. 2007-01-07 * v0.7.0: added basic multiserver support. This change has required some modifications to the groups db format, in order to keep your subscriptions you need to export to a newsrc file from XPN-0.6.5 and reimport it in XPN-0.7.0. * v0.7.0: now is possible to use Function keys for customized keybindings * v0.7.0: modified the command used to test the connection in order to prevent hamster hang-ups. * v0.7.0: fixed a bug that caused XPN to crash trying to export newsrc file with empty groups subscribed. * v0.7.0: fixed a bug in "Apply Scoring and Actions Rules" feature that caused XPN crashes trying to apply !kill rule. * v0.7.0: some minor fixes. 2006-09-11 * v0.6.5: now is possible to customize the keyboad shortcuts. XPN will also check for duplicated shortcuts * v0.6.5: added a new way to show threads, now is possible to put the threads expander in the From column * v0.6.5: now is possible to subscribe a group writing its name manually so you don't have to download the groups list * v0.6.5: now is possible to limit the number of articles headers to download with the Get New Headers function * v0.6.5: now is possible to choose the headers to show in the Article Pane, and the background color of this area now is customizable * v0.6.5: added two new layouts for the main window * v0.6.5: now is possible to re-apply the scoring/action rules on the articles you have already downloaded. * v0.6.5: fixed a bug in the Config Window that caused XPN not to change the color for URLs. * v0.6.5: fixed a bug that caused XPN not open the next article when the first thread was selected and collapsed * v0.6.5: fixed a bug in the View Parent function * v0.6.5: fixed a bug in the Export Newsrc function, that caused ad crash trying to export groups with 0 articles inside. 2006-07-13 * v0.5.7: fixed a bug that caused XPN not to open empty articles * v0.5.7: fixed a bug that occurs with newer GTK releases that caused XPN not to show bold face fonts in Groups Pane and Threads Pane * v0.5.7: added a key-combo that lets you scroll up the article * v0.5.7: fixed an issue with orderings save. * v0.5.7: reorganized and changed the appearance of the Config Window * v0.5.7: changed the appearance of the Score Window * v0.5.7: changed the way article headers and X-Face are shown in the Article Pane * v0.5.7: added a groups context menu * v0.5.7: added some new voices in the threads context menu 2006-03-10 * v0.5.6: added message-id recognition. Now XPN tries to recognize message-ids in the text and make them clickable in order to open a search window. * v0.5.6: added a dialog window that informs you when XPN downloads new articles in watched threads. * v0.5.6: some improvements in Global Search, now is possible to perform multiple searches. * v0.5.6: now XPN checks if there are other istances running (it uses the file xpn.lock in the XPN directory). This behaviour should prevent database break off. * v0.5.6: some fixes in the Score Window * v0.5.6: fixed some bugs in header management * v0.5.6: fixed a bug that caused crashes with multipart articles with email attached * v0.5.6: changed subversion 2005-10-02 * v0.5.5: improved support for outgoing/draf articles, now is possible to re-edit queued articles. * v0.5.5: added a simple SSL connection support (no certificates checks) * v0.5.5: added multipart article support (no binary attachments support) * v0.5.5: added German translation (thanks to Rene Fischer) * v0.5.5: fixed a bug that caused crashes with strange Date fields * v0.5.5: fixed a bug in newsrc importing, now is alse possible to import not standard newsrc files like the Xnews ones. * v0.5.5: fixed a bug in the newsrc system that caused a crash with groups containings lots of articles * v0.5.5: a lot of little bug-fixes and little enhancements * v0.5.5: changed subversion 2005-07-15 * v0.5.0: added some checks on the validity of out-going articles, as required by the GNKSA2.0 * v0.5.0: added Reply-To, Followup-To and Newsgroups headers in the Article Pane, as required by the GNKSA2.0 * v0.5.0: added !setcolor action, it lets you modify the foreground and backgrounnd colors of the article. * v0.5.0: added inverted rules, they are successfull when the match is not satisfied. * v0.5.0: now is possible to disable the threaded view. * v0.5.0: now sorting column in the Threads Pane is stored * v0.5.0: the header parser has been rewritten * v0.5.0: added double-click support when you subscribe/unsubscribe groups (thanks to Lethalman). * v0.5.0: fixed a bug in the autowrap feature that created double lines in some circumstances. * v0.5.0: now the "View Raw Article" is correctly stored. 2005-05-27 * v0.4.6: improved speed in article retrieving * v0.4.6: added an indicator of unread articles in thread, now you don't have to open the thread in order to know if it contains unread articles. * v0.4.6: now the "CANCEL" works again, and "SUPERSEDE" lets you re-edit the original article text. * v0.4.6: fixed some pygtk issues, now XPN works correctly also with pygtk2.6 (and GTK2.6) * v0.4.6: fixed a bug in the "Edit Mail" window that caused some errors when closing the window. * v0.4.6: now the Error Dialog is shown also when XPN isn't able to start (thanks to Antonio Valentino). * v0.4.6: fixed some issues with shelve module that caused problems on some FreeBSD systems. * v0.4.6: some improvements in the french translation (thanks to Patrick Lamaiziere) * v0.4.6: some changes in the "raw view" management. * v0.4.6: changed subversion 2005-03-08 * v0.4.5: added X-Face support (thanks to Andrew Taylor for helping me in the translation of his javascript port of uncompface, and to Alien321 for telling me about the Mnenhy Thunderbird extension) * v0.4.5: added Face support (note you can't send Faces, because this is a non standard header). * v0.4.5: added i18n support with gettext. At the moment the supported languages are Italian and French (thanks to Guillaume Bedot for the code and for the French translation) * v0.4.5: rewrote NNTP connection handler as an externale module. Now it should be more readable and more reliable. * v0.4.5: some refinements in watch/ignore/mark features * v0.4.5: fixed some quirk behaviours in the wrapping feature. Now the live wrapping should work better. * v0.4.5: added Subject based threading, it's used when References based threading fails * v0.4.5: now XPN can generate Message-IDs, and you can also use a personal [pseudo-]FQDN. * v0.4.5: added command line options, now you can run xpn with "-d" option and it will store articles and configs files inside a .xpn directory in your home-dir. (thanks to Guillaume Bedot for the code) * v0.4.5: added a simple outbox, you can store your articles in it when you are offline and then send them when you estabilish the connection with the server. * v0.4.5: now XPN should autmatically repair its database when it gets corrupted. * v0.4.5: some fixes for Supersede/Cancel features * v0.4.5: now you can select multiple row in groups list. So for instance you can subscribe more than one group with one click, or you can use the new "download new headers in selected groups". * v0.4.5: now you can use a different From field when you reply by mail * v0.4.5: fixed a bug introduced in the previous release that caused a crash trying to use a NickName with extended characters in it. * v0.4.5: changed subversion 2005-01-17 * v0.4.0: added off-line reading. Now you can download the whole bodies, or mark some article and download their bodies. * v0.4.0: added Keep Article and Watch/Ignore SubThread * v0.4.0: added actions rule, now you can !keep, !watch, !ignore (and so on) your article through rules * v0.4.0: now XPN stores the position and the size of Main Window and Edit Window * v0.4.0: now you can customize the charsets list XPN use to encode your outgoing articles * v0.4.0: improved speed when loading groups list in Groups Window. * v0.4.0: fixed a bug in the binary version that caused a crash trying to subscribe a group * v0.4.0: added Oriental Charsets support (thanks to Python2.4) * v0.4.0: added Global Search, you can search the whole groups and put the results in a virtual group * v0.4.0: added filtered views * v0.4.0: moved to GTK2.4 and Python2.4 * v0.4.0: added a TraceBack viewer and an error logger * v0.4.0: reorganized some menus * v0.4.0: now the background color is changed also on Groups Pane and Headers pane * v0.4.0: added a lot of little features/enhancements * v0.4.0: fixed a lot of bugs * v0.4.0: changed subversion and minorversion 2004-11-13 * v0.3.5: improved speed when you open an article * v0.3.5: fixed a bug in the smtp connection * v0.3.5: fixed (again) a date sorting bug * v0.3.5: now you can hide read articles * v0.3.5: added spoiler char (^L or formfeed) support. * v0.3.5: added "mute quote" and "mute signature" features * v0.3.5: added "Supersede Article" and "Cancel Article" features * v0.3.5: added three buttons "A" "H" "G" that let you zoom the Article/Headers/Groups Pane * v0.3.5: reorganized the Score Window * v0.3.5: added a Regular Expression Tester in the Score Window * v0.3.5: changed subversion 2004-09-11 * v0.3.1: added "One Click View" feature. Now you can open an article with a single click on it * v0.3.1: fixed some bugs related to the followup function * v0.3.1: fixed the timeout bug. Now XPN continue working even if the connection gets a timeout * v0.3.1: added "Reply By Mail" feature. Now you can reply by mail directly from XPN. You can specify the portnumber and you can use username and password if the server requires authentication * v0.3.1: changed subversion 2004-06-18 * v0.3.0: now headers are collected with XOVER command * v0.3.0: added scoring system, with a simple rules editor/viewer (see xpn.html for the details) * v0.3.0: little changes in the header encoding. Now the encoding used for the header is not linked to the encoding used for the body * v0.3.0: fixed a bug in the custom headers support * v0.3.0: little changes in the rot13 support * v0.3.0: added "find in the body" feature * v0.3.0: added regular expressions support whe you search a group in the Groups Window * v0.3.0: added article search feature. Now you can search an article in the threads pane, also with regular expressions. You can search in From, Subject, Msg-id and References headers and in the body (only for read articles), and combine the results with AND or OR logic * v0.3.0: a lot of little changes and fixes * v0.3.0: changed minorversion 2004-05-10 * v0.2.7: added external editor support * v0.2.7: little change about rot13, now if there isn't selected text the whole article will be encoded/decoded * v0.2.7: fixed a bug caused by articles with strange line-terminators * v0.2.7: little change in connection handling. Now you can enter a group and read already read articles without having to estabilish a connection with server * v0.2.7: fixed a bug in Import Newsrc * v0.2.7: now the function that builds the threaded-view is much faster * v0.2.7: other little changes * v0.2.7: changed subversion 2004-04-23 Antonio Caputo * v0.2.6: added Import/Export newsrc file * v0.2.6: added autoencode feature. Now XPN automatically chooses the best encodig for outgoing articles * v0.2.6: fixed another bug in threads building * v0.2.6: updated xpn.html file * v0.2.6: changed subversion 2004-04-02 Antonio Caputo * v0.2.5: added read articles persistance. When you read an article XPN stores it. You can set two purge time (one for read article and another one for unread articles), after that time article will be deleted * v0.2.5: now you can select the text in Article Pane, and if you try a followup to newsgroup, only the selected text will be quoted * v0.2.5: added token %e, it stands for the email * v0.2.5: added token (%n,%g ...) recognition in X-header fields * v0.2.5: fixed a little bug in threads building. References: null no longer blocks XPN * v0.2.5: fixed a bug that affected the "custom launcher" entry in the config window (thanks to Valentino Volonghi) * v0.2.5: changed subversion 2004-02-29 Antonio Caputo * v0.2.2: restored date sorting * v0.2.2: fixed some strange behaviours in threads_pane * v0.2.2: added more encodings * v0.2.2: added support for web urls. Now you can open web urls, you can also customize the browser launcher command * v0.2.2: now when you move to another group the article pane is cleared * v0.2.2: minor changes in Article module * v0.2.2: added port number customization * v0.2.2: fixed an uncaught exception in "Add Tagline" + v0.2.2: newsgroup list download now is made in a different Thread * v0.2.2: changed subversion 2004-02-08 Antonio Caputo * v0.2.0: rewritten header fetching routine. Now header fetching is about ten times faster * v0.2.0: minor changes in article fetching * v0.2.0: namespace moved from "XPN" to "xpn_src" * v0.2.0: added server logs viewer * v0.2.0: fixed "double click on groups pane" bug * v0.2.0: changed minorversion 2004-01-24 Antonio Caputo * v0.1.8: namespace moved from "src" to "XPN" * v0.1.8: layout changes now are made "on the fly" * v0.1.8: added *bold*, /italic/, _undeline_, recognition * v0.1.8: added "MODE READER" command after connection estabilishment Now you can use XPN with INN2 * v0.1.8: supersedes header is now disabled, I have to study the RFC * v0.1.8: some enhancements in connections handling * v0.1.8: fixed date display * v0.1.8: fixed some headers related bugs, now you can you use ":" in you custom headers * v0.1.8: fixed the "deleting last line" bug in the Edit Win * v0.1.8: some changes in quoting style, the first level quote now is "> ", in past versions was ">" * v0.1.8: added url recognition and colouring whith a user defined color * v0.1.8: fixed the "Row: Col:" display in the Edit Window. Now update occurs even if you only move the cursor * v0.1.8: changed subversion xpn-1.2.6/COPYING0000644000175000017500000004311011141275756011516 0ustar antant GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.