set svn:eol-style to LF for all code/resource files

This commit is contained in:
Thialfihar 2010-07-16 20:13:12 +00:00
parent ec10329664
commit f5efd73d33
37 changed files with 7339 additions and 7339 deletions

View File

@ -1,38 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="5dip"
android:orientation="horizontal">
<TextView
android:id="@+id/filterInfo"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="end"/>
<Button
android:id="@+id/btn_clear"
android:text="@string/btn_clearFilter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="5dip"
android:orientation="horizontal">
<TextView
android:id="@+id/filterInfo"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="end"/>
<Button
android:id="@+id/btn_clear"
android:text="@string/btn_clearFilter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

View File

@ -1,80 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:singleLine="true"
android:paddingLeft="10dip"
android:layout_marginRight="?android:attr/scrollbarSize"
android:layout_height="?android:attr/listPreferredItemHeight"
android:layout_width="fill_parent">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
android:paddingRight="3dip">
<ImageView
android:id="@+id/ic_masterKey"
android:src="@drawable/key_small"
android:paddingRight="6dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"/>
<TextView
android:id="@+id/keyId"
android:text="Key ID"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="5dip"
android:typeface="monospace"/>
<TextView
android:id="@+id/keyDetails"
android:text="(RSA, 1024bit)"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:gravity="right"
android:orientation="horizontal"
android:paddingBottom="2dip"
android:paddingTop="2dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/ic_encryptKey"
android:src="@drawable/encrypted_small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/ic_signKey"
android:src="@drawable/signed_small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:singleLine="true"
android:paddingLeft="10dip"
android:layout_marginRight="?android:attr/scrollbarSize"
android:layout_height="?android:attr/listPreferredItemHeight"
android:layout_width="fill_parent">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
android:paddingRight="3dip">
<ImageView
android:id="@+id/ic_masterKey"
android:src="@drawable/key_small"
android:paddingRight="6dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"/>
<TextView
android:id="@+id/keyId"
android:text="Key ID"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="5dip"
android:typeface="monospace"/>
<TextView
android:id="@+id/keyDetails"
android:text="(RSA, 1024bit)"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:gravity="right"
android:orientation="horizontal"
android:paddingBottom="2dip"
android:paddingTop="2dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/ic_encryptKey"
android:src="@drawable/encrypted_small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/ic_signKey"
android:src="@drawable/signed_small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -1,33 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingLeft="40dip"
android:layout_marginRight="?android:attr/scrollbarSize"
android:singleLine="true"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight">
<TextView
android:id="@+id/userId"
android:text="User ID"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="3dip"/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingLeft="40dip"
android:layout_marginRight="?android:attr/scrollbarSize"
android:singleLine="true"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight">
<TextView
android:id="@+id/userId"
android:text="User ID"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="3dip"/>
</LinearLayout>

View File

@ -1,258 +1,258 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="app_name">APG</string>
<!-- title_lowerCase: capitalized words, no punctuation -->
<string name="title_mailInbox">Mail Inbox</string>
<string name="title_managePublicKeys">Administrér Offentlige Nøgler</string>
<string name="title_manageSecretKeys">Administrér Private Nøgler</string>
<string name="title_selectRecipients">Vælg Modtagere</string>
<string name="title_selectSignature">Vælg Signatur</string>
<string name="title_encrypt">Kryptér</string>
<string name="title_decrypt">Afkryptér</string>
<string name="title_authentification">Autentificering</string>
<string name="title_createKey">Opret Nøgle</string>
<string name="title_editKey">Redigér Nøgle</string>
<string name="title_preferences">Indstillinger</string>
<string name="title_changePassPhrase">Skift Kodeord</string>
<string name="title_setPassPhrase">Sæt Kodeord</string>
<string name="title_sendEmail">"Send Mail..."</string>
<string name="title_encryptToFile">Kryptér Til Fil</string>
<string name="title_decryptToFile">Afkryptér Til Fil</string>
<string name="title_addAccount">Tilføj Konto</string>
<string name="title_importKeys">Importér Nøgle</string>
<string name="title_exportKey">Eksportér Nøgle</string>
<string name="title_exportKeys">Eksportér Nøgler</string>
<string name="title_keyNotFound">Ingen Nøgle Matchede</string>
<!-- section_lowerCase: capitalized words, no punctuation -->
<string name="section_userIds">Bruger ID</string>
<string name="section_keys">Nøgler</string>
<string name="section_general">Generelt</string>
<string name="section_defaults">Standard Indstillinger</string>
<!-- btn_lowerCase: capitalized words, no punctuation -->
<string name="btn_encryptToClipboard">Kryptér Til Clipboard</string>
<string name="btn_send">Kryptér Og Mail</string>
<string name="btn_encrypt">Kryptér</string>
<string name="btn_decrypt">Afkryptér</string>
<string name="btn_verify">Bekræft</string>
<string name="btn_selectEncryptKeys">Vælg Modtagere</string>
<string name="btn_reply">Svar</string>
<string name="btn_encryptMessage">Kryptér Besked</string>
<string name="btn_decryptMessage">Afkryptér Besked</string>
<string name="btn_encryptFile">Kryptér Fil</string>
<string name="btn_decryptFile">Afkryptér Fil</string>
<string name="btn_save">Gem</string>
<string name="btn_doNotSave">Fortryd</string>
<string name="btn_delete">Slet</string>
<string name="btn_noDate">Ingen</string>
<string name="btn_clearFilter">Ryd Filter</string>
<!-- menu_lowerCase: capitalized words, no punctuation -->
<string name="menu_about">Om APG</string>
<string name="menu_addAccount">Tilføj GMail Konto</string>
<string name="menu_deleteAccount">Slet Konto</string>
<string name="menu_managePublicKeys">Administrér Offentlige Nøgler</string>
<string name="menu_manageSecretKeys">Administrér Private Nøgler</string>
<string name="menu_preferences">Indstillinger</string>
<string name="menu_changePassPhrase">Skift Kodeord</string>
<string name="menu_setPassPhrase">Sæt Kodeord</string>
<string name="menu_importKeys">Importér Nøgler</string>
<string name="menu_exportKeys">Eksportér Nøgler</string>
<string name="menu_exportKey">Eksportér Nøgle</string>
<string name="menu_deleteKey">Slet Nøgle</string>
<string name="menu_createKey">Opret Nøgle</string>
<string name="menu_editKey">Redigér Nøgle</string>
<string name="menu_search">Søg</string>
<!-- label_lowerCase: capitalized words, no punctuation -->
<string name="label_sign">Signér</string>
<string name="label_message">Besked</string>
<string name="label_file">Fil</string>
<string name="label_passPhrase">Kodeord</string>
<string name="label_passPhraseAgain">Igen</string>
<string name="label_algorithm">Algoritme</string>
<string name="label_asciiArmour">ASCII Rustning</string>
<string name="label_selectPublicKeys">Offentlig(e) Nøgle(r)</string>
<string name="label_deleteAfterEncryption">Slet Efter Kryptering</string>
<string name="label_deleteAfterDecryption">Slet Efter Afkryptering</string>
<string name="label_encryptionAlgorithm">Krypteringsalgoritme</string>
<string name="label_hashAlgorithm">Hash-algoritme</string>
<string name="label_asymmetric">Offentlig Nøgle</string>
<string name="label_symmetric">Kodeord</string>
<string name="label_passPhraseCacheTtl">Kodeords Cache</string>
<string name="label_messageCompression">Besked Komprimering</string>
<string name="label_fileCompression">Fil Komprimering</string>
<string name="noKeysSelected">Vælg</string>
<string name="oneKeySelected">1 Valgt</string>
<string name="nKeysSelected">Valgt</string>
<string name="unknownUserId">&lt;ukendt&gt;</string>
<string name="none">&lt;ingen&gt;</string>
<string name="noKey">&lt;ingen nøgle&gt;</string>
<string name="noDate">-</string>
<string name="noExpiry">&lt;udløber ikke&gt;</string>
<string name="unknownStatus"></string>
<string name="canEncrypt">kan kryptere</string>
<string name="canSign">kan signere</string>
<string name="expired">udløbet</string>
<string name="notValid">ugyldig</string>
<!-- choice_lowerCase: capitalized firwst word, no punctuation -->
<string name="choice_none">Ingen</string>
<string name="choice_signOnly">Kun signering</string>
<string name="choice_encryptOnly">Kun kryptering</string>
<string name="choice_signAndEncrypt">Signér og kryptér</string>
<string name="choice_15secs">15 secs</string>
<string name="choice_1min">1 min</string>
<string name="choice_3mins">3 min</string>
<string name="choice_5mins">5 min</string>
<string name="choice_10mins">10 min</string>
<string name="choice_untilQuit">Indtil slut</string>
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
<string name="filemanager_titleOpen">Åbn...</string>
<string name="filemanager_titleSave">Gem Som...</string>
<string name="filemanager_titleEncrypt">Vælg Fil Som Skal Krypteres...</string>
<string name="filemanager_titleDecrypt">Vælg Fil Som Skal Afkrypteres...</string>
<string name="filemanager_btnOpen">Åbn</string>
<string name="filemanager_btnSave">Gem</string>
<string name="warning">Advarsel</string>
<string name="error">Fejl</string>
<string name="warningMessage">Advarsel: %s</string>
<string name="errorMessage">Fejl: %s</string>
<!-- sentences -->
<string name="wrongPassPhrase">Forkert kodeord.</string>
<string name="usingClipboardContent">Bruger clipboardets indhold.</string>
<string name="keySaved">Nøgle gemt.</string>
<string name="setAPassPhrase">Sæt et kodeord via Indstillinger først.</string>
<string name="noFilemanagerInstalled">Der er ikke installeret en kompatibel fil håndtering.</string>
<string name="passPhrasesDoNotMatch">Kodeordet matchede ikke.</string>
<string name="passPhraseMustNotBeEmpty">Et tomt kodeord er ikke tilladt.</string>
<string name="passPhraseForSymmetricEncryption">Kodeord til symmetrisk kryptering:</string>
<string name="passPhraseFor">Kodeord til %s:</string>
<string name="fileDeleteConfirmation">Er du sikker på at du vil slette \n%s?</string>
<string name="fileDeleteSuccessful">Filen er slettet.</string>
<string name="noFileSelected">Vælg en fil først.</string>
<string name="decryptionSuccessful">Afkryptering lykkedes.</string>
<string name="encryptionSuccessful">Kryptering lykkedes.</string>
<string name="encryptionToClipboardSuccessful">Kryptering til clipboard lykkedes.</string>
<string name="enterPassPhraseTwice">Tast kodeordet to gange.</string>
<string name="selectEncryptionKey">Vælg mindst én krypteringsnøgle.</string>
<string name="selectEncryptionOrSignatureKey">Vælg mindst én krypteringsnøgle eller signaturnøgle.</string>
<string name="specifyFileToEncryptTo">Angiv navnet på filen der skal krypteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
<string name="specifyFileToDecryptTo">Angiv navnet på filen der skal afkrypteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
<string name="specifyGoogleMailAccount">Angiv den Google Mail konto du ønsker at tilføje.</string>
<string name="specifyFileToImportFrom">Angiv hvilken fil du ønsker at importere nøgler fra. (.asc eller .gpg)</string>
<string name="specifyFileToExportTo">Angiv hvilken fil der skal eksporteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
<string name="specifyFileToExportSecretKeysTo">Angiv hvilken fil der skal eksporteres til.\nADVARSEL! Du er ved at eksportere PRIVATE nøgler.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
<string name="keyDeletionConfirmation">Ønsker du at slette \'%s\'-nøglen?\nDu kan ikke fortryde denne handling!</string>
<string name="secretKeyDeletionConfirmation">Ønsker du at slette den PRIVATE nøgle, \'%s\'?\nDu kan ikke fortryde denne handling!</string>
<string name="keysAddedAndUpdated">Tilføjelse af %s nøgle(r) og opdatering af %s nøgle(r) lykkedes."</string>
<string name="keysAdded">Tilføjelse af %s nøgle(r) lykkedes.</string>
<string name="keysUpdated">Opdatring af %s nøgle(r) lykkedes.</string>
<string name="noKeysAddedOrUpdated">Ingen nøgler blev tilføjet eller opdateret.</string>
<string name="keyExported">Eksport af 1 nøgle lykkedes.</string>
<string name="keysExported">Eksport af %s nøgler lykkedes.</string>
<string name="noKeysExported">Ingen nøgler blev eksporteret.</string>
<string name="keyCreationElGamalInfo">NB: Kun undernøgler understøtter ElGamal, og for ELGamal vil den nærmeste nøglestørrelse - 1536, 2048, 3072, 4096, eller 8192 - blive brugt.</string>
<string name="keyNotFound">Kunne ikke finde %08X nøglen.</string>
<!-- error_lowerCase: phrases, no punctuation, all lowercase,
they will be put after "errorMessage", e.g. "Error: file not found" -->
<string name="error_fileDeleteFailed">\'%s\' kunne ikke slettes</string>
<string name="error_fileNotFound">filen findes ikke</string>
<string name="error_noSecretKeyFound">ingen egnet privat nøgle fundet</string>
<string name="error_noKnownEncryptionFound">ingen kendt krypterings måde fundet</string>
<string name="error_externalStorageNotReady">ekstern storage er ikke parat</string>
<string name="error_accountNotFound">\'%s\'-kontoen blev ikke fundet</string>
<string name="error_addingAccountFailed">\'%s\'-kontoen kunne ikke tilføjes</string>
<string name="error_invalidEmail">ugyldig email \'%s\'</string>
<string name="error_keySizeMinimum512bit">nøgle størrelsen skal være på mindst 512bit</string>
<string name="error_masterKeyMustNotBeElGamal">hoved nøglen kan ikke være en ElGamal nøgle</string>
<string name="error_unknownAlgorithmChoice">ukendt algoritme valg</string>
<string name="error_userIdNeedsAName">angiv et navn</string>
<string name="error_userIdNeedsAnEmailAddress">angiv en email adresse</string>
<string name="error_keyNeedsAUserId">der skal bruges mindst ét bruger-id</string>
<string name="error_mainUserIdMustNotBeEmpty">hovedbruger-id kan ikke være tomt</string>
<string name="error_keyNeedsMasterKey">der skal mindst bruges en hovednøgle</string>
<string name="error_expiryMustComeAfterCreation">udløbsdatoen skal være senere end oprettelsesdatoen</string>
<string name="error_noEncryptionKeysOrPassPhrase">hverken krypteringsnøgler eller kodeord modtaget</string>
<string name="error_signatureFailed">signering mislykkedes</string>
<string name="error_noSignaturePassPhrase">intet kodeord modtaget</string>
<string name="error_noSignatureKey">ingen signatur nøgle modtaget</string>
<string name="error_invalidData">ikke gyldig krypteringsdata</string>
<string name="error_corruptData">beskadiget data</string>
<string name="error_noSymmetricEncryptionPacket">kunne ikke finde en pakke med symmetrisk kryptering</string>
<string name="error_wrongPassPhrase">forkert kodeord</string>
<string name="error_savingKeys">der opstod en fejl da nøglen eller nøglerne skulle gemmes</string>
<!-- progress_lowerCase: lowercase, phrases, usually ending in '...' -->
<string name="progress_done">færdig.</string>
<string name="progress_initializing">starter op...</string>
<string name="progress_saving">gemmer...</string>
<string name="progress_importing">importerer...</string>
<string name="progress_exporting">eksporterer...</string>
<string name="progress_generating">genererer nøgle, dette kan tage et stykke tid...</string>
<string name="progress_buildingKey">opbygger nøgle...</string>
<string name="progress_preparingMasterKey">forbereder hovednøgle...</string>
<string name="progress_certifyingMasterKey">bekræfter hovednøgle...</string>
<string name="progress_buildingMasterKeyRing">bygger hovednøglering...</string>
<string name="progress_addingSubKeys">tilføjer undernøgler...</string>
<string name="progress_savingKeyRing">gemmer nøglering...</string>
<string name="progress_importingSecretKeys">importerer private nøgler...</string>
<string name="progress_importingPublicKeys">importerer offentlige nøgler...</string>
<string name="progress_reloadingKeys">genloader nøgler...</string>
<string name="progress_exportingKey">eksporterer nøgle...</string>
<string name="progress_exportingKeys">eksporterer nøgler...</string>
<string name="progress_extractingSignatureKey">henter signatur nøgle...</string>
<string name="progress_extractingKey">henter nøgle...</string>
<string name="progress_preparingStreams">forbereder streams...</string>
<string name="progress_encrypting">krypterer data...</string>
<string name="progress_decrypting">afkrypterer data...</string>
<string name="progress_preparingSignature">forbereder signatur...</string>
<string name="progress_generatingSignature">skaber signatur...</string>
<string name="progress_processingSignature">behandler signatur...</string>
<string name="progress_verifyingSignature">bekræfter signatur...</string>
<string name="progress_signing">signerer...</string>
<string name="progress_readingData">læser data...</string>
<string name="progress_findingKey">søger nøgle...</string>
<string name="progress_decompressingData">afkomprimerer data...</string>
<string name="progress_verifyingIntegrity">bekræfter integritet...</string>
<!-- permission strings -->
<string name="permission_read_key_details_label">Læs nøgle detaljer fra APG.</string>
<string name="permission_read_key_details_description">Læs om offentlige og private nøgler gemt i APG, f. eks. nøgle ID og bruger ID. Selve nøglerne kan IKKE læses.</string>
<!-- action strings -->
<string name="action_encrypt">Kryptér</string>
<string name="action_decrypt">Afkryptér</string>
<string name="action_importPublic">Importér Offentlige Nøgler</string>
<string name="action_importSecret">Importér Private Nøgler</string>
<string name="hint_publicKeys">Søg I Offentlige Nøgler</string>
<string name="hint_secretKeys">Søg I Private Nøgler</string>
<string name="filterInfo">Filter: \"%s\"</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="app_name">APG</string>
<!-- title_lowerCase: capitalized words, no punctuation -->
<string name="title_mailInbox">Mail Inbox</string>
<string name="title_managePublicKeys">Administrér Offentlige Nøgler</string>
<string name="title_manageSecretKeys">Administrér Private Nøgler</string>
<string name="title_selectRecipients">Vælg Modtagere</string>
<string name="title_selectSignature">Vælg Signatur</string>
<string name="title_encrypt">Kryptér</string>
<string name="title_decrypt">Afkryptér</string>
<string name="title_authentification">Autentificering</string>
<string name="title_createKey">Opret Nøgle</string>
<string name="title_editKey">Redigér Nøgle</string>
<string name="title_preferences">Indstillinger</string>
<string name="title_changePassPhrase">Skift Kodeord</string>
<string name="title_setPassPhrase">Sæt Kodeord</string>
<string name="title_sendEmail">"Send Mail..."</string>
<string name="title_encryptToFile">Kryptér Til Fil</string>
<string name="title_decryptToFile">Afkryptér Til Fil</string>
<string name="title_addAccount">Tilføj Konto</string>
<string name="title_importKeys">Importér Nøgle</string>
<string name="title_exportKey">Eksportér Nøgle</string>
<string name="title_exportKeys">Eksportér Nøgler</string>
<string name="title_keyNotFound">Ingen Nøgle Matchede</string>
<!-- section_lowerCase: capitalized words, no punctuation -->
<string name="section_userIds">Bruger ID</string>
<string name="section_keys">Nøgler</string>
<string name="section_general">Generelt</string>
<string name="section_defaults">Standard Indstillinger</string>
<!-- btn_lowerCase: capitalized words, no punctuation -->
<string name="btn_encryptToClipboard">Kryptér Til Clipboard</string>
<string name="btn_send">Kryptér Og Mail</string>
<string name="btn_encrypt">Kryptér</string>
<string name="btn_decrypt">Afkryptér</string>
<string name="btn_verify">Bekræft</string>
<string name="btn_selectEncryptKeys">Vælg Modtagere</string>
<string name="btn_reply">Svar</string>
<string name="btn_encryptMessage">Kryptér Besked</string>
<string name="btn_decryptMessage">Afkryptér Besked</string>
<string name="btn_encryptFile">Kryptér Fil</string>
<string name="btn_decryptFile">Afkryptér Fil</string>
<string name="btn_save">Gem</string>
<string name="btn_doNotSave">Fortryd</string>
<string name="btn_delete">Slet</string>
<string name="btn_noDate">Ingen</string>
<string name="btn_clearFilter">Ryd Filter</string>
<!-- menu_lowerCase: capitalized words, no punctuation -->
<string name="menu_about">Om APG</string>
<string name="menu_addAccount">Tilføj GMail Konto</string>
<string name="menu_deleteAccount">Slet Konto</string>
<string name="menu_managePublicKeys">Administrér Offentlige Nøgler</string>
<string name="menu_manageSecretKeys">Administrér Private Nøgler</string>
<string name="menu_preferences">Indstillinger</string>
<string name="menu_changePassPhrase">Skift Kodeord</string>
<string name="menu_setPassPhrase">Sæt Kodeord</string>
<string name="menu_importKeys">Importér Nøgler</string>
<string name="menu_exportKeys">Eksportér Nøgler</string>
<string name="menu_exportKey">Eksportér Nøgle</string>
<string name="menu_deleteKey">Slet Nøgle</string>
<string name="menu_createKey">Opret Nøgle</string>
<string name="menu_editKey">Redigér Nøgle</string>
<string name="menu_search">Søg</string>
<!-- label_lowerCase: capitalized words, no punctuation -->
<string name="label_sign">Signér</string>
<string name="label_message">Besked</string>
<string name="label_file">Fil</string>
<string name="label_passPhrase">Kodeord</string>
<string name="label_passPhraseAgain">Igen</string>
<string name="label_algorithm">Algoritme</string>
<string name="label_asciiArmour">ASCII Rustning</string>
<string name="label_selectPublicKeys">Offentlig(e) Nøgle(r)</string>
<string name="label_deleteAfterEncryption">Slet Efter Kryptering</string>
<string name="label_deleteAfterDecryption">Slet Efter Afkryptering</string>
<string name="label_encryptionAlgorithm">Krypteringsalgoritme</string>
<string name="label_hashAlgorithm">Hash-algoritme</string>
<string name="label_asymmetric">Offentlig Nøgle</string>
<string name="label_symmetric">Kodeord</string>
<string name="label_passPhraseCacheTtl">Kodeords Cache</string>
<string name="label_messageCompression">Besked Komprimering</string>
<string name="label_fileCompression">Fil Komprimering</string>
<string name="noKeysSelected">Vælg</string>
<string name="oneKeySelected">1 Valgt</string>
<string name="nKeysSelected">Valgt</string>
<string name="unknownUserId">&lt;ukendt&gt;</string>
<string name="none">&lt;ingen&gt;</string>
<string name="noKey">&lt;ingen nøgle&gt;</string>
<string name="noDate">-</string>
<string name="noExpiry">&lt;udløber ikke&gt;</string>
<string name="unknownStatus"></string>
<string name="canEncrypt">kan kryptere</string>
<string name="canSign">kan signere</string>
<string name="expired">udløbet</string>
<string name="notValid">ugyldig</string>
<!-- choice_lowerCase: capitalized firwst word, no punctuation -->
<string name="choice_none">Ingen</string>
<string name="choice_signOnly">Kun signering</string>
<string name="choice_encryptOnly">Kun kryptering</string>
<string name="choice_signAndEncrypt">Signér og kryptér</string>
<string name="choice_15secs">15 secs</string>
<string name="choice_1min">1 min</string>
<string name="choice_3mins">3 min</string>
<string name="choice_5mins">5 min</string>
<string name="choice_10mins">10 min</string>
<string name="choice_untilQuit">Indtil slut</string>
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
<string name="filemanager_titleOpen">Åbn...</string>
<string name="filemanager_titleSave">Gem Som...</string>
<string name="filemanager_titleEncrypt">Vælg Fil Som Skal Krypteres...</string>
<string name="filemanager_titleDecrypt">Vælg Fil Som Skal Afkrypteres...</string>
<string name="filemanager_btnOpen">Åbn</string>
<string name="filemanager_btnSave">Gem</string>
<string name="warning">Advarsel</string>
<string name="error">Fejl</string>
<string name="warningMessage">Advarsel: %s</string>
<string name="errorMessage">Fejl: %s</string>
<!-- sentences -->
<string name="wrongPassPhrase">Forkert kodeord.</string>
<string name="usingClipboardContent">Bruger clipboardets indhold.</string>
<string name="keySaved">Nøgle gemt.</string>
<string name="setAPassPhrase">Sæt et kodeord via Indstillinger først.</string>
<string name="noFilemanagerInstalled">Der er ikke installeret en kompatibel fil håndtering.</string>
<string name="passPhrasesDoNotMatch">Kodeordet matchede ikke.</string>
<string name="passPhraseMustNotBeEmpty">Et tomt kodeord er ikke tilladt.</string>
<string name="passPhraseForSymmetricEncryption">Kodeord til symmetrisk kryptering:</string>
<string name="passPhraseFor">Kodeord til %s:</string>
<string name="fileDeleteConfirmation">Er du sikker på at du vil slette \n%s?</string>
<string name="fileDeleteSuccessful">Filen er slettet.</string>
<string name="noFileSelected">Vælg en fil først.</string>
<string name="decryptionSuccessful">Afkryptering lykkedes.</string>
<string name="encryptionSuccessful">Kryptering lykkedes.</string>
<string name="encryptionToClipboardSuccessful">Kryptering til clipboard lykkedes.</string>
<string name="enterPassPhraseTwice">Tast kodeordet to gange.</string>
<string name="selectEncryptionKey">Vælg mindst én krypteringsnøgle.</string>
<string name="selectEncryptionOrSignatureKey">Vælg mindst én krypteringsnøgle eller signaturnøgle.</string>
<string name="specifyFileToEncryptTo">Angiv navnet på filen der skal krypteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
<string name="specifyFileToDecryptTo">Angiv navnet på filen der skal afkrypteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
<string name="specifyGoogleMailAccount">Angiv den Google Mail konto du ønsker at tilføje.</string>
<string name="specifyFileToImportFrom">Angiv hvilken fil du ønsker at importere nøgler fra. (.asc eller .gpg)</string>
<string name="specifyFileToExportTo">Angiv hvilken fil der skal eksporteres til.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
<string name="specifyFileToExportSecretKeysTo">Angiv hvilken fil der skal eksporteres til.\nADVARSEL! Du er ved at eksportere PRIVATE nøgler.\nADVARSEL! Filen vil blive overskrevet hvis den allerede eksisterer.</string>
<string name="keyDeletionConfirmation">Ønsker du at slette \'%s\'-nøglen?\nDu kan ikke fortryde denne handling!</string>
<string name="secretKeyDeletionConfirmation">Ønsker du at slette den PRIVATE nøgle, \'%s\'?\nDu kan ikke fortryde denne handling!</string>
<string name="keysAddedAndUpdated">Tilføjelse af %s nøgle(r) og opdatering af %s nøgle(r) lykkedes."</string>
<string name="keysAdded">Tilføjelse af %s nøgle(r) lykkedes.</string>
<string name="keysUpdated">Opdatring af %s nøgle(r) lykkedes.</string>
<string name="noKeysAddedOrUpdated">Ingen nøgler blev tilføjet eller opdateret.</string>
<string name="keyExported">Eksport af 1 nøgle lykkedes.</string>
<string name="keysExported">Eksport af %s nøgler lykkedes.</string>
<string name="noKeysExported">Ingen nøgler blev eksporteret.</string>
<string name="keyCreationElGamalInfo">NB: Kun undernøgler understøtter ElGamal, og for ELGamal vil den nærmeste nøglestørrelse - 1536, 2048, 3072, 4096, eller 8192 - blive brugt.</string>
<string name="keyNotFound">Kunne ikke finde %08X nøglen.</string>
<!-- error_lowerCase: phrases, no punctuation, all lowercase,
they will be put after "errorMessage", e.g. "Error: file not found" -->
<string name="error_fileDeleteFailed">\'%s\' kunne ikke slettes</string>
<string name="error_fileNotFound">filen findes ikke</string>
<string name="error_noSecretKeyFound">ingen egnet privat nøgle fundet</string>
<string name="error_noKnownEncryptionFound">ingen kendt krypterings måde fundet</string>
<string name="error_externalStorageNotReady">ekstern storage er ikke parat</string>
<string name="error_accountNotFound">\'%s\'-kontoen blev ikke fundet</string>
<string name="error_addingAccountFailed">\'%s\'-kontoen kunne ikke tilføjes</string>
<string name="error_invalidEmail">ugyldig email \'%s\'</string>
<string name="error_keySizeMinimum512bit">nøgle størrelsen skal være på mindst 512bit</string>
<string name="error_masterKeyMustNotBeElGamal">hoved nøglen kan ikke være en ElGamal nøgle</string>
<string name="error_unknownAlgorithmChoice">ukendt algoritme valg</string>
<string name="error_userIdNeedsAName">angiv et navn</string>
<string name="error_userIdNeedsAnEmailAddress">angiv en email adresse</string>
<string name="error_keyNeedsAUserId">der skal bruges mindst ét bruger-id</string>
<string name="error_mainUserIdMustNotBeEmpty">hovedbruger-id kan ikke være tomt</string>
<string name="error_keyNeedsMasterKey">der skal mindst bruges en hovednøgle</string>
<string name="error_expiryMustComeAfterCreation">udløbsdatoen skal være senere end oprettelsesdatoen</string>
<string name="error_noEncryptionKeysOrPassPhrase">hverken krypteringsnøgler eller kodeord modtaget</string>
<string name="error_signatureFailed">signering mislykkedes</string>
<string name="error_noSignaturePassPhrase">intet kodeord modtaget</string>
<string name="error_noSignatureKey">ingen signatur nøgle modtaget</string>
<string name="error_invalidData">ikke gyldig krypteringsdata</string>
<string name="error_corruptData">beskadiget data</string>
<string name="error_noSymmetricEncryptionPacket">kunne ikke finde en pakke med symmetrisk kryptering</string>
<string name="error_wrongPassPhrase">forkert kodeord</string>
<string name="error_savingKeys">der opstod en fejl da nøglen eller nøglerne skulle gemmes</string>
<!-- progress_lowerCase: lowercase, phrases, usually ending in '...' -->
<string name="progress_done">færdig.</string>
<string name="progress_initializing">starter op...</string>
<string name="progress_saving">gemmer...</string>
<string name="progress_importing">importerer...</string>
<string name="progress_exporting">eksporterer...</string>
<string name="progress_generating">genererer nøgle, dette kan tage et stykke tid...</string>
<string name="progress_buildingKey">opbygger nøgle...</string>
<string name="progress_preparingMasterKey">forbereder hovednøgle...</string>
<string name="progress_certifyingMasterKey">bekræfter hovednøgle...</string>
<string name="progress_buildingMasterKeyRing">bygger hovednøglering...</string>
<string name="progress_addingSubKeys">tilføjer undernøgler...</string>
<string name="progress_savingKeyRing">gemmer nøglering...</string>
<string name="progress_importingSecretKeys">importerer private nøgler...</string>
<string name="progress_importingPublicKeys">importerer offentlige nøgler...</string>
<string name="progress_reloadingKeys">genloader nøgler...</string>
<string name="progress_exportingKey">eksporterer nøgle...</string>
<string name="progress_exportingKeys">eksporterer nøgler...</string>
<string name="progress_extractingSignatureKey">henter signatur nøgle...</string>
<string name="progress_extractingKey">henter nøgle...</string>
<string name="progress_preparingStreams">forbereder streams...</string>
<string name="progress_encrypting">krypterer data...</string>
<string name="progress_decrypting">afkrypterer data...</string>
<string name="progress_preparingSignature">forbereder signatur...</string>
<string name="progress_generatingSignature">skaber signatur...</string>
<string name="progress_processingSignature">behandler signatur...</string>
<string name="progress_verifyingSignature">bekræfter signatur...</string>
<string name="progress_signing">signerer...</string>
<string name="progress_readingData">læser data...</string>
<string name="progress_findingKey">søger nøgle...</string>
<string name="progress_decompressingData">afkomprimerer data...</string>
<string name="progress_verifyingIntegrity">bekræfter integritet...</string>
<!-- permission strings -->
<string name="permission_read_key_details_label">Læs nøgle detaljer fra APG.</string>
<string name="permission_read_key_details_description">Læs om offentlige og private nøgler gemt i APG, f. eks. nøgle ID og bruger ID. Selve nøglerne kan IKKE læses.</string>
<!-- action strings -->
<string name="action_encrypt">Kryptér</string>
<string name="action_decrypt">Afkryptér</string>
<string name="action_importPublic">Importér Offentlige Nøgler</string>
<string name="action_importSecret">Importér Private Nøgler</string>
<string name="hint_publicKeys">Søg I Offentlige Nøgler</string>
<string name="hint_secretKeys">Søg I Private Nøgler</string>
<string name="filterInfo">Filter: \"%s\"</string>
</resources>

File diff suppressed because it is too large Load Diff

View File

@ -1,112 +1,112 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import org.bouncycastle2.jce.provider.BouncyCastleProvider;
import org.bouncycastle2.openpgp.PGPException;
import org.bouncycastle2.openpgp.PGPSecretKey;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class AskForSecretKeyPassPhrase {
public static interface PassPhraseCallbackInterface {
void passPhraseCallback(long keyId, String passPhrase);
}
public static Dialog createDialog(Activity context, long secretKeyId,
PassPhraseCallbackInterface callback) {
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle(R.string.title_authentification);
final PGPSecretKey secretKey;
final Activity activity = context;
if (secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none) {
secretKey = null;
alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption));
} else {
secretKey = Apg.getMasterKey(Apg.getSecretKeyRing(secretKeyId));
if (secretKey == null) {
alert.setTitle(R.string.title_keyNotFound);
alert.setMessage(context.getString(R.string.keyNotFound, secretKeyId));
alert.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
activity.removeDialog(Id.dialog.pass_phrase);
}
});
alert.setCancelable(false);
return alert.create();
}
String userId = Apg.getMainUserIdSafe(context, secretKey);
alert.setMessage(context.getString(R.string.passPhraseFor, userId));
}
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.pass_phrase, null);
final EditText input = (EditText) view.findViewById(R.id.passPhrase);
final EditText inputNotUsed = (EditText) view.findViewById(R.id.passPhraseAgain);
inputNotUsed.setVisibility(View.GONE);
alert.setView(view);
final PassPhraseCallbackInterface cb = callback;
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
activity.removeDialog(Id.dialog.pass_phrase);
String passPhrase = "" + input.getText();
long keyId;
if (secretKey != null) {
try {
secretKey.extractPrivateKey(passPhrase.toCharArray(),
new BouncyCastleProvider());
} catch (PGPException e) {
Toast.makeText(activity,
R.string.wrongPassPhrase,
Toast.LENGTH_SHORT).show();
return;
}
keyId = secretKey.getKeyID();
} else {
keyId = Id.key.symmetric;
}
cb.passPhraseCallback(keyId, passPhrase);
}
});
alert.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
activity.removeDialog(Id.dialog.pass_phrase);
}
});
return alert.create();
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import org.bouncycastle2.jce.provider.BouncyCastleProvider;
import org.bouncycastle2.openpgp.PGPException;
import org.bouncycastle2.openpgp.PGPSecretKey;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class AskForSecretKeyPassPhrase {
public static interface PassPhraseCallbackInterface {
void passPhraseCallback(long keyId, String passPhrase);
}
public static Dialog createDialog(Activity context, long secretKeyId,
PassPhraseCallbackInterface callback) {
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle(R.string.title_authentification);
final PGPSecretKey secretKey;
final Activity activity = context;
if (secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none) {
secretKey = null;
alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption));
} else {
secretKey = Apg.getMasterKey(Apg.getSecretKeyRing(secretKeyId));
if (secretKey == null) {
alert.setTitle(R.string.title_keyNotFound);
alert.setMessage(context.getString(R.string.keyNotFound, secretKeyId));
alert.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
activity.removeDialog(Id.dialog.pass_phrase);
}
});
alert.setCancelable(false);
return alert.create();
}
String userId = Apg.getMainUserIdSafe(context, secretKey);
alert.setMessage(context.getString(R.string.passPhraseFor, userId));
}
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.pass_phrase, null);
final EditText input = (EditText) view.findViewById(R.id.passPhrase);
final EditText inputNotUsed = (EditText) view.findViewById(R.id.passPhraseAgain);
inputNotUsed.setVisibility(View.GONE);
alert.setView(view);
final PassPhraseCallbackInterface cb = callback;
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
activity.removeDialog(Id.dialog.pass_phrase);
String passPhrase = "" + input.getText();
long keyId;
if (secretKey != null) {
try {
secretKey.extractPrivateKey(passPhrase.toCharArray(),
new BouncyCastleProvider());
} catch (PGPException e) {
Toast.makeText(activity,
R.string.wrongPassPhrase,
Toast.LENGTH_SHORT).show();
return;
}
keyId = secretKey.getKeyID();
} else {
keyId = Id.key.symmetric;
}
cb.passPhraseCallback(keyId, passPhrase);
}
});
alert.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
activity.removeDialog(Id.dialog.pass_phrase);
}
});
return alert.create();
}
}

View File

@ -1,381 +1,381 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import java.io.File;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class BaseActivity extends Activity
implements Runnable, ProgressDialogUpdater,
AskForSecretKeyPassPhrase.PassPhraseCallbackInterface {
private ProgressDialog mProgressDialog = null;
private Thread mRunningThread = null;
private long mSecretKeyId = 0;
private String mDeleteFile = null;
protected Preferences mPreferences;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
handlerCallback(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPreferences = Preferences.getPreferences(this);
Apg.initialize(this);
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dir = new File(Constants.path.app_dir);
if (!dir.exists() && !dir.mkdirs()) {
// ignore this for now, it's not crucial
// that the directory doesn't exist at this point
}
}
startCacheService(this, mPreferences);
}
public static void startCacheService(Activity activity, Preferences preferences) {
Intent intent = new Intent(activity, Service.class);
intent.putExtra(Service.EXTRA_TTL, preferences.getPassPhraseCacheTtl());
activity.startService(intent);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, Id.menu.option.preferences, 0, R.string.menu_preferences)
.setIcon(android.R.drawable.ic_menu_preferences);
menu.add(0, Id.menu.option.about, 1, R.string.menu_about)
.setIcon(android.R.drawable.ic_menu_info_details);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case Id.menu.option.about: {
showDialog(Id.dialog.about);
return true;
}
case Id.menu.option.preferences: {
startActivity(new Intent(this, PreferencesActivity.class));
return true;
}
case Id.menu.option.search: {
startSearch("", false, null, false);
return true;
}
default: {
break;
}
}
return false;
}
@Override
protected Dialog onCreateDialog(int id) {
// in case it is a progress dialog
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(false);
switch (id) {
case Id.dialog.encrypting: {
mProgressDialog.setMessage(this.getString(R.string.progress_initializing));
return mProgressDialog;
}
case Id.dialog.decrypting: {
mProgressDialog.setMessage(this.getString(R.string.progress_initializing));
return mProgressDialog;
}
case Id.dialog.saving: {
mProgressDialog.setMessage(this.getString(R.string.progress_saving));
return mProgressDialog;
}
case Id.dialog.importing: {
mProgressDialog.setMessage(this.getString(R.string.progress_importing));
return mProgressDialog;
}
case Id.dialog.exporting: {
mProgressDialog.setMessage(this.getString(R.string.progress_exporting));
return mProgressDialog;
}
default: {
break;
}
}
mProgressDialog = null;
switch (id) {
case Id.dialog.about: {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("About " + Apg.getFullVersion(this));
LayoutInflater inflater =
(LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.info, null);
TextView message = (TextView) layout.findViewById(R.id.message);
message.setText("This is an attempt to bring OpenPGP to Android. " +
"It is far from complete, but more features are planned (see website).\n\n" +
"Feel free to send bug reports, suggestions, feature requests, feedback, " +
"photographs.\n\n" +
"mail: thi@thialfihar.org\n" +
"site: http://apg.thialfihar.org\n\n" +
"This software is provided \"as is\", without warranty of any kind.");
alert.setView(layout);
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
BaseActivity.this.removeDialog(Id.dialog.about);
}
});
return alert.create();
}
case Id.dialog.pass_phrase: {
return AskForSecretKeyPassPhrase.createDialog(this, getSecretKeyId(), this);
}
case Id.dialog.pass_phrases_do_not_match: {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setIcon(android.R.drawable.ic_dialog_alert);
alert.setTitle(R.string.error);
alert.setMessage(R.string.passPhrasesDoNotMatch);
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
removeDialog(Id.dialog.pass_phrases_do_not_match);
}
});
alert.setCancelable(false);
return alert.create();
}
case Id.dialog.no_pass_phrase: {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setIcon(android.R.drawable.ic_dialog_alert);
alert.setTitle(R.string.error);
alert.setMessage(R.string.passPhraseMustNotBeEmpty);
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
removeDialog(Id.dialog.no_pass_phrase);
}
});
alert.setCancelable(false);
return alert.create();
}
case Id.dialog.delete_file: {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setIcon(android.R.drawable.ic_dialog_alert);
alert.setTitle(R.string.warning);
alert.setMessage(this.getString(R.string.fileDeleteConfirmation, getDeleteFile()));
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
removeDialog(Id.dialog.delete_file);
File file = new File(getDeleteFile());
String msg = "";
if (file.delete()) {
msg = BaseActivity.this.getString(
R.string.fileDeleteSuccessful);
} else {
msg = BaseActivity.this.getString(
R.string.errorMessage,
BaseActivity.this.getString(
R.string.error_fileDeleteFailed, file));
}
Toast.makeText(BaseActivity.this,
msg, Toast.LENGTH_SHORT).show();
}
});
alert.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
removeDialog(Id.dialog.delete_file);
}
});
alert.setCancelable(true);
return alert.create();
}
default: {
break;
}
}
return super.onCreateDialog(id);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Id.request.secret_keys: {
if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras();
setSecretKeyId(bundle.getLong(Apg.EXTRA_KEY_ID));
} else {
setSecretKeyId(Id.key.none);
}
break;
}
default: {
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
public void setProgress(int resourceId, int progress, int max) {
setProgress(getString(resourceId), progress, max);
}
public void setProgress(int progress, int max) {
Message msg = new Message();
Bundle data = new Bundle();
data.putInt(Apg.EXTRA_STATUS, Id.message.progress_update);
data.putInt(Apg.EXTRA_PROGRESS, progress);
data.putInt(Apg.EXTRA_MAX, max);
msg.setData(data);
mHandler.sendMessage(msg);
}
public void setProgress(String message, int progress, int max) {
Message msg = new Message();
Bundle data = new Bundle();
data.putInt(Apg.EXTRA_STATUS, Id.message.progress_update);
data.putString(Apg.EXTRA_MESSAGE, message);
data.putInt(Apg.EXTRA_PROGRESS, progress);
data.putInt(Apg.EXTRA_MAX, max);
msg.setData(data);
mHandler.sendMessage(msg);
}
public void handlerCallback(Message msg) {
Bundle data = msg.getData();
if (data == null) {
return;
}
int type = data.getInt(Apg.EXTRA_STATUS);
switch (type) {
case Id.message.progress_update: {
String message = data.getString(Apg.EXTRA_MESSAGE);
if (mProgressDialog != null) {
if (message != null) {
mProgressDialog.setMessage(message);
}
mProgressDialog.setMax(data.getInt(Apg.EXTRA_MAX));
mProgressDialog.setProgress(data.getInt(Apg.EXTRA_PROGRESS));
}
break;
}
case Id.message.import_done: // intentionall no break
case Id.message.export_done: // intentionall no break
case Id.message.done: {
mProgressDialog = null;
doneCallback(msg);
break;
}
}
}
public void doneCallback(Message msg) {
}
public void passPhraseCallback(long keyId, String passPhrase) {
Apg.setCachedPassPhrase(keyId, passPhrase);
}
public void sendMessage(Message msg) {
mHandler.sendMessage(msg);
}
public void startThread() {
mRunningThread = new Thread(this);
mRunningThread.start();
}
public void run() {
}
public void setSecretKeyId(long id) {
mSecretKeyId = id;
}
public long getSecretKeyId() {
return mSecretKeyId;
}
protected void setDeleteFile(String deleteFile) {
mDeleteFile = deleteFile;
}
protected String getDeleteFile() {
return mDeleteFile;
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import java.io.File;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class BaseActivity extends Activity
implements Runnable, ProgressDialogUpdater,
AskForSecretKeyPassPhrase.PassPhraseCallbackInterface {
private ProgressDialog mProgressDialog = null;
private Thread mRunningThread = null;
private long mSecretKeyId = 0;
private String mDeleteFile = null;
protected Preferences mPreferences;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
handlerCallback(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPreferences = Preferences.getPreferences(this);
Apg.initialize(this);
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dir = new File(Constants.path.app_dir);
if (!dir.exists() && !dir.mkdirs()) {
// ignore this for now, it's not crucial
// that the directory doesn't exist at this point
}
}
startCacheService(this, mPreferences);
}
public static void startCacheService(Activity activity, Preferences preferences) {
Intent intent = new Intent(activity, Service.class);
intent.putExtra(Service.EXTRA_TTL, preferences.getPassPhraseCacheTtl());
activity.startService(intent);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, Id.menu.option.preferences, 0, R.string.menu_preferences)
.setIcon(android.R.drawable.ic_menu_preferences);
menu.add(0, Id.menu.option.about, 1, R.string.menu_about)
.setIcon(android.R.drawable.ic_menu_info_details);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case Id.menu.option.about: {
showDialog(Id.dialog.about);
return true;
}
case Id.menu.option.preferences: {
startActivity(new Intent(this, PreferencesActivity.class));
return true;
}
case Id.menu.option.search: {
startSearch("", false, null, false);
return true;
}
default: {
break;
}
}
return false;
}
@Override
protected Dialog onCreateDialog(int id) {
// in case it is a progress dialog
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(false);
switch (id) {
case Id.dialog.encrypting: {
mProgressDialog.setMessage(this.getString(R.string.progress_initializing));
return mProgressDialog;
}
case Id.dialog.decrypting: {
mProgressDialog.setMessage(this.getString(R.string.progress_initializing));
return mProgressDialog;
}
case Id.dialog.saving: {
mProgressDialog.setMessage(this.getString(R.string.progress_saving));
return mProgressDialog;
}
case Id.dialog.importing: {
mProgressDialog.setMessage(this.getString(R.string.progress_importing));
return mProgressDialog;
}
case Id.dialog.exporting: {
mProgressDialog.setMessage(this.getString(R.string.progress_exporting));
return mProgressDialog;
}
default: {
break;
}
}
mProgressDialog = null;
switch (id) {
case Id.dialog.about: {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("About " + Apg.getFullVersion(this));
LayoutInflater inflater =
(LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.info, null);
TextView message = (TextView) layout.findViewById(R.id.message);
message.setText("This is an attempt to bring OpenPGP to Android. " +
"It is far from complete, but more features are planned (see website).\n\n" +
"Feel free to send bug reports, suggestions, feature requests, feedback, " +
"photographs.\n\n" +
"mail: thi@thialfihar.org\n" +
"site: http://apg.thialfihar.org\n\n" +
"This software is provided \"as is\", without warranty of any kind.");
alert.setView(layout);
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
BaseActivity.this.removeDialog(Id.dialog.about);
}
});
return alert.create();
}
case Id.dialog.pass_phrase: {
return AskForSecretKeyPassPhrase.createDialog(this, getSecretKeyId(), this);
}
case Id.dialog.pass_phrases_do_not_match: {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setIcon(android.R.drawable.ic_dialog_alert);
alert.setTitle(R.string.error);
alert.setMessage(R.string.passPhrasesDoNotMatch);
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
removeDialog(Id.dialog.pass_phrases_do_not_match);
}
});
alert.setCancelable(false);
return alert.create();
}
case Id.dialog.no_pass_phrase: {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setIcon(android.R.drawable.ic_dialog_alert);
alert.setTitle(R.string.error);
alert.setMessage(R.string.passPhraseMustNotBeEmpty);
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
removeDialog(Id.dialog.no_pass_phrase);
}
});
alert.setCancelable(false);
return alert.create();
}
case Id.dialog.delete_file: {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setIcon(android.R.drawable.ic_dialog_alert);
alert.setTitle(R.string.warning);
alert.setMessage(this.getString(R.string.fileDeleteConfirmation, getDeleteFile()));
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
removeDialog(Id.dialog.delete_file);
File file = new File(getDeleteFile());
String msg = "";
if (file.delete()) {
msg = BaseActivity.this.getString(
R.string.fileDeleteSuccessful);
} else {
msg = BaseActivity.this.getString(
R.string.errorMessage,
BaseActivity.this.getString(
R.string.error_fileDeleteFailed, file));
}
Toast.makeText(BaseActivity.this,
msg, Toast.LENGTH_SHORT).show();
}
});
alert.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
removeDialog(Id.dialog.delete_file);
}
});
alert.setCancelable(true);
return alert.create();
}
default: {
break;
}
}
return super.onCreateDialog(id);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Id.request.secret_keys: {
if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras();
setSecretKeyId(bundle.getLong(Apg.EXTRA_KEY_ID));
} else {
setSecretKeyId(Id.key.none);
}
break;
}
default: {
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
public void setProgress(int resourceId, int progress, int max) {
setProgress(getString(resourceId), progress, max);
}
public void setProgress(int progress, int max) {
Message msg = new Message();
Bundle data = new Bundle();
data.putInt(Apg.EXTRA_STATUS, Id.message.progress_update);
data.putInt(Apg.EXTRA_PROGRESS, progress);
data.putInt(Apg.EXTRA_MAX, max);
msg.setData(data);
mHandler.sendMessage(msg);
}
public void setProgress(String message, int progress, int max) {
Message msg = new Message();
Bundle data = new Bundle();
data.putInt(Apg.EXTRA_STATUS, Id.message.progress_update);
data.putString(Apg.EXTRA_MESSAGE, message);
data.putInt(Apg.EXTRA_PROGRESS, progress);
data.putInt(Apg.EXTRA_MAX, max);
msg.setData(data);
mHandler.sendMessage(msg);
}
public void handlerCallback(Message msg) {
Bundle data = msg.getData();
if (data == null) {
return;
}
int type = data.getInt(Apg.EXTRA_STATUS);
switch (type) {
case Id.message.progress_update: {
String message = data.getString(Apg.EXTRA_MESSAGE);
if (mProgressDialog != null) {
if (message != null) {
mProgressDialog.setMessage(message);
}
mProgressDialog.setMax(data.getInt(Apg.EXTRA_MAX));
mProgressDialog.setProgress(data.getInt(Apg.EXTRA_PROGRESS));
}
break;
}
case Id.message.import_done: // intentionall no break
case Id.message.export_done: // intentionall no break
case Id.message.done: {
mProgressDialog = null;
doneCallback(msg);
break;
}
}
}
public void doneCallback(Message msg) {
}
public void passPhraseCallback(long keyId, String passPhrase) {
Apg.setCachedPassPhrase(keyId, passPhrase);
}
public void sendMessage(Message msg) {
mHandler.sendMessage(msg);
}
public void startThread() {
mRunningThread = new Thread(this);
mRunningThread.start();
}
public void run() {
}
public void setSecretKeyId(long id) {
mSecretKeyId = id;
}
public long getSecretKeyId() {
return mSecretKeyId;
}
protected void setDeleteFile(String deleteFile) {
mDeleteFile = deleteFile;
}
protected String getDeleteFile() {
return mDeleteFile;
}
}

View File

@ -1,45 +1,45 @@
package org.thialfihar.android.apg;
public class CachedPassPhrase {
public final long timestamp;
public final String passPhrase;
public CachedPassPhrase(long timestamp, String passPhrase) {
super();
this.timestamp = timestamp;
this.passPhrase = passPhrase;
}
public int hashCode() {
int hc1 = (int)(this.timestamp & 0xffffffff);
int hc2 = (this.passPhrase == null ? 0 : this.passPhrase.hashCode());
return (hc1 + hc2) * hc2 + hc1;
}
public boolean equals(Object other) {
if (!(other instanceof CachedPassPhrase)) {
return false;
}
CachedPassPhrase o = (CachedPassPhrase) other;
if (timestamp != o.timestamp) {
return false;
}
if (passPhrase != o.passPhrase) {
if (passPhrase == null || o.passPhrase == null) {
return false;
}
if (!passPhrase.equals(o.passPhrase)) {
return false;
}
}
return true;
}
public String toString() {
return "(" + timestamp + ", *******)";
}
}
package org.thialfihar.android.apg;
public class CachedPassPhrase {
public final long timestamp;
public final String passPhrase;
public CachedPassPhrase(long timestamp, String passPhrase) {
super();
this.timestamp = timestamp;
this.passPhrase = passPhrase;
}
public int hashCode() {
int hc1 = (int)(this.timestamp & 0xffffffff);
int hc2 = (this.passPhrase == null ? 0 : this.passPhrase.hashCode());
return (hc1 + hc2) * hc2 + hc1;
}
public boolean equals(Object other) {
if (!(other instanceof CachedPassPhrase)) {
return false;
}
CachedPassPhrase o = (CachedPassPhrase) other;
if (timestamp != o.timestamp) {
return false;
}
if (passPhrase != o.passPhrase) {
if (passPhrase == null || o.passPhrase == null) {
return false;
}
if (!passPhrase.equals(o.passPhrase)) {
return false;
}
}
return true;
}
public String toString() {
return "(" + timestamp + ", *******)";
}
}

View File

@ -1,35 +1,35 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import android.os.Environment;
public final class Constants {
public static final class path {
public static final String app_dir = Environment.getExternalStorageDirectory() + "/APG";
}
public static final class pref {
public static final String has_seen_change_log = "seenChangeLogDialog";
public static final String default_encryption_algorithm = "defaultEncryptionAlgorithm";
public static final String default_hash_algorithm = "defaultHashAlgorithm";
public static final String default_ascii_armour = "defaultAsciiArmour";
public static final String default_message_compression = "defaultMessageCompression";
public static final String default_file_compression = "defaultFileCompression";
public static final String pass_phrase_cache_ttl = "passPhraseCacheTtl";
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import android.os.Environment;
public final class Constants {
public static final class path {
public static final String app_dir = Environment.getExternalStorageDirectory() + "/APG";
}
public static final class pref {
public static final String has_seen_change_log = "seenChangeLogDialog";
public static final String default_encryption_algorithm = "defaultEncryptionAlgorithm";
public static final String default_hash_algorithm = "defaultHashAlgorithm";
public static final String default_ascii_armour = "defaultAsciiArmour";
public static final String default_message_compression = "defaultMessageCompression";
public static final String default_file_compression = "defaultFileCompression";
public static final String pass_phrase_cache_ttl = "passPhraseCacheTtl";
}
}

View File

@ -1,79 +1,79 @@
package org.thialfihar.android.apg;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.thialfihar.android.apg.Apg.GeneralException;
import android.content.Context;
import android.os.Environment;
public class DataDestination {
private String mStreamFilename;
private String mFilename;
private int mMode = Id.mode.undefined;
public DataDestination() {
}
public void setMode(int mode) {
mMode = mode;
}
public void setFilename(String filename) {
mFilename = filename;
}
public String getStreamFilename() {
return mStreamFilename;
}
protected OutputStream getOutputStream(Context context)
throws Apg.GeneralException, FileNotFoundException, IOException {
OutputStream out = null;
mStreamFilename = null;
switch (mMode) {
case Id.mode.stream: {
try {
while (true) {
mStreamFilename = Apg.generateRandomString(32);
if (mStreamFilename == null) {
throw new Apg.GeneralException("couldn't generate random file name");
}
context.openFileInput(mStreamFilename).close();
}
} catch (FileNotFoundException e) {
// found a name that isn't used yet
}
out = context.openFileOutput(mStreamFilename, Context.MODE_PRIVATE);
break;
}
case Id.mode.byte_array: {
out = new ByteArrayOutputStream();
break;
}
case Id.mode.file: {
if (mFilename.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
}
}
out = new FileOutputStream(mFilename);
break;
}
default: {
break;
}
}
return out;
}
}
package org.thialfihar.android.apg;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.thialfihar.android.apg.Apg.GeneralException;
import android.content.Context;
import android.os.Environment;
public class DataDestination {
private String mStreamFilename;
private String mFilename;
private int mMode = Id.mode.undefined;
public DataDestination() {
}
public void setMode(int mode) {
mMode = mode;
}
public void setFilename(String filename) {
mFilename = filename;
}
public String getStreamFilename() {
return mStreamFilename;
}
protected OutputStream getOutputStream(Context context)
throws Apg.GeneralException, FileNotFoundException, IOException {
OutputStream out = null;
mStreamFilename = null;
switch (mMode) {
case Id.mode.stream: {
try {
while (true) {
mStreamFilename = Apg.generateRandomString(32);
if (mStreamFilename == null) {
throw new Apg.GeneralException("couldn't generate random file name");
}
context.openFileInput(mStreamFilename).close();
}
} catch (FileNotFoundException e) {
// found a name that isn't used yet
}
out = context.openFileOutput(mStreamFilename, Context.MODE_PRIVATE);
break;
}
case Id.mode.byte_array: {
out = new ByteArrayOutputStream();
break;
}
case Id.mode.file: {
if (mFilename.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
}
}
out = new FileOutputStream(mFilename);
break;
}
default: {
break;
}
}
return out;
}
}

View File

@ -1,88 +1,88 @@
package org.thialfihar.android.apg;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import org.thialfihar.android.apg.Apg.GeneralException;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
public class DataSource {
private Uri mContentUri = null;
private String mText = null;
private byte[] mData = null;
public DataSource() {
}
public void setUri(Uri uri) {
mContentUri = uri;
}
public void setUri(String uri) {
if (uri.startsWith("/")) {
setUri(Uri.parse("file://" + uri));
} else {
setUri(Uri.parse(uri));
}
}
public void setText(String text) {
mText = text;
}
public void setData(byte[] data) {
mData = data;
}
public InputData getInputData(Context context, boolean withSize)
throws GeneralException, FileNotFoundException, IOException {
InputStream in = null;
long size = 0;
if (mContentUri != null) {
if (mContentUri.getScheme().equals("file")) {
// get the rest after "file://"
String path = mContentUri.toString().substring(6);
if (path.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
}
}
in = new FileInputStream(path);
File file = new File(path);
if (withSize) {
size = file.length();
}
} else {
in = context.getContentResolver().openInputStream(mContentUri);
if (withSize) {
InputStream tmp = context.getContentResolver().openInputStream(mContentUri);
size = Apg.getLengthOfStream(tmp);
tmp.close();
}
}
} else if (mText != null || mData != null) {
byte[] bytes = null;
if (mData != null) {
bytes = mData;
} else {
bytes = mText.getBytes();
}
in = new ByteArrayInputStream(bytes);
if (withSize) {
size = bytes.length;
}
}
return new InputData(in, size);
}
}
package org.thialfihar.android.apg;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import org.thialfihar.android.apg.Apg.GeneralException;
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
public class DataSource {
private Uri mContentUri = null;
private String mText = null;
private byte[] mData = null;
public DataSource() {
}
public void setUri(Uri uri) {
mContentUri = uri;
}
public void setUri(String uri) {
if (uri.startsWith("/")) {
setUri(Uri.parse("file://" + uri));
} else {
setUri(Uri.parse(uri));
}
}
public void setText(String text) {
mText = text;
}
public void setData(byte[] data) {
mData = data;
}
public InputData getInputData(Context context, boolean withSize)
throws GeneralException, FileNotFoundException, IOException {
InputStream in = null;
long size = 0;
if (mContentUri != null) {
if (mContentUri.getScheme().equals("file")) {
// get the rest after "file://"
String path = mContentUri.toString().substring(6);
if (path.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
}
}
in = new FileInputStream(path);
File file = new File(path);
if (withSize) {
size = file.length();
}
} else {
in = context.getContentResolver().openInputStream(mContentUri);
if (withSize) {
InputStream tmp = context.getContentResolver().openInputStream(mContentUri);
size = Apg.getLengthOfStream(tmp);
tmp.close();
}
}
} else if (mText != null || mData != null) {
byte[] bytes = null;
if (mData != null) {
bytes = mData;
} else {
bytes = mText.getBytes();
}
in = new ByteArrayInputStream(bytes);
if (withSize) {
size = bytes.length;
}
}
return new InputData(in, size);
}
}

View File

@ -1,118 +1,118 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
public class FileDialog {
private static EditText mFilename;
private static ImageButton mBrowse;
private static Activity mActivity;
private static String mFileManagerTitle;
private static String mFileManagerButton;
private static int mRequestCode;
public static interface OnClickListener {
public void onCancelClick();
public void onOkClick(String filename);
}
public static AlertDialog build(Activity activity, String title, String message,
String defaultFile, OnClickListener onClickListener,
String fileManagerTitle, String fileManagerButton,
int requestCode) {
// TODO: fileManagerTitle and fileManagerButton are deprecated, no use for them right now,
// but maybe the Intent now used will someday support them again, so leaving them in
LayoutInflater inflater =
(LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
alert.setTitle(title);
alert.setMessage(message);
View view = (View) inflater.inflate(R.layout.file_dialog, null);
mActivity = activity;
mFilename = (EditText) view.findViewById(R.id.input);
mFilename.setText(defaultFile);
mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);
mBrowse.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openFile();
}
});
mFileManagerTitle = fileManagerTitle;
mFileManagerButton = fileManagerButton;
mRequestCode = requestCode;
alert.setView(view);
final OnClickListener clickListener = onClickListener;
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
clickListener.onOkClick(mFilename.getText().toString());
}
});
alert.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
clickListener.onCancelClick();
}
});
return alert.create();
}
public static void setFilename(String filename) {
if (mFilename != null) {
mFilename.setText(filename);
}
}
/**
* Opens the file manager to select a file to open.
*/
private static void openFile() {
String filename = mFilename.getText().toString();
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setData(Uri.parse("file://" + filename));
intent.setType("*/*");
try {
mActivity.startActivityForResult(intent, mRequestCode);
} catch (ActivityNotFoundException e) {
// No compatible file manager was found.
Toast.makeText(mActivity, R.string.noFilemanagerInstalled, Toast.LENGTH_SHORT).show();
}
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
public class FileDialog {
private static EditText mFilename;
private static ImageButton mBrowse;
private static Activity mActivity;
private static String mFileManagerTitle;
private static String mFileManagerButton;
private static int mRequestCode;
public static interface OnClickListener {
public void onCancelClick();
public void onOkClick(String filename);
}
public static AlertDialog build(Activity activity, String title, String message,
String defaultFile, OnClickListener onClickListener,
String fileManagerTitle, String fileManagerButton,
int requestCode) {
// TODO: fileManagerTitle and fileManagerButton are deprecated, no use for them right now,
// but maybe the Intent now used will someday support them again, so leaving them in
LayoutInflater inflater =
(LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
alert.setTitle(title);
alert.setMessage(message);
View view = (View) inflater.inflate(R.layout.file_dialog, null);
mActivity = activity;
mFilename = (EditText) view.findViewById(R.id.input);
mFilename.setText(defaultFile);
mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);
mBrowse.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openFile();
}
});
mFileManagerTitle = fileManagerTitle;
mFileManagerButton = fileManagerButton;
mRequestCode = requestCode;
alert.setView(view);
final OnClickListener clickListener = onClickListener;
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
clickListener.onOkClick(mFilename.getText().toString());
}
});
alert.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
clickListener.onCancelClick();
}
});
return alert.create();
}
public static void setFilename(String filename) {
if (mFilename != null) {
mFilename.setText(filename);
}
}
/**
* Opens the file manager to select a file to open.
*/
private static void openFile() {
String filename = mFilename.getText().toString();
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setData(Uri.parse("file://" + filename));
intent.setType("*/*");
try {
mActivity.startActivityForResult(intent, mRequestCode);
} catch (ActivityNotFoundException e) {
// No compatible file manager was found.
Toast.makeText(mActivity, R.string.noFilemanagerInstalled, Toast.LENGTH_SHORT).show();
}
}
}

View File

@ -1,177 +1,177 @@
package org.thialfihar.android.apg;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import org.thialfihar.android.apg.utils.Choice;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
public class GeneralActivity extends BaseActivity {
private Intent mIntent;
private ArrayAdapter<Choice> mAdapter;
private ListView mList;
private Button mCancelButton;
private String mDataString;
private Uri mDataUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.general);
mIntent = getIntent();
InputStream inStream = null;
{
String data = mIntent.getStringExtra(Intent.EXTRA_TEXT);
if (data != null) {
mDataString = data;
inStream = new ByteArrayInputStream(data.getBytes());
}
}
if (inStream == null) {
Uri data = mIntent.getData();
if (data != null) {
mDataUri = data;
try {
inStream = getContentResolver().openInputStream(data);
} catch (FileNotFoundException e) {
// didn't work
Toast.makeText(this, "failed to open stream", Toast.LENGTH_SHORT).show();
}
}
}
if (inStream == null) {
Toast.makeText(this, "no data found", Toast.LENGTH_SHORT).show();
finish();
return;
}
int contentType = Id.content.unknown;
try {
contentType = Apg.getStreamContent(this, inStream);
inStream.close();
} catch (IOException e) {
// just means that there's no PGP data in there
}
mList = (ListView) findViewById(R.id.options);
Vector<Choice> choices = new Vector<Choice>();
if (contentType == Id.content.keys) {
choices.add(new Choice(Id.choice.action.import_public,
getString(R.string.action_importPublic)));
choices.add(new Choice(Id.choice.action.import_secret,
getString(R.string.action_importSecret)));
}
if (contentType == Id.content.encrypted_data) {
choices.add(new Choice(Id.choice.action.decrypt, getString(R.string.action_decrypt)));
}
if (contentType == Id.content.unknown) {
choices.add(new Choice(Id.choice.action.encrypt, getString(R.string.action_encrypt)));
}
mAdapter = new ArrayAdapter<Choice>(this, android.R.layout.simple_list_item_1, choices);
mList.setAdapter(mAdapter);
mList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
clicked(mAdapter.getItem(arg2).getId());
}
});
mCancelButton = (Button) findViewById(R.id.btn_cancel);
mCancelButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
GeneralActivity.this.finish();
}
});
if (choices.size() == 1) {
clicked(choices.get(0).getId());
}
}
private void clicked(int id) {
Intent intent = new Intent();
switch (id) {
case Id.choice.action.encrypt: {
intent.setClass(this, EncryptActivity.class);
if (mDataString != null) {
intent.setAction(Apg.Intent.ENCRYPT);
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
intent.setAction(Apg.Intent.ENCRYPT_FILE);
intent.setDataAndType(mDataUri, mIntent.getType());
}
break;
}
case Id.choice.action.decrypt: {
intent.setClass(this, DecryptActivity.class);
if (mDataString != null) {
intent.setAction(Apg.Intent.DECRYPT);
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
intent.setAction(Apg.Intent.DECRYPT_FILE);
intent.setDataAndType(mDataUri, mIntent.getType());
}
break;
}
case Id.choice.action.import_public: {
intent.setClass(this, PublicKeyListActivity.class);
intent.setAction(Apg.Intent.IMPORT);
if (mDataString != null) {
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
intent.setDataAndType(mDataUri, mIntent.getType());
}
break;
}
case Id.choice.action.import_secret: {
intent.setClass(this, SecretKeyListActivity.class);
intent.setAction(Apg.Intent.IMPORT);
if (mDataString != null) {
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
intent.setDataAndType(mDataUri, mIntent.getType());
}
break;
}
default: {
// shouldn't happen
return;
}
}
startActivity(intent);
finish();
}
}
package org.thialfihar.android.apg;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import org.thialfihar.android.apg.utils.Choice;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
public class GeneralActivity extends BaseActivity {
private Intent mIntent;
private ArrayAdapter<Choice> mAdapter;
private ListView mList;
private Button mCancelButton;
private String mDataString;
private Uri mDataUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.general);
mIntent = getIntent();
InputStream inStream = null;
{
String data = mIntent.getStringExtra(Intent.EXTRA_TEXT);
if (data != null) {
mDataString = data;
inStream = new ByteArrayInputStream(data.getBytes());
}
}
if (inStream == null) {
Uri data = mIntent.getData();
if (data != null) {
mDataUri = data;
try {
inStream = getContentResolver().openInputStream(data);
} catch (FileNotFoundException e) {
// didn't work
Toast.makeText(this, "failed to open stream", Toast.LENGTH_SHORT).show();
}
}
}
if (inStream == null) {
Toast.makeText(this, "no data found", Toast.LENGTH_SHORT).show();
finish();
return;
}
int contentType = Id.content.unknown;
try {
contentType = Apg.getStreamContent(this, inStream);
inStream.close();
} catch (IOException e) {
// just means that there's no PGP data in there
}
mList = (ListView) findViewById(R.id.options);
Vector<Choice> choices = new Vector<Choice>();
if (contentType == Id.content.keys) {
choices.add(new Choice(Id.choice.action.import_public,
getString(R.string.action_importPublic)));
choices.add(new Choice(Id.choice.action.import_secret,
getString(R.string.action_importSecret)));
}
if (contentType == Id.content.encrypted_data) {
choices.add(new Choice(Id.choice.action.decrypt, getString(R.string.action_decrypt)));
}
if (contentType == Id.content.unknown) {
choices.add(new Choice(Id.choice.action.encrypt, getString(R.string.action_encrypt)));
}
mAdapter = new ArrayAdapter<Choice>(this, android.R.layout.simple_list_item_1, choices);
mList.setAdapter(mAdapter);
mList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
clicked(mAdapter.getItem(arg2).getId());
}
});
mCancelButton = (Button) findViewById(R.id.btn_cancel);
mCancelButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
GeneralActivity.this.finish();
}
});
if (choices.size() == 1) {
clicked(choices.get(0).getId());
}
}
private void clicked(int id) {
Intent intent = new Intent();
switch (id) {
case Id.choice.action.encrypt: {
intent.setClass(this, EncryptActivity.class);
if (mDataString != null) {
intent.setAction(Apg.Intent.ENCRYPT);
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
intent.setAction(Apg.Intent.ENCRYPT_FILE);
intent.setDataAndType(mDataUri, mIntent.getType());
}
break;
}
case Id.choice.action.decrypt: {
intent.setClass(this, DecryptActivity.class);
if (mDataString != null) {
intent.setAction(Apg.Intent.DECRYPT);
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
intent.setAction(Apg.Intent.DECRYPT_FILE);
intent.setDataAndType(mDataUri, mIntent.getType());
}
break;
}
case Id.choice.action.import_public: {
intent.setClass(this, PublicKeyListActivity.class);
intent.setAction(Apg.Intent.IMPORT);
if (mDataString != null) {
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
intent.setDataAndType(mDataUri, mIntent.getType());
}
break;
}
case Id.choice.action.import_secret: {
intent.setClass(this, SecretKeyListActivity.class);
intent.setAction(Apg.Intent.IMPORT);
if (mDataString != null) {
intent.putExtra(Apg.EXTRA_TEXT, mDataString);
} else if (mDataUri != null) {
intent.setDataAndType(mDataUri, mIntent.getType());
}
break;
}
default: {
// shouldn't happen
return;
}
}
startActivity(intent);
finish();
}
}

View File

@ -1,155 +1,155 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import org.bouncycastle2.bcpg.CompressionAlgorithmTags;
public final class Id {
public static final class menu {
public static final int export = 0x21070001;
public static final int delete = 0x21070002;
public static final int edit = 0x21070003;
public static final class option {
public static final int new_pass_phrase = 0x21070001;
public static final int create = 0x21070002;
public static final int about = 0x21070003;
public static final int manage_public_keys = 0x21070004;
public static final int manage_secret_keys = 0x21070005;
public static final int import_keys = 0x21070006;
public static final int export_keys = 0x21070007;
public static final int preferences = 0x21070008;
public static final int search = 0x21070009;
}
}
public static final class message {
public static final int progress_update = 0x21070001;
public static final int done = 0x21070002;
public static final int import_keys = 0x21070003;
public static final int export_keys = 0x21070004;
public static final int import_done = 0x21070005;
public static final int export_done = 0x21070006;
public static final int create_key = 0x21070007;
public static final int edit_key = 0x21070008;
}
public static final class request {
public static final int public_keys = 0x21070001;
public static final int secret_keys = 0x21070002;
public static final int filename = 0x21070003;
public static final int output_filename = 0x21070004;
}
public static final class dialog {
public static final int pass_phrase = 0x21070001;
public static final int encrypting = 0x21070002;
public static final int decrypting = 0x21070003;
public static final int new_pass_phrase = 0x21070004;
public static final int pass_phrases_do_not_match = 0x21070005;
public static final int no_pass_phrase = 0x21070006;
public static final int saving = 0x21070007;
public static final int delete_key = 0x21070008;
public static final int import_keys = 0x21070009;
public static final int importing = 0x2107000a;
public static final int export_key = 0x2107000b;
public static final int export_keys = 0x2107000c;
public static final int exporting = 0x2107000d;
public static final int new_account = 0x2107000e;
public static final int about = 0x2107000f;
public static final int change_log = 0x21070010;
public static final int output_filename = 0x21070011;
public static final int delete_file = 0x21070012;
}
public static final class task {
public static final int import_keys = 0x21070001;
public static final int export_keys = 0x21070002;
}
public static final class database {
public static final int type_public = 0;
public static final int type_secret = 1;
}
public static final class type {
public static final int public_key = 0x21070001;
public static final int secret_key = 0x21070002;
public static final int user_id = 0x21070003;
public static final int key = 0x21070004;
}
public static final class choice {
public static final class algorithm {
public static final int dsa = 0x21070001;
public static final int elgamal = 0x21070002;
public static final int rsa = 0x21070003;
}
public static final class compression {
public static final int none = 0x21070001;
public static final int zlib = CompressionAlgorithmTags.ZLIB;
public static final int bzip2 = CompressionAlgorithmTags.BZIP2;
public static final int zip = CompressionAlgorithmTags.ZIP;
}
public static final class usage {
public static final int sign_only = 0x21070001;
public static final int encrypt_only = 0x21070002;
public static final int sign_and_encrypt = 0x21070003;
}
public static final class action {
public static final int encrypt = 0x21070001;
public static final int decrypt = 0x21070002;
public static final int import_public = 0x21070003;
public static final int import_secret = 0x21070004;
}
}
public static final class return_value {
public static final int ok = 0;
public static final int error = -1;
public static final int no_master_key = -2;
public static final int updated = 1;
}
public static final class target {
public static final int clipboard = 0x21070001;
public static final int email = 0x21070002;
public static final int file = 0x21070003;
public static final int message = 0x21070004;
}
public static final class mode {
public static final int undefined = 0x21070001;
public static final int byte_array = 0x21070002;
public static final int file = 0x21070003;
public static final int stream = 0x21070004;
}
public static final class key {
public static final int none = 0;
public static final int symmetric = -1;
}
public static final class content {
public static final int unknown = 0;
public static final int encrypted_data = 1;
public static final int keys = 2;
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import org.bouncycastle2.bcpg.CompressionAlgorithmTags;
public final class Id {
public static final class menu {
public static final int export = 0x21070001;
public static final int delete = 0x21070002;
public static final int edit = 0x21070003;
public static final class option {
public static final int new_pass_phrase = 0x21070001;
public static final int create = 0x21070002;
public static final int about = 0x21070003;
public static final int manage_public_keys = 0x21070004;
public static final int manage_secret_keys = 0x21070005;
public static final int import_keys = 0x21070006;
public static final int export_keys = 0x21070007;
public static final int preferences = 0x21070008;
public static final int search = 0x21070009;
}
}
public static final class message {
public static final int progress_update = 0x21070001;
public static final int done = 0x21070002;
public static final int import_keys = 0x21070003;
public static final int export_keys = 0x21070004;
public static final int import_done = 0x21070005;
public static final int export_done = 0x21070006;
public static final int create_key = 0x21070007;
public static final int edit_key = 0x21070008;
}
public static final class request {
public static final int public_keys = 0x21070001;
public static final int secret_keys = 0x21070002;
public static final int filename = 0x21070003;
public static final int output_filename = 0x21070004;
}
public static final class dialog {
public static final int pass_phrase = 0x21070001;
public static final int encrypting = 0x21070002;
public static final int decrypting = 0x21070003;
public static final int new_pass_phrase = 0x21070004;
public static final int pass_phrases_do_not_match = 0x21070005;
public static final int no_pass_phrase = 0x21070006;
public static final int saving = 0x21070007;
public static final int delete_key = 0x21070008;
public static final int import_keys = 0x21070009;
public static final int importing = 0x2107000a;
public static final int export_key = 0x2107000b;
public static final int export_keys = 0x2107000c;
public static final int exporting = 0x2107000d;
public static final int new_account = 0x2107000e;
public static final int about = 0x2107000f;
public static final int change_log = 0x21070010;
public static final int output_filename = 0x21070011;
public static final int delete_file = 0x21070012;
}
public static final class task {
public static final int import_keys = 0x21070001;
public static final int export_keys = 0x21070002;
}
public static final class database {
public static final int type_public = 0;
public static final int type_secret = 1;
}
public static final class type {
public static final int public_key = 0x21070001;
public static final int secret_key = 0x21070002;
public static final int user_id = 0x21070003;
public static final int key = 0x21070004;
}
public static final class choice {
public static final class algorithm {
public static final int dsa = 0x21070001;
public static final int elgamal = 0x21070002;
public static final int rsa = 0x21070003;
}
public static final class compression {
public static final int none = 0x21070001;
public static final int zlib = CompressionAlgorithmTags.ZLIB;
public static final int bzip2 = CompressionAlgorithmTags.BZIP2;
public static final int zip = CompressionAlgorithmTags.ZIP;
}
public static final class usage {
public static final int sign_only = 0x21070001;
public static final int encrypt_only = 0x21070002;
public static final int sign_and_encrypt = 0x21070003;
}
public static final class action {
public static final int encrypt = 0x21070001;
public static final int decrypt = 0x21070002;
public static final int import_public = 0x21070003;
public static final int import_secret = 0x21070004;
}
}
public static final class return_value {
public static final int ok = 0;
public static final int error = -1;
public static final int no_master_key = -2;
public static final int updated = 1;
}
public static final class target {
public static final int clipboard = 0x21070001;
public static final int email = 0x21070002;
public static final int file = 0x21070003;
public static final int message = 0x21070004;
}
public static final class mode {
public static final int undefined = 0x21070001;
public static final int byte_array = 0x21070002;
public static final int file = 0x21070003;
public static final int stream = 0x21070004;
}
public static final class key {
public static final int none = 0;
public static final int symmetric = -1;
}
public static final class content {
public static final int unknown = 0;
public static final int encrypted_data = 1;
public static final int keys = 2;
}
}

View File

@ -1,25 +1,25 @@
package org.thialfihar.android.apg;
import java.io.InputStream;
public class InputData {
private PositionAwareInputStream mInputStream;
private long mSize;
InputData(InputStream inputStream, long size) {
mInputStream = new PositionAwareInputStream(inputStream);
mSize = size;
}
public InputStream getInputStream() {
return mInputStream;
}
public long getSize() {
return mSize;
}
public long getStreamPosition() {
return mInputStream.position();
}
}
package org.thialfihar.android.apg;
import java.io.InputStream;
public class InputData {
private PositionAwareInputStream mInputStream;
private long mSize;
InputData(InputStream inputStream, long size) {
mInputStream = new PositionAwareInputStream(inputStream);
mSize = size;
}
public InputStream getInputStream() {
return mInputStream;
}
public long getSize() {
return mSize;
}
public long getStreamPosition() {
return mInputStream.position();
}
}

View File

@ -1,95 +1,95 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.thialfihar.android.apg;
import android.content.Context;
import android.preference.ListPreference;
import android.util.AttributeSet;
/**
* A list preference which persists its values as integers instead of strings.
* Code reading the values should use
* {@link android.content.SharedPreferences#getInt}.
* When using XML-declared arrays for entry values, the arrays should be regular
* string arrays containing valid integer values.
*
* @author Rodrigo Damazio
*/
public class IntegerListPreference extends ListPreference {
public IntegerListPreference(Context context) {
super(context);
verifyEntryValues(null);
}
public IntegerListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
verifyEntryValues(null);
}
@Override
public void setEntryValues(CharSequence[] entryValues) {
CharSequence[] oldValues = getEntryValues();
super.setEntryValues(entryValues);
verifyEntryValues(oldValues);
}
@Override
public void setEntryValues(int entryValuesResId) {
CharSequence[] oldValues = getEntryValues();
super.setEntryValues(entryValuesResId);
verifyEntryValues(oldValues);
}
@Override
protected String getPersistedString(String defaultReturnValue) {
// During initial load, there's no known default value
int defaultIntegerValue = Integer.MIN_VALUE;
if (defaultReturnValue != null) {
defaultIntegerValue = Integer.parseInt(defaultReturnValue);
}
// When the list preference asks us to read a string, instead read an
// integer.
int value = getPersistedInt(defaultIntegerValue);
return Integer.toString(value);
}
@Override
protected boolean persistString(String value) {
// When asked to save a string, instead save an integer
return persistInt(Integer.parseInt(value));
}
private void verifyEntryValues(CharSequence[] oldValues) {
CharSequence[] entryValues = getEntryValues();
if (entryValues == null) {
return;
}
for (CharSequence entryValue : entryValues) {
try {
Integer.parseInt(entryValue.toString());
} catch (NumberFormatException nfe) {
super.setEntryValues(oldValues);
throw nfe;
}
}
}
}
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.thialfihar.android.apg;
import android.content.Context;
import android.preference.ListPreference;
import android.util.AttributeSet;
/**
* A list preference which persists its values as integers instead of strings.
* Code reading the values should use
* {@link android.content.SharedPreferences#getInt}.
* When using XML-declared arrays for entry values, the arrays should be regular
* string arrays containing valid integer values.
*
* @author Rodrigo Damazio
*/
public class IntegerListPreference extends ListPreference {
public IntegerListPreference(Context context) {
super(context);
verifyEntryValues(null);
}
public IntegerListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
verifyEntryValues(null);
}
@Override
public void setEntryValues(CharSequence[] entryValues) {
CharSequence[] oldValues = getEntryValues();
super.setEntryValues(entryValues);
verifyEntryValues(oldValues);
}
@Override
public void setEntryValues(int entryValuesResId) {
CharSequence[] oldValues = getEntryValues();
super.setEntryValues(entryValuesResId);
verifyEntryValues(oldValues);
}
@Override
protected String getPersistedString(String defaultReturnValue) {
// During initial load, there's no known default value
int defaultIntegerValue = Integer.MIN_VALUE;
if (defaultReturnValue != null) {
defaultIntegerValue = Integer.parseInt(defaultReturnValue);
}
// When the list preference asks us to read a string, instead read an
// integer.
int value = getPersistedInt(defaultIntegerValue);
return Integer.toString(value);
}
@Override
protected boolean persistString(String value) {
// When asked to save a string, instead save an integer
return persistInt(Integer.parseInt(value));
}
private void verifyEntryValues(CharSequence[] oldValues) {
CharSequence[] entryValues = getEntryValues();
if (entryValues == null) {
return;
}
for (CharSequence entryValue : entryValues) {
try {
Integer.parseInt(entryValue.toString());
} catch (NumberFormatException nfe) {
super.setEntryValues(oldValues);
throw nfe;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,218 +1,218 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import java.util.Vector;
import java.util.regex.Matcher;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;
public class MailListActivity extends ListActivity {
LayoutInflater mInflater = null;
private static class Conversation {
public long id;
public String subject;
public Vector<Message> messages;
public Conversation(long id, String subject) {
this.id = id;
this.subject = subject;
}
}
private static class Message {
public Conversation parent;
public long id;
public String subject;
public String fromAddress;
public String data;
public String replyTo;
public boolean signedOnly;
public Message(Conversation parent, long id, String subject,
String fromAddress, String replyTo,
String data, boolean signedOnly) {
this.parent = parent;
this.id = id;
this.subject = subject;
this.fromAddress = fromAddress;
this.replyTo = replyTo;
this.data = data;
if (this.replyTo == null || this.replyTo.equals("")) {
this.replyTo = this.fromAddress;
}
this.signedOnly = signedOnly;
}
}
private Vector<Conversation> mconversations;
private Vector<Message> mmessages;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mconversations = new Vector<Conversation>();
mmessages = new Vector<Message>();
String account = getIntent().getExtras().getString(Apg.EXTRA_ACCOUNT);
// TODO: what if account is null?
Uri uri = Uri.parse("content://gmail-ls/conversations/" + account);
Cursor cursor =
managedQuery(uri, new String[] { "conversation_id", "subject" }, null, null, null);
for (int i = 0; i < cursor.getCount(); ++i) {
cursor.moveToPosition(i);
int idIndex = cursor.getColumnIndex("conversation_id");
int subjectIndex = cursor.getColumnIndex("subject");
long conversationId = cursor.getLong(idIndex);
Conversation conversation =
new Conversation(conversationId, cursor.getString(subjectIndex));
Uri messageUri = Uri.withAppendedPath(uri, "" + conversationId + "/messages");
Cursor messageCursor =
managedQuery(messageUri, new String[] {
"messageId",
"subject",
"fromAddress",
"replyToAddresses",
"body" }, null, null, null);
Vector<Message> messages = new Vector<Message>();
for (int j = 0; j < messageCursor.getCount(); ++j) {
messageCursor.moveToPosition(j);
idIndex = messageCursor.getColumnIndex("messageId");
subjectIndex = messageCursor.getColumnIndex("subject");
int fromAddressIndex = messageCursor.getColumnIndex("fromAddress");
int replyToIndex = messageCursor.getColumnIndex("replyToAddresses");
int bodyIndex = messageCursor.getColumnIndex("body");
String data = messageCursor.getString(bodyIndex);
data = Html.fromHtml(data).toString();
boolean signedOnly = false;
Matcher matcher = Apg.PGP_MESSAGE.matcher(data);
if (matcher.matches()) {
data = matcher.group(1);
} else {
matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data);
if (matcher.matches()) {
data = matcher.group(1);
signedOnly = true;
} else {
data = null;
}
}
Message message =
new Message(conversation,
messageCursor.getLong(idIndex),
messageCursor.getString(subjectIndex),
messageCursor.getString(fromAddressIndex),
messageCursor.getString(replyToIndex),
data, signedOnly);
messages.add(message);
mmessages.add(message);
}
conversation.messages = messages;
mconversations.add(conversation);
}
setListAdapter(new MailboxAdapter());
getListView().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
Intent intent = new Intent(MailListActivity.this, DecryptActivity.class);
intent.setAction(Apg.Intent.DECRYPT);
Message message = (Message) ((MailboxAdapter) getListAdapter()).getItem(position);
intent.putExtra(Apg.EXTRA_TEXT, message.data);
intent.putExtra(Apg.EXTRA_SUBJECT, message.subject);
intent.putExtra(Apg.EXTRA_REPLY_TO, message.replyTo);
startActivity(intent);
}
});
}
private class MailboxAdapter extends BaseAdapter implements ListAdapter {
@Override
public boolean isEnabled(int position) {
Message message = (Message) getItem(position);
return message.data != null;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
return mmessages.size();
}
@Override
public Object getItem(int position) {
return mmessages.get(position);
}
@Override
public long getItemId(int position) {
return mmessages.get(position).id;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = mInflater.inflate(R.layout.mailbox_message_item, null);
Message message = (Message) getItem(position);
TextView subject = (TextView) view.findViewById(R.id.subject);
TextView email = (TextView) view.findViewById(R.id.emailAddress);
ImageView status = (ImageView) view.findViewById(R.id.ic_status);
subject.setText(message.subject);
email.setText(message.fromAddress);
if (message.data != null) {
if (message.signedOnly) {
status.setImageResource(R.drawable.signed);
} else {
status.setImageResource(R.drawable.encrypted);
}
status.setVisibility(View.VISIBLE);
} else {
status.setVisibility(View.INVISIBLE);
}
return view;
}
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import java.util.Vector;
import java.util.regex.Matcher;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;
public class MailListActivity extends ListActivity {
LayoutInflater mInflater = null;
private static class Conversation {
public long id;
public String subject;
public Vector<Message> messages;
public Conversation(long id, String subject) {
this.id = id;
this.subject = subject;
}
}
private static class Message {
public Conversation parent;
public long id;
public String subject;
public String fromAddress;
public String data;
public String replyTo;
public boolean signedOnly;
public Message(Conversation parent, long id, String subject,
String fromAddress, String replyTo,
String data, boolean signedOnly) {
this.parent = parent;
this.id = id;
this.subject = subject;
this.fromAddress = fromAddress;
this.replyTo = replyTo;
this.data = data;
if (this.replyTo == null || this.replyTo.equals("")) {
this.replyTo = this.fromAddress;
}
this.signedOnly = signedOnly;
}
}
private Vector<Conversation> mconversations;
private Vector<Message> mmessages;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mconversations = new Vector<Conversation>();
mmessages = new Vector<Message>();
String account = getIntent().getExtras().getString(Apg.EXTRA_ACCOUNT);
// TODO: what if account is null?
Uri uri = Uri.parse("content://gmail-ls/conversations/" + account);
Cursor cursor =
managedQuery(uri, new String[] { "conversation_id", "subject" }, null, null, null);
for (int i = 0; i < cursor.getCount(); ++i) {
cursor.moveToPosition(i);
int idIndex = cursor.getColumnIndex("conversation_id");
int subjectIndex = cursor.getColumnIndex("subject");
long conversationId = cursor.getLong(idIndex);
Conversation conversation =
new Conversation(conversationId, cursor.getString(subjectIndex));
Uri messageUri = Uri.withAppendedPath(uri, "" + conversationId + "/messages");
Cursor messageCursor =
managedQuery(messageUri, new String[] {
"messageId",
"subject",
"fromAddress",
"replyToAddresses",
"body" }, null, null, null);
Vector<Message> messages = new Vector<Message>();
for (int j = 0; j < messageCursor.getCount(); ++j) {
messageCursor.moveToPosition(j);
idIndex = messageCursor.getColumnIndex("messageId");
subjectIndex = messageCursor.getColumnIndex("subject");
int fromAddressIndex = messageCursor.getColumnIndex("fromAddress");
int replyToIndex = messageCursor.getColumnIndex("replyToAddresses");
int bodyIndex = messageCursor.getColumnIndex("body");
String data = messageCursor.getString(bodyIndex);
data = Html.fromHtml(data).toString();
boolean signedOnly = false;
Matcher matcher = Apg.PGP_MESSAGE.matcher(data);
if (matcher.matches()) {
data = matcher.group(1);
} else {
matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data);
if (matcher.matches()) {
data = matcher.group(1);
signedOnly = true;
} else {
data = null;
}
}
Message message =
new Message(conversation,
messageCursor.getLong(idIndex),
messageCursor.getString(subjectIndex),
messageCursor.getString(fromAddressIndex),
messageCursor.getString(replyToIndex),
data, signedOnly);
messages.add(message);
mmessages.add(message);
}
conversation.messages = messages;
mconversations.add(conversation);
}
setListAdapter(new MailboxAdapter());
getListView().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
Intent intent = new Intent(MailListActivity.this, DecryptActivity.class);
intent.setAction(Apg.Intent.DECRYPT);
Message message = (Message) ((MailboxAdapter) getListAdapter()).getItem(position);
intent.putExtra(Apg.EXTRA_TEXT, message.data);
intent.putExtra(Apg.EXTRA_SUBJECT, message.subject);
intent.putExtra(Apg.EXTRA_REPLY_TO, message.replyTo);
startActivity(intent);
}
});
}
private class MailboxAdapter extends BaseAdapter implements ListAdapter {
@Override
public boolean isEnabled(int position) {
Message message = (Message) getItem(position);
return message.data != null;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
return mmessages.size();
}
@Override
public Object getItem(int position) {
return mmessages.get(position);
}
@Override
public long getItemId(int position) {
return mmessages.get(position).id;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = mInflater.inflate(R.layout.mailbox_message_item, null);
Message message = (Message) getItem(position);
TextView subject = (TextView) view.findViewById(R.id.subject);
TextView email = (TextView) view.findViewById(R.id.emailAddress);
ImageView status = (ImageView) view.findViewById(R.id.ic_status);
subject.setText(message.subject);
email.setText(message.fromAddress);
if (message.data != null) {
if (message.signedOnly) {
status.setImageResource(R.drawable.signed);
} else {
status.setImageResource(R.drawable.encrypted);
}
status.setVisibility(View.VISIBLE);
} else {
status.setVisibility(View.INVISIBLE);
}
return view;
}
}
}

View File

@ -1,67 +1,67 @@
package org.thialfihar.android.apg;
import java.io.IOException;
import java.io.InputStream;
public class PositionAwareInputStream extends InputStream {
private InputStream mStream;
private long mPosition;
public PositionAwareInputStream(InputStream in) {
mStream = in;
mPosition = 0;
}
@Override
public int read() throws IOException {
int ch = mStream.read();
++mPosition;
return ch;
}
@Override
public int available() throws IOException {
return mStream.available();
}
@Override
public void close() throws IOException {
mStream.close();
}
@Override
public boolean markSupported() {
return false;
}
@Override
public int read(byte[] b) throws IOException {
int result = mStream.read(b);
mPosition += result;
return result;
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
int result = mStream.read(b, offset, length);
mPosition += result;
return result;
}
@Override
public synchronized void reset() throws IOException {
mStream.reset();
mPosition = 0;
}
@Override
public long skip(long n) throws IOException {
long result = mStream.skip(n);
mPosition += result;
return result;
}
public long position() {
return mPosition;
}
}
package org.thialfihar.android.apg;
import java.io.IOException;
import java.io.InputStream;
public class PositionAwareInputStream extends InputStream {
private InputStream mStream;
private long mPosition;
public PositionAwareInputStream(InputStream in) {
mStream = in;
mPosition = 0;
}
@Override
public int read() throws IOException {
int ch = mStream.read();
++mPosition;
return ch;
}
@Override
public int available() throws IOException {
return mStream.available();
}
@Override
public void close() throws IOException {
mStream.close();
}
@Override
public boolean markSupported() {
return false;
}
@Override
public int read(byte[] b) throws IOException {
int result = mStream.read(b);
mPosition += result;
return result;
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
int result = mStream.read(b, offset, length);
mPosition += result;
return result;
}
@Override
public synchronized void reset() throws IOException {
mStream.reset();
mPosition = 0;
}
@Override
public long skip(long n) throws IOException {
long result = mStream.skip(n);
mPosition += result;
return result;
}
public long position() {
return mPosition;
}
}

View File

@ -1,180 +1,180 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import org.bouncycastle2.bcpg.HashAlgorithmTags;
import org.bouncycastle2.openpgp.PGPEncryptedData;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
public class PreferencesActivity extends PreferenceActivity {
private IntegerListPreference mPassPhraseCacheTtl = null;
private IntegerListPreference mEncryptionAlgorithm = null;
private IntegerListPreference mHashAlgorithm = null;
private IntegerListPreference mMessageCompression = null;
private IntegerListPreference mFileCompression = null;
private CheckBoxPreference mAsciiArmour = null;
private Preferences mPreferences;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPreferences = Preferences.getPreferences(this);
addPreferencesFromResource(R.xml.apg_preferences);
mPassPhraseCacheTtl = (IntegerListPreference) findPreference(Constants.pref.pass_phrase_cache_ttl);
mPassPhraseCacheTtl.setValue("" + mPreferences.getPassPhraseCacheTtl());
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
mPassPhraseCacheTtl.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mPassPhraseCacheTtl.setValue(newValue.toString());
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString()));
BaseActivity.startCacheService(PreferencesActivity.this, mPreferences);
return false;
}
});
mEncryptionAlgorithm = (IntegerListPreference) findPreference(Constants.pref.default_encryption_algorithm);
int valueIds[] = {
PGPEncryptedData.AES_128, PGPEncryptedData.AES_192, PGPEncryptedData.AES_256,
PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH, PGPEncryptedData.CAST5,
PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES, PGPEncryptedData.IDEA,
};
String entries[] = {
"AES-128", "AES-192", "AES-256",
"Blowfish", "Twofish", "CAST5",
"DES", "Triple DES", "IDEA",
};
String values[] = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
values[i] = "" + valueIds[i];
}
mEncryptionAlgorithm.setEntries(entries);
mEncryptionAlgorithm.setEntryValues(values);
mEncryptionAlgorithm.setValue("" + mPreferences.getDefaultEncryptionAlgorithm());
mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
mEncryptionAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mEncryptionAlgorithm.setValue(newValue.toString());
mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
mPreferences.setDefaultEncryptionAlgorithm(Integer.parseInt(newValue.toString()));
return false;
}
});
mHashAlgorithm = (IntegerListPreference) findPreference(Constants.pref.default_hash_algorithm);
valueIds = new int[] {
HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160, HashAlgorithmTags.SHA1,
HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256, HashAlgorithmTags.SHA384,
HashAlgorithmTags.SHA512,
};
entries = new String[] {
"MD5", "RIPEMD-160", "SHA-1",
"SHA-224", "SHA-256", "SHA-384",
"SHA-512",
};
values = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
values[i] = "" + valueIds[i];
}
mHashAlgorithm.setEntries(entries);
mHashAlgorithm.setEntryValues(values);
mHashAlgorithm.setValue("" + mPreferences.getDefaultHashAlgorithm());
mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
mHashAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mHashAlgorithm.setValue(newValue.toString());
mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
mPreferences.setDefaultHashAlgorithm(Integer.parseInt(newValue.toString()));
return false;
}
});
mMessageCompression = (IntegerListPreference) findPreference(Constants.pref.default_message_compression);
valueIds = new int[] {
Id.choice.compression.none,
Id.choice.compression.zip,
Id.choice.compression.zlib,
Id.choice.compression.bzip2,
};
entries = new String[] {
getString(R.string.choice_none) + " (" + getString(R.string.fast) + ")",
"ZIP (" + getString(R.string.fast) + ")",
"ZLIB (" + getString(R.string.fast) + ")",
"BZIP2 (" + getString(R.string.very_slow) + ")",
};
values = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
values[i] = "" + valueIds[i];
}
mMessageCompression.setEntries(entries);
mMessageCompression.setEntryValues(values);
mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression());
mMessageCompression.setSummary(mMessageCompression.getEntry());
mMessageCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mMessageCompression.setValue(newValue.toString());
mMessageCompression.setSummary(mMessageCompression.getEntry());
mPreferences.setDefaultMessageCompression(Integer.parseInt(newValue.toString()));
return false;
}
});
mFileCompression = (IntegerListPreference) findPreference(Constants.pref.default_file_compression);
mFileCompression.setEntries(entries);
mFileCompression.setEntryValues(values);
mFileCompression.setValue("" + mPreferences.getDefaultFileCompression());
mFileCompression.setSummary(mFileCompression.getEntry());
mFileCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mFileCompression.setValue(newValue.toString());
mFileCompression.setSummary(mFileCompression.getEntry());
mPreferences.setDefaultFileCompression(Integer.parseInt(newValue.toString()));
return false;
}
});
mAsciiArmour = (CheckBoxPreference) findPreference(Constants.pref.default_ascii_armour);
mAsciiArmour.setChecked(mPreferences.getDefaultAsciiArmour());
mAsciiArmour.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mAsciiArmour.setChecked((Boolean)newValue);
mPreferences.setDefaultAsciiArmour((Boolean)newValue);
return false;
}
});
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import org.bouncycastle2.bcpg.HashAlgorithmTags;
import org.bouncycastle2.openpgp.PGPEncryptedData;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
public class PreferencesActivity extends PreferenceActivity {
private IntegerListPreference mPassPhraseCacheTtl = null;
private IntegerListPreference mEncryptionAlgorithm = null;
private IntegerListPreference mHashAlgorithm = null;
private IntegerListPreference mMessageCompression = null;
private IntegerListPreference mFileCompression = null;
private CheckBoxPreference mAsciiArmour = null;
private Preferences mPreferences;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPreferences = Preferences.getPreferences(this);
addPreferencesFromResource(R.xml.apg_preferences);
mPassPhraseCacheTtl = (IntegerListPreference) findPreference(Constants.pref.pass_phrase_cache_ttl);
mPassPhraseCacheTtl.setValue("" + mPreferences.getPassPhraseCacheTtl());
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
mPassPhraseCacheTtl.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mPassPhraseCacheTtl.setValue(newValue.toString());
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString()));
BaseActivity.startCacheService(PreferencesActivity.this, mPreferences);
return false;
}
});
mEncryptionAlgorithm = (IntegerListPreference) findPreference(Constants.pref.default_encryption_algorithm);
int valueIds[] = {
PGPEncryptedData.AES_128, PGPEncryptedData.AES_192, PGPEncryptedData.AES_256,
PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH, PGPEncryptedData.CAST5,
PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES, PGPEncryptedData.IDEA,
};
String entries[] = {
"AES-128", "AES-192", "AES-256",
"Blowfish", "Twofish", "CAST5",
"DES", "Triple DES", "IDEA",
};
String values[] = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
values[i] = "" + valueIds[i];
}
mEncryptionAlgorithm.setEntries(entries);
mEncryptionAlgorithm.setEntryValues(values);
mEncryptionAlgorithm.setValue("" + mPreferences.getDefaultEncryptionAlgorithm());
mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
mEncryptionAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mEncryptionAlgorithm.setValue(newValue.toString());
mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry());
mPreferences.setDefaultEncryptionAlgorithm(Integer.parseInt(newValue.toString()));
return false;
}
});
mHashAlgorithm = (IntegerListPreference) findPreference(Constants.pref.default_hash_algorithm);
valueIds = new int[] {
HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160, HashAlgorithmTags.SHA1,
HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256, HashAlgorithmTags.SHA384,
HashAlgorithmTags.SHA512,
};
entries = new String[] {
"MD5", "RIPEMD-160", "SHA-1",
"SHA-224", "SHA-256", "SHA-384",
"SHA-512",
};
values = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
values[i] = "" + valueIds[i];
}
mHashAlgorithm.setEntries(entries);
mHashAlgorithm.setEntryValues(values);
mHashAlgorithm.setValue("" + mPreferences.getDefaultHashAlgorithm());
mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
mHashAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mHashAlgorithm.setValue(newValue.toString());
mHashAlgorithm.setSummary(mHashAlgorithm.getEntry());
mPreferences.setDefaultHashAlgorithm(Integer.parseInt(newValue.toString()));
return false;
}
});
mMessageCompression = (IntegerListPreference) findPreference(Constants.pref.default_message_compression);
valueIds = new int[] {
Id.choice.compression.none,
Id.choice.compression.zip,
Id.choice.compression.zlib,
Id.choice.compression.bzip2,
};
entries = new String[] {
getString(R.string.choice_none) + " (" + getString(R.string.fast) + ")",
"ZIP (" + getString(R.string.fast) + ")",
"ZLIB (" + getString(R.string.fast) + ")",
"BZIP2 (" + getString(R.string.very_slow) + ")",
};
values = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
values[i] = "" + valueIds[i];
}
mMessageCompression.setEntries(entries);
mMessageCompression.setEntryValues(values);
mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression());
mMessageCompression.setSummary(mMessageCompression.getEntry());
mMessageCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mMessageCompression.setValue(newValue.toString());
mMessageCompression.setSummary(mMessageCompression.getEntry());
mPreferences.setDefaultMessageCompression(Integer.parseInt(newValue.toString()));
return false;
}
});
mFileCompression = (IntegerListPreference) findPreference(Constants.pref.default_file_compression);
mFileCompression.setEntries(entries);
mFileCompression.setEntryValues(values);
mFileCompression.setValue("" + mPreferences.getDefaultFileCompression());
mFileCompression.setSummary(mFileCompression.getEntry());
mFileCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mFileCompression.setValue(newValue.toString());
mFileCompression.setSummary(mFileCompression.getEntry());
mPreferences.setDefaultFileCompression(Integer.parseInt(newValue.toString()));
return false;
}
});
mAsciiArmour = (CheckBoxPreference) findPreference(Constants.pref.default_ascii_armour);
mAsciiArmour.setChecked(mPreferences.getDefaultAsciiArmour());
mAsciiArmour.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
mAsciiArmour.setChecked((Boolean)newValue);
mPreferences.setDefaultAsciiArmour((Boolean)newValue);
return false;
}
});
}
}

View File

@ -1,185 +1,185 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import java.math.BigInteger;
public final class Primes {
// taken from http://www.ietf.org/rfc/rfc3526.txt
public static final String P1536 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF";
public static final String P2048 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
"15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
public static final String P3072 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
"43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF";
public static final String P4096 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" +
"FFFFFFFF FFFFFFFF";
public static final String P6144 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
"36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
"F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
"179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
"DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
"5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
"D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
"23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
"CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
"06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
"DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
"12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF";
public static final String P8192 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
"36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
"F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
"179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
"DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
"5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
"D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
"23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
"CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
"06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
"DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
"12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" +
"38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" +
"741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" +
"3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" +
"22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" +
"4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" +
"062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" +
"4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" +
"B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" +
"4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" +
"9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" +
"60C980DD 98EDD3DF FFFFFFFF FFFFFFFF";
public static BigInteger getBestPrime(int keySize) {
String primeString;
if (keySize >= (8192 + 6144) / 2) {
primeString = P8192;
} else if (keySize >= (6144 + 4096) / 2) {
primeString = P6144;
} else if (keySize >= (4096 + 3072) / 2) {
primeString = P4096;
} else if (keySize >= (3072 + 2048) / 2) {
primeString = P3072;
} else if (keySize >= (2048 + 1536) / 2) {
primeString = P2048;
} else {
primeString = P1536;
}
return new BigInteger(primeString.replaceAll(" ", ""), 16);
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import java.math.BigInteger;
public final class Primes {
// taken from http://www.ietf.org/rfc/rfc3526.txt
public static final String P1536 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF";
public static final String P2048 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
"15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
public static final String P3072 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
"43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF";
public static final String P4096 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" +
"FFFFFFFF FFFFFFFF";
public static final String P6144 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
"36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
"F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
"179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
"DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
"5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
"D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
"23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
"CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
"06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
"DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
"12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF";
public static final String P8192 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
"36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
"F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
"179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
"DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
"5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
"D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
"23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
"CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
"06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
"DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
"12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" +
"38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" +
"741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" +
"3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" +
"22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" +
"4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" +
"062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" +
"4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" +
"B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" +
"4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" +
"9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" +
"60C980DD 98EDD3DF FFFFFFFF FFFFFFFF";
public static BigInteger getBestPrime(int keySize) {
String primeString;
if (keySize >= (8192 + 6144) / 2) {
primeString = P8192;
} else if (keySize >= (6144 + 4096) / 2) {
primeString = P6144;
} else if (keySize >= (4096 + 3072) / 2) {
primeString = P4096;
} else if (keySize >= (3072 + 2048) / 2) {
primeString = P3072;
} else if (keySize >= (2048 + 1536) / 2) {
primeString = P2048;
} else {
primeString = P1536;
}
return new BigInteger(primeString.replaceAll(" ", ""), 16);
}
}

View File

@ -1,23 +1,23 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
public interface ProgressDialogUpdater {
void setProgress(String message, int current, int total);
void setProgress(int resourceId, int current, int total);
void setProgress(int current, int total);
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
public interface ProgressDialogUpdater {
void setProgress(String message, int current, int total);
void setProgress(int resourceId, int current, int total);
void setProgress(int current, int total);
}

View File

@ -1,62 +1,62 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.View;
import android.widget.ExpandableListView;
public class PublicKeyListActivity extends KeyListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
mExportFilename = Constants.path.app_dir + "/pubexport.asc";
mKeyType = Id.type.public_key;
super.onCreate(savedInstanceState);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, Id.menu.option.import_keys, 0, R.string.menu_importKeys)
.setIcon(android.R.drawable.ic_menu_add);
menu.add(0, Id.menu.option.export_keys, 1, R.string.menu_exportKeys)
.setIcon(android.R.drawable.ic_menu_save);
menu.add(1, Id.menu.option.search, 2, R.string.menu_search)
.setIcon(android.R.drawable.ic_menu_search);
menu.add(1, Id.menu.option.preferences, 3, R.string.menu_preferences)
.setIcon(android.R.drawable.ic_menu_preferences);
menu.add(1, Id.menu.option.about, 4, R.string.menu_about)
.setIcon(android.R.drawable.ic_menu_info_details);
return true;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
ExpandableListView.ExpandableListContextMenuInfo info =
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
// TODO: user id? menu.setHeaderTitle("Key");
menu.add(0, Id.menu.export, 0, R.string.menu_exportKey);
menu.add(0, Id.menu.delete, 1, R.string.menu_deleteKey);
}
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.View;
import android.widget.ExpandableListView;
public class PublicKeyListActivity extends KeyListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
mExportFilename = Constants.path.app_dir + "/pubexport.asc";
mKeyType = Id.type.public_key;
super.onCreate(savedInstanceState);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, Id.menu.option.import_keys, 0, R.string.menu_importKeys)
.setIcon(android.R.drawable.ic_menu_add);
menu.add(0, Id.menu.option.export_keys, 1, R.string.menu_exportKeys)
.setIcon(android.R.drawable.ic_menu_save);
menu.add(1, Id.menu.option.search, 2, R.string.menu_search)
.setIcon(android.R.drawable.ic_menu_search);
menu.add(1, Id.menu.option.preferences, 3, R.string.menu_preferences)
.setIcon(android.R.drawable.ic_menu_preferences);
menu.add(1, Id.menu.option.about, 4, R.string.menu_about)
.setIcon(android.R.drawable.ic_menu_info_details);
return true;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
ExpandableListView.ExpandableListContextMenuInfo info =
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
// TODO: user id? menu.setHeaderTitle("Key");
menu.add(0, Id.menu.export, 0, R.string.menu_exportKey);
menu.add(0, Id.menu.delete, 1, R.string.menu_deleteKey);
}
}
}

View File

@ -1,180 +1,180 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.ExpandableListView.OnChildClickListener;
public class SecretKeyListActivity extends KeyListActivity implements OnChildClickListener {
@Override
public void onCreate(Bundle savedInstanceState) {
mExportFilename = Constants.path.app_dir + "/secexport.asc";
mKeyType = Id.type.secret_key;
super.onCreate(savedInstanceState);
mList.setOnChildClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, Id.menu.option.import_keys, 0, R.string.menu_importKeys)
.setIcon(android.R.drawable.ic_menu_add);
menu.add(0, Id.menu.option.export_keys, 1, R.string.menu_exportKeys)
.setIcon(android.R.drawable.ic_menu_save);
menu.add(1, Id.menu.option.create, 2, R.string.menu_createKey)
.setIcon(android.R.drawable.ic_menu_add);
menu.add(3, Id.menu.option.search, 3, R.string.menu_search)
.setIcon(android.R.drawable.ic_menu_search);
menu.add(3, Id.menu.option.preferences, 4, R.string.menu_preferences)
.setIcon(android.R.drawable.ic_menu_preferences);
menu.add(3, Id.menu.option.about, 5, R.string.menu_about)
.setIcon(android.R.drawable.ic_menu_info_details);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case Id.menu.option.create: {
createKey();
return true;
}
default: {
return super.onOptionsItemSelected(item);
}
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
ExpandableListView.ExpandableListContextMenuInfo info =
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
// TODO: user id? menu.setHeaderTitle("Key");
menu.add(0, Id.menu.edit, 0, R.string.menu_editKey);
menu.add(0, Id.menu.export, 1, R.string.menu_exportKey);
menu.add(0, Id.menu.delete, 2, R.string.menu_deleteKey);
}
}
@Override
public boolean onContextItemSelected(MenuItem menuItem) {
ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuItem.getMenuInfo();
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
if (type != ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
return super.onContextItemSelected(menuItem);
}
switch (menuItem.getItemId()) {
case Id.menu.edit: {
mSelectedItem = groupPosition;
checkPassPhraseAndEdit();
return true;
}
default: {
return super.onContextItemSelected(menuItem);
}
}
}
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) {
mSelectedItem = groupPosition;
checkPassPhraseAndEdit();
return true;
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case Id.dialog.pass_phrase: {
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
return AskForSecretKeyPassPhrase.createDialog(this, keyId, this);
}
default: {
return super.onCreateDialog(id);
}
}
}
public void checkPassPhraseAndEdit() {
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
String passPhrase = Apg.getCachedPassPhrase(keyId);
if (passPhrase == null) {
showDialog(Id.dialog.pass_phrase);
} else {
Apg.setEditPassPhrase(passPhrase);
editKey();
}
}
@Override
public void passPhraseCallback(long keyId, String passPhrase) {
super.passPhraseCallback(keyId, passPhrase);
Apg.setEditPassPhrase(passPhrase);
editKey();
}
private void createKey() {
Apg.setEditPassPhrase("");
Intent intent = new Intent(this, EditKeyActivity.class);
startActivityForResult(intent, Id.message.create_key);
}
private void editKey() {
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
Intent intent = new Intent(this, EditKeyActivity.class);
intent.putExtra(Apg.EXTRA_KEY_ID, keyId);
startActivityForResult(intent, Id.message.edit_key);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Id.message.create_key: // intentionally no break
case Id.message.edit_key: {
if (resultCode == RESULT_OK) {
refreshList();
}
break;
}
default: {
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.ExpandableListView.OnChildClickListener;
public class SecretKeyListActivity extends KeyListActivity implements OnChildClickListener {
@Override
public void onCreate(Bundle savedInstanceState) {
mExportFilename = Constants.path.app_dir + "/secexport.asc";
mKeyType = Id.type.secret_key;
super.onCreate(savedInstanceState);
mList.setOnChildClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, Id.menu.option.import_keys, 0, R.string.menu_importKeys)
.setIcon(android.R.drawable.ic_menu_add);
menu.add(0, Id.menu.option.export_keys, 1, R.string.menu_exportKeys)
.setIcon(android.R.drawable.ic_menu_save);
menu.add(1, Id.menu.option.create, 2, R.string.menu_createKey)
.setIcon(android.R.drawable.ic_menu_add);
menu.add(3, Id.menu.option.search, 3, R.string.menu_search)
.setIcon(android.R.drawable.ic_menu_search);
menu.add(3, Id.menu.option.preferences, 4, R.string.menu_preferences)
.setIcon(android.R.drawable.ic_menu_preferences);
menu.add(3, Id.menu.option.about, 5, R.string.menu_about)
.setIcon(android.R.drawable.ic_menu_info_details);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case Id.menu.option.create: {
createKey();
return true;
}
default: {
return super.onOptionsItemSelected(item);
}
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
ExpandableListView.ExpandableListContextMenuInfo info =
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
// TODO: user id? menu.setHeaderTitle("Key");
menu.add(0, Id.menu.edit, 0, R.string.menu_editKey);
menu.add(0, Id.menu.export, 1, R.string.menu_exportKey);
menu.add(0, Id.menu.delete, 2, R.string.menu_deleteKey);
}
}
@Override
public boolean onContextItemSelected(MenuItem menuItem) {
ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuItem.getMenuInfo();
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
if (type != ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
return super.onContextItemSelected(menuItem);
}
switch (menuItem.getItemId()) {
case Id.menu.edit: {
mSelectedItem = groupPosition;
checkPassPhraseAndEdit();
return true;
}
default: {
return super.onContextItemSelected(menuItem);
}
}
}
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) {
mSelectedItem = groupPosition;
checkPassPhraseAndEdit();
return true;
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case Id.dialog.pass_phrase: {
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
return AskForSecretKeyPassPhrase.createDialog(this, keyId, this);
}
default: {
return super.onCreateDialog(id);
}
}
}
public void checkPassPhraseAndEdit() {
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
String passPhrase = Apg.getCachedPassPhrase(keyId);
if (passPhrase == null) {
showDialog(Id.dialog.pass_phrase);
} else {
Apg.setEditPassPhrase(passPhrase);
editKey();
}
}
@Override
public void passPhraseCallback(long keyId, String passPhrase) {
super.passPhraseCallback(keyId, passPhrase);
Apg.setEditPassPhrase(passPhrase);
editKey();
}
private void createKey() {
Apg.setEditPassPhrase("");
Intent intent = new Intent(this, EditKeyActivity.class);
startActivityForResult(intent, Id.message.create_key);
}
private void editKey() {
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
Intent intent = new Intent(this, EditKeyActivity.class);
intent.putExtra(Apg.EXTRA_KEY_ID, keyId);
startActivityForResult(intent, Id.message.edit_key);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Id.message.create_key: // intentionally no break
case Id.message.edit_key: {
if (resultCode == RESULT_OK) {
refreshList();
}
break;
}
default: {
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
}

View File

@ -1,225 +1,225 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import java.util.Date;
import org.thialfihar.android.apg.provider.KeyRings;
import org.thialfihar.android.apg.provider.Keys;
import org.thialfihar.android.apg.provider.UserIds;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
public class SelectPublicKeyListAdapter extends BaseAdapter {
protected LayoutInflater mInflater;
protected ListView mParent;
protected SQLiteDatabase mDatabase;
protected Cursor mCursor;
protected String mSearchString;
protected Activity mActivity;
public SelectPublicKeyListAdapter(Activity activity, ListView parent,
String searchString, long selectedKeyIds[]) {
mSearchString = searchString;
mActivity = activity;
mParent = parent;
mDatabase = Apg.getDatabase().db();
mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
long now = new Date().getTime() / 1000;
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " +
"(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " +
Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " +
Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" +
") " +
" INNER JOIN " + UserIds.TABLE_NAME + " ON " +
"(" + Keys.TABLE_NAME + "." + Keys._ID + " = " +
UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " +
UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
String inIdList = null;
if (selectedKeyIds != null && selectedKeyIds.length > 0) {
inIdList = KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID + " IN (";
for (int i = 0; i < selectedKeyIds.length; ++i) {
if (i != 0) {
inIdList += ", ";
}
inIdList += DatabaseUtils.sqlEscapeString("" + selectedKeyIds[i]);
}
inIdList += ")";
}
if (searchString != null && searchString.trim().length() > 0) {
String[] chunks = searchString.trim().split(" +");
qb.appendWhere("(EXISTS (SELECT tmp." + UserIds._ID + " FROM " +
UserIds.TABLE_NAME + " AS tmp WHERE " +
"tmp." + UserIds.KEY_ID + " = " +
Keys.TABLE_NAME + "." + Keys._ID);
for (int i = 0; i < chunks.length; ++i) {
qb.appendWhere(" AND tmp." + UserIds.USER_ID + " LIKE ");
qb.appendWhereEscapeString("%" + chunks[i] + "%");
}
qb.appendWhere("))");
if (inIdList != null) {
qb.appendWhere(" OR (" + inIdList + ")");
}
}
String orderBy = UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC";
if (inIdList != null) {
orderBy = inIdList + " DESC, " + orderBy;
}
mCursor = qb.query(mDatabase,
new String[] {
KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
"tmp." + Keys.KEY_RING_ID + " = " +
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
"tmp." + Keys.CAN_ENCRYPT + " = '1')", // 3
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
"tmp." + Keys.KEY_RING_ID + " = " +
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
"tmp." + Keys.CAN_ENCRYPT + " = '1' AND " +
"tmp." + Keys.CREATION + " <= '" + now + "' AND " +
"(tmp." + Keys.EXPIRY + " IS NULL OR " +
"tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4
},
KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?",
new String[] { "" + Id.database.type_public },
null, null, orderBy);
activity.startManagingCursor(mCursor);
}
public void cleanup() {
if (mCursor != null) {
mActivity.stopManagingCursor(mCursor);
mCursor.close();
}
}
@Override
public boolean isEnabled(int position) {
mCursor.moveToPosition(position);
return mCursor.getInt(4) > 0; // valid CAN_ENCRYPT
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
return mCursor.getCount();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
mCursor.moveToPosition(position);
return mCursor.getLong(1); // MASTER_KEY_ID
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
mCursor.moveToPosition(position);
View view = mInflater.inflate(R.layout.select_public_key_item, null);
boolean enabled = isEnabled(position);
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
mainUserId.setText(R.string.unknownUserId);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
mainUserIdRest.setText("");
TextView keyId = (TextView) view.findViewById(R.id.keyId);
keyId.setText(R.string.noKey);
TextView status = (TextView) view.findViewById(R.id.status);
status.setText(R.string.unknownStatus);
String userId = mCursor.getString(2); // USER_ID
if (userId != null) {
String chunks[] = userId.split(" <", 2);
userId = chunks[0];
if (chunks.length > 1) {
mainUserIdRest.setText("<" + chunks[1]);
}
mainUserId.setText(userId);
}
long masterKeyId = mCursor.getLong(1); // MASTER_KEY_ID
keyId.setText("" + Long.toHexString(masterKeyId & 0xffffffffL));
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);
}
if (enabled) {
status.setText(R.string.canEncrypt);
} else {
if (mCursor.getInt(3) > 0) {
// has some CAN_ENCRYPT keys, but col(4) = 0, so must be revoked or expired
status.setText(R.string.expired);
} else {
status.setText(R.string.noKey);
}
}
status.setText(status.getText() + " ");
CheckBox selected = (CheckBox) view.findViewById(R.id.selected);
if (!enabled) {
mParent.setItemChecked(position, false);
}
selected.setChecked(mParent.isItemChecked(position));
view.setEnabled(enabled);
mainUserId.setEnabled(enabled);
mainUserIdRest.setEnabled(enabled);
keyId.setEnabled(enabled);
selected.setEnabled(enabled);
status.setEnabled(enabled);
return view;
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg;
import java.util.Date;
import org.thialfihar.android.apg.provider.KeyRings;
import org.thialfihar.android.apg.provider.Keys;
import org.thialfihar.android.apg.provider.UserIds;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
public class SelectPublicKeyListAdapter extends BaseAdapter {
protected LayoutInflater mInflater;
protected ListView mParent;
protected SQLiteDatabase mDatabase;
protected Cursor mCursor;
protected String mSearchString;
protected Activity mActivity;
public SelectPublicKeyListAdapter(Activity activity, ListView parent,
String searchString, long selectedKeyIds[]) {
mSearchString = searchString;
mActivity = activity;
mParent = parent;
mDatabase = Apg.getDatabase().db();
mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
long now = new Date().getTime() / 1000;
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " +
"(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " +
Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " +
Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" +
") " +
" INNER JOIN " + UserIds.TABLE_NAME + " ON " +
"(" + Keys.TABLE_NAME + "." + Keys._ID + " = " +
UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " +
UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
String inIdList = null;
if (selectedKeyIds != null && selectedKeyIds.length > 0) {
inIdList = KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID + " IN (";
for (int i = 0; i < selectedKeyIds.length; ++i) {
if (i != 0) {
inIdList += ", ";
}
inIdList += DatabaseUtils.sqlEscapeString("" + selectedKeyIds[i]);
}
inIdList += ")";
}
if (searchString != null && searchString.trim().length() > 0) {
String[] chunks = searchString.trim().split(" +");
qb.appendWhere("(EXISTS (SELECT tmp." + UserIds._ID + " FROM " +
UserIds.TABLE_NAME + " AS tmp WHERE " +
"tmp." + UserIds.KEY_ID + " = " +
Keys.TABLE_NAME + "." + Keys._ID);
for (int i = 0; i < chunks.length; ++i) {
qb.appendWhere(" AND tmp." + UserIds.USER_ID + " LIKE ");
qb.appendWhereEscapeString("%" + chunks[i] + "%");
}
qb.appendWhere("))");
if (inIdList != null) {
qb.appendWhere(" OR (" + inIdList + ")");
}
}
String orderBy = UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC";
if (inIdList != null) {
orderBy = inIdList + " DESC, " + orderBy;
}
mCursor = qb.query(mDatabase,
new String[] {
KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
"tmp." + Keys.KEY_RING_ID + " = " +
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
"tmp." + Keys.CAN_ENCRYPT + " = '1')", // 3
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
"tmp." + Keys.KEY_RING_ID + " = " +
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
"tmp." + Keys.CAN_ENCRYPT + " = '1' AND " +
"tmp." + Keys.CREATION + " <= '" + now + "' AND " +
"(tmp." + Keys.EXPIRY + " IS NULL OR " +
"tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4
},
KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?",
new String[] { "" + Id.database.type_public },
null, null, orderBy);
activity.startManagingCursor(mCursor);
}
public void cleanup() {
if (mCursor != null) {
mActivity.stopManagingCursor(mCursor);
mCursor.close();
}
}
@Override
public boolean isEnabled(int position) {
mCursor.moveToPosition(position);
return mCursor.getInt(4) > 0; // valid CAN_ENCRYPT
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
return mCursor.getCount();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
mCursor.moveToPosition(position);
return mCursor.getLong(1); // MASTER_KEY_ID
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
mCursor.moveToPosition(position);
View view = mInflater.inflate(R.layout.select_public_key_item, null);
boolean enabled = isEnabled(position);
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
mainUserId.setText(R.string.unknownUserId);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
mainUserIdRest.setText("");
TextView keyId = (TextView) view.findViewById(R.id.keyId);
keyId.setText(R.string.noKey);
TextView status = (TextView) view.findViewById(R.id.status);
status.setText(R.string.unknownStatus);
String userId = mCursor.getString(2); // USER_ID
if (userId != null) {
String chunks[] = userId.split(" <", 2);
userId = chunks[0];
if (chunks.length > 1) {
mainUserIdRest.setText("<" + chunks[1]);
}
mainUserId.setText(userId);
}
long masterKeyId = mCursor.getLong(1); // MASTER_KEY_ID
keyId.setText("" + Long.toHexString(masterKeyId & 0xffffffffL));
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);
}
if (enabled) {
status.setText(R.string.canEncrypt);
} else {
if (mCursor.getInt(3) > 0) {
// has some CAN_ENCRYPT keys, but col(4) = 0, so must be revoked or expired
status.setText(R.string.expired);
} else {
status.setText(R.string.noKey);
}
}
status.setText(status.getText() + " ");
CheckBox selected = (CheckBox) view.findViewById(R.id.selected);
if (!enabled) {
mParent.setItemChecked(position, false);
}
selected.setChecked(mParent.isItemChecked(position));
view.setEnabled(enabled);
mainUserId.setEnabled(enabled);
mainUserIdRest.setEnabled(enabled);
keyId.setEnabled(enabled);
selected.setEnabled(enabled);
status.setEnabled(enabled);
return view;
}
}

View File

@ -1,175 +1,175 @@
package org.thialfihar.android.apg;
import java.util.Date;
import org.thialfihar.android.apg.provider.KeyRings;
import org.thialfihar.android.apg.provider.Keys;
import org.thialfihar.android.apg.provider.UserIds;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class SelectSecretKeyListAdapter extends BaseAdapter {
protected LayoutInflater mInflater;
protected ListView mParent;
protected SQLiteDatabase mDatabase;
protected Cursor mCursor;
protected String mSearchString;
protected Activity mActivity;
public SelectSecretKeyListAdapter(Activity activity, ListView parent, String searchString) {
mSearchString = searchString;
mActivity = activity;
mParent = parent;
mDatabase = Apg.getDatabase().db();
mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
long now = new Date().getTime() / 1000;
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " +
"(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " +
Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " +
Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" +
") " +
" INNER JOIN " + UserIds.TABLE_NAME + " ON " +
"(" + Keys.TABLE_NAME + "." + Keys._ID + " = " +
UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " +
UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
if (searchString != null && searchString.trim().length() > 0) {
String[] chunks = searchString.trim().split(" +");
qb.appendWhere("EXISTS (SELECT tmp." + UserIds._ID + " FROM " +
UserIds.TABLE_NAME + " AS tmp WHERE " +
"tmp." + UserIds.KEY_ID + " = " +
Keys.TABLE_NAME + "." + Keys._ID);
for (int i = 0; i < chunks.length; ++i) {
qb.appendWhere(" AND tmp." + UserIds.USER_ID + " LIKE ");
qb.appendWhereEscapeString("%" + chunks[i] + "%");
}
qb.appendWhere(")");
}
mCursor = qb.query(mDatabase,
new String[] {
KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
"tmp." + Keys.KEY_RING_ID + " = " +
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
"tmp." + Keys.CAN_SIGN + " = '1')", // 3,
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
"tmp." + Keys.KEY_RING_ID + " = " +
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
"tmp." + Keys.CAN_SIGN + " = '1' AND " +
"tmp." + Keys.CREATION + " <= '" + now + "' AND " +
"(tmp." + Keys.EXPIRY + " IS NULL OR " +
"tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4
},
KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?",
new String[] { "" + Id.database.type_secret },
null, null, UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC");
activity.startManagingCursor(mCursor);
}
public void cleanup() {
if (mCursor != null) {
mActivity.stopManagingCursor(mCursor);
mCursor.close();
}
}
@Override
public boolean isEnabled(int position) {
mCursor.moveToPosition(position);
return mCursor.getInt(4) > 0; // valid CAN_SIGN
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
return mCursor.getCount();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
mCursor.moveToPosition(position);
return mCursor.getLong(1); // MASTER_KEY_ID
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
mCursor.moveToPosition(position);
View view = mInflater.inflate(R.layout.select_secret_key_item, null);
boolean enabled = isEnabled(position);
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
mainUserId.setText(R.string.unknownUserId);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
mainUserIdRest.setText("");
TextView keyId = (TextView) view.findViewById(R.id.keyId);
keyId.setText(R.string.noKey);
TextView status = (TextView) view.findViewById(R.id.status);
status.setText(R.string.unknownStatus);
String userId = mCursor.getString(2); // USER_ID
if (userId != null) {
String chunks[] = userId.split(" <", 2);
userId = chunks[0];
if (chunks.length > 1) {
mainUserIdRest.setText("<" + chunks[1]);
}
mainUserId.setText(userId);
}
long masterKeyId = mCursor.getLong(1); // MASTER_KEY_ID
keyId.setText("" + Long.toHexString(masterKeyId & 0xffffffffL));
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);
}
if (enabled) {
status.setText(R.string.canSign);
} else {
if (mCursor.getInt(3) > 0) {
// has some CAN_SIGN keys, but col(4) = 0, so must be revoked or expired
status.setText(R.string.expired);
} else {
status.setText(R.string.noKey);
}
}
status.setText(status.getText() + " ");
view.setEnabled(enabled);
mainUserId.setEnabled(enabled);
mainUserIdRest.setEnabled(enabled);
keyId.setEnabled(enabled);
status.setEnabled(enabled);
return view;
}
package org.thialfihar.android.apg;
import java.util.Date;
import org.thialfihar.android.apg.provider.KeyRings;
import org.thialfihar.android.apg.provider.Keys;
import org.thialfihar.android.apg.provider.UserIds;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class SelectSecretKeyListAdapter extends BaseAdapter {
protected LayoutInflater mInflater;
protected ListView mParent;
protected SQLiteDatabase mDatabase;
protected Cursor mCursor;
protected String mSearchString;
protected Activity mActivity;
public SelectSecretKeyListAdapter(Activity activity, ListView parent, String searchString) {
mSearchString = searchString;
mActivity = activity;
mParent = parent;
mDatabase = Apg.getDatabase().db();
mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
long now = new Date().getTime() / 1000;
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " +
"(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " +
Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " +
Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" +
") " +
" INNER JOIN " + UserIds.TABLE_NAME + " ON " +
"(" + Keys.TABLE_NAME + "." + Keys._ID + " = " +
UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " +
UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
if (searchString != null && searchString.trim().length() > 0) {
String[] chunks = searchString.trim().split(" +");
qb.appendWhere("EXISTS (SELECT tmp." + UserIds._ID + " FROM " +
UserIds.TABLE_NAME + " AS tmp WHERE " +
"tmp." + UserIds.KEY_ID + " = " +
Keys.TABLE_NAME + "." + Keys._ID);
for (int i = 0; i < chunks.length; ++i) {
qb.appendWhere(" AND tmp." + UserIds.USER_ID + " LIKE ");
qb.appendWhereEscapeString("%" + chunks[i] + "%");
}
qb.appendWhere(")");
}
mCursor = qb.query(mDatabase,
new String[] {
KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
"tmp." + Keys.KEY_RING_ID + " = " +
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
"tmp." + Keys.CAN_SIGN + " = '1')", // 3,
"(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " +
"tmp." + Keys.KEY_RING_ID + " = " +
KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " +
"tmp." + Keys.IS_REVOKED + " = '0' AND " +
"tmp." + Keys.CAN_SIGN + " = '1' AND " +
"tmp." + Keys.CREATION + " <= '" + now + "' AND " +
"(tmp." + Keys.EXPIRY + " IS NULL OR " +
"tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4
},
KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?",
new String[] { "" + Id.database.type_secret },
null, null, UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC");
activity.startManagingCursor(mCursor);
}
public void cleanup() {
if (mCursor != null) {
mActivity.stopManagingCursor(mCursor);
mCursor.close();
}
}
@Override
public boolean isEnabled(int position) {
mCursor.moveToPosition(position);
return mCursor.getInt(4) > 0; // valid CAN_SIGN
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
return mCursor.getCount();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
mCursor.moveToPosition(position);
return mCursor.getLong(1); // MASTER_KEY_ID
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
mCursor.moveToPosition(position);
View view = mInflater.inflate(R.layout.select_secret_key_item, null);
boolean enabled = isEnabled(position);
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
mainUserId.setText(R.string.unknownUserId);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
mainUserIdRest.setText("");
TextView keyId = (TextView) view.findViewById(R.id.keyId);
keyId.setText(R.string.noKey);
TextView status = (TextView) view.findViewById(R.id.status);
status.setText(R.string.unknownStatus);
String userId = mCursor.getString(2); // USER_ID
if (userId != null) {
String chunks[] = userId.split(" <", 2);
userId = chunks[0];
if (chunks.length > 1) {
mainUserIdRest.setText("<" + chunks[1]);
}
mainUserId.setText(userId);
}
long masterKeyId = mCursor.getLong(1); // MASTER_KEY_ID
keyId.setText("" + Long.toHexString(masterKeyId & 0xffffffffL));
if (mainUserIdRest.getText().length() == 0) {
mainUserIdRest.setVisibility(View.GONE);
}
if (enabled) {
status.setText(R.string.canSign);
} else {
if (mCursor.getInt(3) > 0) {
// has some CAN_SIGN keys, but col(4) = 0, so must be revoked or expired
status.setText(R.string.expired);
} else {
status.setText(R.string.noKey);
}
}
status.setText(status.getText() + " ");
view.setEnabled(enabled);
mainUserId.setEnabled(enabled);
mainUserIdRest.setEnabled(enabled);
keyId.setEnabled(enabled);
status.setEnabled(enabled);
return view;
}
}

View File

@ -1,78 +1,78 @@
package org.thialfihar.android.apg;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
public class Service extends android.app.Service {
private final IBinder mBinder = new LocalBinder();
public static final String EXTRA_TTL = "ttl";
private int mPassPhraseCacheTtl = 15;
private Handler mCacheHandler = new Handler();
private Runnable mCacheTask = new Runnable() {
public void run() {
// check every ttl/2 seconds, which shouldn't be heavy on the device (even if ttl = 15),
// and makes sure the longest a pass phrase survives in the cache is 1.5 * ttl
int delay = mPassPhraseCacheTtl * 1000 / 2;
// also make sure the delay is not longer than one minute
if (delay > 60000) {
delay = 60000;
}
delay = Apg.cleanUpCache(mPassPhraseCacheTtl, delay);
// don't check too often, even if we were close
if (delay < 5000) {
delay = 5000;
}
mCacheHandler.postDelayed(this, delay);
}
};
static private boolean mIsRunning = false;
@Override
public void onCreate() {
super.onCreate();
mIsRunning = true;
}
@Override
public void onDestroy() {
super.onDestroy();
mIsRunning = false;
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if (intent != null) {
mPassPhraseCacheTtl = intent.getIntExtra(EXTRA_TTL, 15);
}
if (mPassPhraseCacheTtl < 15) {
mPassPhraseCacheTtl = 15;
}
mCacheHandler.removeCallbacks(mCacheTask);
mCacheHandler.postDelayed(mCacheTask, 1000);
}
static public boolean isRunning() {
return mIsRunning;
}
public class LocalBinder extends Binder {
Service getService() {
return Service.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
package org.thialfihar.android.apg;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
public class Service extends android.app.Service {
private final IBinder mBinder = new LocalBinder();
public static final String EXTRA_TTL = "ttl";
private int mPassPhraseCacheTtl = 15;
private Handler mCacheHandler = new Handler();
private Runnable mCacheTask = new Runnable() {
public void run() {
// check every ttl/2 seconds, which shouldn't be heavy on the device (even if ttl = 15),
// and makes sure the longest a pass phrase survives in the cache is 1.5 * ttl
int delay = mPassPhraseCacheTtl * 1000 / 2;
// also make sure the delay is not longer than one minute
if (delay > 60000) {
delay = 60000;
}
delay = Apg.cleanUpCache(mPassPhraseCacheTtl, delay);
// don't check too often, even if we were close
if (delay < 5000) {
delay = 5000;
}
mCacheHandler.postDelayed(this, delay);
}
};
static private boolean mIsRunning = false;
@Override
public void onCreate() {
super.onCreate();
mIsRunning = true;
}
@Override
public void onDestroy() {
super.onDestroy();
mIsRunning = false;
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if (intent != null) {
mPassPhraseCacheTtl = intent.getIntExtra(EXTRA_TTL, 15);
}
if (mPassPhraseCacheTtl < 15) {
mPassPhraseCacheTtl = 15;
}
mCacheHandler.removeCallbacks(mCacheTask);
mCacheHandler.postDelayed(mCacheTask, 1000);
}
static public boolean isRunning() {
return mIsRunning;
}
public class LocalBinder extends Binder {
Service getService() {
return Service.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}

View File

@ -1,27 +1,27 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.provider;
import android.provider.BaseColumns;
public class Accounts implements BaseColumns {
public static final String TABLE_NAME = "accounts";
public static final String _ID_type = "INTEGER PRIMARY KEY";
public static final String NAME = "c_name";
public static final String NAME_type = "TEXT";
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.provider;
import android.provider.BaseColumns;
public class Accounts implements BaseColumns {
public static final String TABLE_NAME = "accounts";
public static final String _ID_type = "INTEGER PRIMARY KEY";
public static final String NAME = "c_name";
public static final String NAME_type = "TEXT";
}

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,33 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.provider;
import android.provider.BaseColumns;
public class KeyRings implements BaseColumns {
public static final String TABLE_NAME = "key_rings";
public static final String _ID_type = "INTEGER PRIMARY KEY";
public static final String MASTER_KEY_ID = "c_master_key_id";
public static final String MASTER_KEY_ID_type = "INT64";
public static final String TYPE = "c_type";
public static final String TYPE_type = "INTEGER";
public static final String WHO_ID = "c_who_id";
public static final String WHO_ID_type = "INTEGER";
public static final String KEY_RING_DATA = "c_key_ring_data";
public static final String KEY_RING_DATA_type = "BLOB";
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.provider;
import android.provider.BaseColumns;
public class KeyRings implements BaseColumns {
public static final String TABLE_NAME = "key_rings";
public static final String _ID_type = "INTEGER PRIMARY KEY";
public static final String MASTER_KEY_ID = "c_master_key_id";
public static final String MASTER_KEY_ID_type = "INT64";
public static final String TYPE = "c_type";
public static final String TYPE_type = "INTEGER";
public static final String WHO_ID = "c_who_id";
public static final String WHO_ID_type = "INTEGER";
public static final String KEY_RING_DATA = "c_key_ring_data";
public static final String KEY_RING_DATA_type = "BLOB";
}

View File

@ -1,31 +1,31 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.provider;
import android.provider.BaseColumns;
public class UserIds implements BaseColumns {
public static final String TABLE_NAME = "user_ids";
public static final String _ID_type = "INTEGER PRIMARY KEY";
public static final String KEY_ID = "c_key_id";
public static final String KEY_ID_type = "INTEGER";
public static final String USER_ID = "c_user_id";
public static final String USER_ID_type = "TEXT";
public static final String RANK = "c_rank";
public static final String RANK_type = "INTEGER";
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.provider;
import android.provider.BaseColumns;
public class UserIds implements BaseColumns {
public static final String TABLE_NAME = "user_ids";
public static final String _ID_type = "INTEGER PRIMARY KEY";
public static final String KEY_ID = "c_key_id";
public static final String KEY_ID_type = "INTEGER";
public static final String USER_ID = "c_user_id";
public static final String USER_ID_type = "TEXT";
public static final String RANK = "c_rank";
public static final String RANK_type = "INTEGER";
}

View File

@ -1,25 +1,25 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.ui.widget;
public interface Editor {
public interface EditorListener {
public void onDeleted(Editor editor);
}
public void setEditorListener(EditorListener listener);
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.ui.widget;
public interface Editor {
public interface EditorListener {
public void onDeleted(Editor editor);
}
public void setEditorListener(EditorListener listener);
}

View File

@ -1,242 +1,242 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.ui.widget;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Vector;
import org.bouncycastle2.openpgp.PGPPublicKey;
import org.bouncycastle2.openpgp.PGPSecretKey;
import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.utils.Choice;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
private PGPSecretKey mKey;
private EditorListener mEditorListener = null;
private boolean mIsMasterKey;
ImageButton mDeleteButton;
TextView mAlgorithm;
TextView mKeyId;
Spinner mUsage;
TextView mCreationDate;
Button mExpiryDateButton;
GregorianCalendar mExpiryDate;
private DatePickerDialog.OnDateSetListener mExpiryDateSetListener =
new DatePickerDialog.OnDateSetListener() {
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
GregorianCalendar date = new GregorianCalendar(year, monthOfYear, dayOfMonth);
setExpiryDate(date);
}
};
public KeyEditor(Context context) {
super(context);
}
public KeyEditor(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
setDrawingCacheEnabled(true);
setAlwaysDrawnWithCacheEnabled(true);
mAlgorithm = (TextView) findViewById(R.id.algorithm);
mKeyId = (TextView) findViewById(R.id.keyId);
mCreationDate = (TextView) findViewById(R.id.creation);
mExpiryDateButton = (Button) findViewById(R.id.expiry);
mUsage = (Spinner) findViewById(R.id.usage);
Choice choices[] = {
new Choice(Id.choice.usage.sign_only,
getResources().getString(R.string.choice_signOnly)),
new Choice(Id.choice.usage.encrypt_only,
getResources().getString(R.string.choice_encryptOnly)),
new Choice(Id.choice.usage.sign_and_encrypt,
getResources().getString(R.string.choice_signAndEncrypt)),
};
ArrayAdapter<Choice> adapter =
new ArrayAdapter<Choice>(getContext(),
android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mUsage.setAdapter(adapter);
mDeleteButton = (ImageButton) findViewById(R.id.delete);
mDeleteButton.setOnClickListener(this);
setExpiryDate(null);
mExpiryDateButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
GregorianCalendar date = mExpiryDate;
if (date == null) {
date = new GregorianCalendar();
}
DatePickerDialog dialog =
new DatePickerDialog(getContext(), mExpiryDateSetListener,
date.get(Calendar.YEAR),
date.get(Calendar.MONTH),
date.get(Calendar.DAY_OF_MONTH));
dialog.setCancelable(true);
dialog.setButton(Dialog.BUTTON_NEGATIVE,
getContext().getString(R.string.btn_noDate),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
setExpiryDate(null);
}
});
dialog.show();
}
});
super.onFinishInflate();
}
public void setValue(PGPSecretKey key, boolean isMasterKey) {
mKey = key;
mIsMasterKey = isMasterKey;
if (mIsMasterKey) {
mDeleteButton.setVisibility(View.INVISIBLE);
}
mAlgorithm.setText(Apg.getAlgorithmInfo(key));
String keyId1Str = Long.toHexString((key.getKeyID() >> 32) & 0xffffffffL);
while (keyId1Str.length() < 8) {
keyId1Str = "0" + keyId1Str;
}
String keyId2Str = Long.toHexString(key.getKeyID() & 0xffffffffL);
while (keyId2Str.length() < 8) {
keyId2Str = "0" + keyId2Str;
}
mKeyId.setText(keyId1Str + " " + keyId2Str);
Vector<Choice> choices = new Vector<Choice>();
boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT);
if (!isElGamalKey) {
choices.add(new Choice(Id.choice.usage.sign_only,
getResources().getString(R.string.choice_signOnly)));
}
if (!mIsMasterKey) {
choices.add(new Choice(Id.choice.usage.encrypt_only,
getResources().getString(R.string.choice_encryptOnly)));
}
if (!isElGamalKey) {
choices.add(new Choice(Id.choice.usage.sign_and_encrypt,
getResources().getString(R.string.choice_signAndEncrypt)));
}
ArrayAdapter<Choice> adapter =
new ArrayAdapter<Choice>(getContext(),
android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mUsage.setAdapter(adapter);
int selectId = 0;
if (Apg.isEncryptionKey(key)) {
if (Apg.isSigningKey(key)) {
selectId = Id.choice.usage.sign_and_encrypt;
} else {
selectId = Id.choice.usage.encrypt_only;
}
} else {
selectId = Id.choice.usage.sign_only;
}
for (int i = 0; i < choices.size(); ++i) {
if (choices.get(i).getId() == selectId) {
mUsage.setSelection(i);
break;
}
}
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(Apg.getCreationDate(key));
mCreationDate.setText(DateFormat.getDateInstance().format(cal.getTime()));
cal = new GregorianCalendar();
Date date = Apg.getExpiryDate(key);
if (date == null) {
setExpiryDate(null);
} else {
cal.setTime(Apg.getExpiryDate(key));
setExpiryDate(cal);
}
}
public PGPSecretKey getValue() {
return mKey;
}
@Override
public void onClick(View v) {
final ViewGroup parent = (ViewGroup)getParent();
if (v == mDeleteButton) {
parent.removeView(this);
if (mEditorListener != null) {
mEditorListener.onDeleted(this);
}
}
}
@Override
public void setEditorListener(EditorListener listener) {
mEditorListener = listener;
}
private void setExpiryDate(GregorianCalendar date) {
mExpiryDate = date;
if (date == null) {
mExpiryDateButton.setText(R.string.none);
} else {
mExpiryDateButton.setText(DateFormat.getDateInstance().format(date.getTime()));
}
}
public GregorianCalendar getExpiryDate() {
return mExpiryDate;
}
public int getUsage() {
return ((Choice) mUsage.getSelectedItem()).getId();
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.ui.widget;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Vector;
import org.bouncycastle2.openpgp.PGPPublicKey;
import org.bouncycastle2.openpgp.PGPSecretKey;
import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.utils.Choice;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
private PGPSecretKey mKey;
private EditorListener mEditorListener = null;
private boolean mIsMasterKey;
ImageButton mDeleteButton;
TextView mAlgorithm;
TextView mKeyId;
Spinner mUsage;
TextView mCreationDate;
Button mExpiryDateButton;
GregorianCalendar mExpiryDate;
private DatePickerDialog.OnDateSetListener mExpiryDateSetListener =
new DatePickerDialog.OnDateSetListener() {
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
GregorianCalendar date = new GregorianCalendar(year, monthOfYear, dayOfMonth);
setExpiryDate(date);
}
};
public KeyEditor(Context context) {
super(context);
}
public KeyEditor(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
setDrawingCacheEnabled(true);
setAlwaysDrawnWithCacheEnabled(true);
mAlgorithm = (TextView) findViewById(R.id.algorithm);
mKeyId = (TextView) findViewById(R.id.keyId);
mCreationDate = (TextView) findViewById(R.id.creation);
mExpiryDateButton = (Button) findViewById(R.id.expiry);
mUsage = (Spinner) findViewById(R.id.usage);
Choice choices[] = {
new Choice(Id.choice.usage.sign_only,
getResources().getString(R.string.choice_signOnly)),
new Choice(Id.choice.usage.encrypt_only,
getResources().getString(R.string.choice_encryptOnly)),
new Choice(Id.choice.usage.sign_and_encrypt,
getResources().getString(R.string.choice_signAndEncrypt)),
};
ArrayAdapter<Choice> adapter =
new ArrayAdapter<Choice>(getContext(),
android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mUsage.setAdapter(adapter);
mDeleteButton = (ImageButton) findViewById(R.id.delete);
mDeleteButton.setOnClickListener(this);
setExpiryDate(null);
mExpiryDateButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
GregorianCalendar date = mExpiryDate;
if (date == null) {
date = new GregorianCalendar();
}
DatePickerDialog dialog =
new DatePickerDialog(getContext(), mExpiryDateSetListener,
date.get(Calendar.YEAR),
date.get(Calendar.MONTH),
date.get(Calendar.DAY_OF_MONTH));
dialog.setCancelable(true);
dialog.setButton(Dialog.BUTTON_NEGATIVE,
getContext().getString(R.string.btn_noDate),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
setExpiryDate(null);
}
});
dialog.show();
}
});
super.onFinishInflate();
}
public void setValue(PGPSecretKey key, boolean isMasterKey) {
mKey = key;
mIsMasterKey = isMasterKey;
if (mIsMasterKey) {
mDeleteButton.setVisibility(View.INVISIBLE);
}
mAlgorithm.setText(Apg.getAlgorithmInfo(key));
String keyId1Str = Long.toHexString((key.getKeyID() >> 32) & 0xffffffffL);
while (keyId1Str.length() < 8) {
keyId1Str = "0" + keyId1Str;
}
String keyId2Str = Long.toHexString(key.getKeyID() & 0xffffffffL);
while (keyId2Str.length() < 8) {
keyId2Str = "0" + keyId2Str;
}
mKeyId.setText(keyId1Str + " " + keyId2Str);
Vector<Choice> choices = new Vector<Choice>();
boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT);
if (!isElGamalKey) {
choices.add(new Choice(Id.choice.usage.sign_only,
getResources().getString(R.string.choice_signOnly)));
}
if (!mIsMasterKey) {
choices.add(new Choice(Id.choice.usage.encrypt_only,
getResources().getString(R.string.choice_encryptOnly)));
}
if (!isElGamalKey) {
choices.add(new Choice(Id.choice.usage.sign_and_encrypt,
getResources().getString(R.string.choice_signAndEncrypt)));
}
ArrayAdapter<Choice> adapter =
new ArrayAdapter<Choice>(getContext(),
android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mUsage.setAdapter(adapter);
int selectId = 0;
if (Apg.isEncryptionKey(key)) {
if (Apg.isSigningKey(key)) {
selectId = Id.choice.usage.sign_and_encrypt;
} else {
selectId = Id.choice.usage.encrypt_only;
}
} else {
selectId = Id.choice.usage.sign_only;
}
for (int i = 0; i < choices.size(); ++i) {
if (choices.get(i).getId() == selectId) {
mUsage.setSelection(i);
break;
}
}
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(Apg.getCreationDate(key));
mCreationDate.setText(DateFormat.getDateInstance().format(cal.getTime()));
cal = new GregorianCalendar();
Date date = Apg.getExpiryDate(key);
if (date == null) {
setExpiryDate(null);
} else {
cal.setTime(Apg.getExpiryDate(key));
setExpiryDate(cal);
}
}
public PGPSecretKey getValue() {
return mKey;
}
@Override
public void onClick(View v) {
final ViewGroup parent = (ViewGroup)getParent();
if (v == mDeleteButton) {
parent.removeView(this);
if (mEditorListener != null) {
mEditorListener.onDeleted(this);
}
}
}
@Override
public void setEditorListener(EditorListener listener) {
mEditorListener = listener;
}
private void setExpiryDate(GregorianCalendar date) {
mExpiryDate = date;
if (date == null) {
mExpiryDateButton.setText(R.string.none);
} else {
mExpiryDateButton.setText(DateFormat.getDateInstance().format(date.getTime()));
}
}
public GregorianCalendar getExpiryDate() {
return mExpiryDate;
}
public int getUsage() {
return ((Choice) mUsage.getSelectedItem()).getId();
}
}

View File

@ -1,337 +1,337 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.ui.widget;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Vector;
import org.bouncycastle2.openpgp.PGPException;
import org.bouncycastle2.openpgp.PGPSecretKey;
import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.ui.widget.Editor.EditorListener;
import org.thialfihar.android.apg.utils.Choice;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Runnable {
private LayoutInflater mInflater;
private View mAdd;
private ViewGroup mEditors;
private TextView mTitle;
private int mType = 0;
private Choice mNewKeyAlgorithmChoice;
private int mNewKeySize;
volatile private PGPSecretKey mNewKey;
private ProgressDialog mProgressDialog;
private Thread mRunningThread = null;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Bundle data = msg.getData();
if (data != null) {
boolean closeProgressDialog = data.getBoolean("closeProgressDialog");
if (closeProgressDialog) {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
}
String error = data.getString(Apg.EXTRA_ERROR);
if (error != null) {
Toast.makeText(getContext(),
getContext().getString(R.string.errorMessage, error),
Toast.LENGTH_SHORT).show();
}
boolean gotNewKey = data.getBoolean("gotNewKey");
if (gotNewKey) {
KeyEditor view =
(KeyEditor) mInflater.inflate(R.layout.edit_key_key_item,
mEditors, false);
view.setEditorListener(SectionView.this);
boolean isMasterKey = (mEditors.getChildCount() == 0);
view.setValue(mNewKey, isMasterKey);
mEditors.addView(view);
SectionView.this.updateEditorsVisible();
}
}
}
};
public SectionView(Context context) {
super(context);
}
public SectionView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ViewGroup getEditors() {
return mEditors;
}
public void setType(int type) {
mType = type;
switch (type) {
case Id.type.user_id: {
mTitle.setText(R.string.section_userIds);
break;
}
case Id.type.key: {
mTitle.setText(R.string.section_keys);
break;
}
default: {
break;
}
}
}
/** {@inheritDoc} */
@Override
protected void onFinishInflate() {
mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
setDrawingCacheEnabled(true);
setAlwaysDrawnWithCacheEnabled(true);
mAdd = findViewById(R.id.header);
mAdd.setOnClickListener(this);
mEditors = (ViewGroup) findViewById(R.id.editors);
mTitle = (TextView) findViewById(R.id.title);
updateEditorsVisible();
super.onFinishInflate();
}
/** {@inheritDoc} */
public void onDeleted(Editor editor) {
this.updateEditorsVisible();
}
protected void updateEditorsVisible() {
final boolean hasChildren = mEditors.getChildCount() > 0;
mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE);
}
/** {@inheritDoc} */
public void onClick(View v) {
switch (mType) {
case Id.type.user_id: {
UserIdEditor view =
(UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item,
mEditors, false);
view.setEditorListener(this);
if (mEditors.getChildCount() == 0) {
view.setIsMainUserId(true);
}
mEditors.addView(view);
break;
}
case Id.type.key: {
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
View view = mInflater.inflate(R.layout.create_key, null);
dialog.setView(view);
dialog.setTitle(R.string.title_createKey);
dialog.setMessage(R.string.keyCreationElGamalInfo);
boolean wouldBeMasterKey = (mEditors.getChildCount() == 0);
final Spinner algorithm = (Spinner) view.findViewById(R.id.algorithm);
Vector<Choice> choices = new Vector<Choice>();
choices.add(new Choice(Id.choice.algorithm.dsa,
getResources().getString(R.string.dsa)));
if (!wouldBeMasterKey) {
choices.add(new Choice(Id.choice.algorithm.elgamal,
getResources().getString(R.string.elgamal)));
}
choices.add(new Choice(Id.choice.algorithm.rsa,
getResources().getString(R.string.rsa)));
ArrayAdapter<Choice> adapter =
new ArrayAdapter<Choice>(getContext(),
android.R.layout.simple_spinner_item,
choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
algorithm.setAdapter(adapter);
// make RSA the default
for (int i = 0; i < choices.size(); ++i) {
if (choices.get(i).getId() == Id.choice.algorithm.rsa) {
algorithm.setSelection(i);
break;
}
}
final EditText keySize = (EditText) view.findViewById(R.id.size);
dialog.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface di, int id) {
di.dismiss();
try {
mNewKeySize = Integer.parseInt("" + keySize.getText());
} catch (NumberFormatException e) {
mNewKeySize = 0;
}
mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem();
createKey();
}
});
dialog.setCancelable(true);
dialog.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface di, int id) {
di.dismiss();
}
});
dialog.create().show();
break;
}
default: {
break;
}
}
this.updateEditorsVisible();
}
public void setUserIds(Vector<String> list) {
if (mType != Id.type.user_id) {
return;
}
mEditors.removeAllViews();
for (String userId : list) {
UserIdEditor view =
(UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item, mEditors, false);
view.setEditorListener(this);
view.setValue(userId);
if (mEditors.getChildCount() == 0) {
view.setIsMainUserId(true);
}
mEditors.addView(view);
}
this.updateEditorsVisible();
}
public void setKeys(Vector<PGPSecretKey> list) {
if (mType != Id.type.key) {
return;
}
mEditors.removeAllViews();
for (PGPSecretKey key : list) {
KeyEditor view =
(KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, mEditors, false);
view.setEditorListener(this);
boolean isMasterKey = (mEditors.getChildCount() == 0);
view.setValue(key, isMasterKey);
mEditors.addView(view);
}
this.updateEditorsVisible();
}
private void createKey() {
mProgressDialog = new ProgressDialog(getContext());
mProgressDialog.setMessage(getContext().getString(R.string.progress_generating));
mProgressDialog.setCancelable(false);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.show();
mRunningThread = new Thread(this);
mRunningThread.start();
}
public void run() {
String error = null;
try {
PGPSecretKey masterKey = null;
String passPhrase;
if (mEditors.getChildCount() > 0) {
masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue();
passPhrase = Apg.getCachedPassPhrase(masterKey.getKeyID());
} else {
passPhrase = "";
}
mNewKey = Apg.createKey(getContext(),
mNewKeyAlgorithmChoice.getId(),
mNewKeySize, passPhrase,
masterKey);
} catch (NoSuchProviderException e) {
error = "" + e;
} catch (NoSuchAlgorithmException e) {
error = "" + e;
} catch (PGPException e) {
error = "" + e;
} catch (InvalidParameterException e) {
error = "" + e;
} catch (InvalidAlgorithmParameterException e) {
error = "" + e;
} catch (Apg.GeneralException e) {
error = "" + e;
}
Message message = new Message();
Bundle data = new Bundle();
data.putBoolean("closeProgressDialog", true);
if (error != null) {
data.putString(Apg.EXTRA_ERROR, error);
} else {
data.putBoolean("gotNewKey", true);
}
message.setData(data);
mHandler.sendMessage(message);
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.ui.widget;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Vector;
import org.bouncycastle2.openpgp.PGPException;
import org.bouncycastle2.openpgp.PGPSecretKey;
import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.ui.widget.Editor.EditorListener;
import org.thialfihar.android.apg.utils.Choice;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Runnable {
private LayoutInflater mInflater;
private View mAdd;
private ViewGroup mEditors;
private TextView mTitle;
private int mType = 0;
private Choice mNewKeyAlgorithmChoice;
private int mNewKeySize;
volatile private PGPSecretKey mNewKey;
private ProgressDialog mProgressDialog;
private Thread mRunningThread = null;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Bundle data = msg.getData();
if (data != null) {
boolean closeProgressDialog = data.getBoolean("closeProgressDialog");
if (closeProgressDialog) {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
}
String error = data.getString(Apg.EXTRA_ERROR);
if (error != null) {
Toast.makeText(getContext(),
getContext().getString(R.string.errorMessage, error),
Toast.LENGTH_SHORT).show();
}
boolean gotNewKey = data.getBoolean("gotNewKey");
if (gotNewKey) {
KeyEditor view =
(KeyEditor) mInflater.inflate(R.layout.edit_key_key_item,
mEditors, false);
view.setEditorListener(SectionView.this);
boolean isMasterKey = (mEditors.getChildCount() == 0);
view.setValue(mNewKey, isMasterKey);
mEditors.addView(view);
SectionView.this.updateEditorsVisible();
}
}
}
};
public SectionView(Context context) {
super(context);
}
public SectionView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ViewGroup getEditors() {
return mEditors;
}
public void setType(int type) {
mType = type;
switch (type) {
case Id.type.user_id: {
mTitle.setText(R.string.section_userIds);
break;
}
case Id.type.key: {
mTitle.setText(R.string.section_keys);
break;
}
default: {
break;
}
}
}
/** {@inheritDoc} */
@Override
protected void onFinishInflate() {
mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
setDrawingCacheEnabled(true);
setAlwaysDrawnWithCacheEnabled(true);
mAdd = findViewById(R.id.header);
mAdd.setOnClickListener(this);
mEditors = (ViewGroup) findViewById(R.id.editors);
mTitle = (TextView) findViewById(R.id.title);
updateEditorsVisible();
super.onFinishInflate();
}
/** {@inheritDoc} */
public void onDeleted(Editor editor) {
this.updateEditorsVisible();
}
protected void updateEditorsVisible() {
final boolean hasChildren = mEditors.getChildCount() > 0;
mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE);
}
/** {@inheritDoc} */
public void onClick(View v) {
switch (mType) {
case Id.type.user_id: {
UserIdEditor view =
(UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item,
mEditors, false);
view.setEditorListener(this);
if (mEditors.getChildCount() == 0) {
view.setIsMainUserId(true);
}
mEditors.addView(view);
break;
}
case Id.type.key: {
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
View view = mInflater.inflate(R.layout.create_key, null);
dialog.setView(view);
dialog.setTitle(R.string.title_createKey);
dialog.setMessage(R.string.keyCreationElGamalInfo);
boolean wouldBeMasterKey = (mEditors.getChildCount() == 0);
final Spinner algorithm = (Spinner) view.findViewById(R.id.algorithm);
Vector<Choice> choices = new Vector<Choice>();
choices.add(new Choice(Id.choice.algorithm.dsa,
getResources().getString(R.string.dsa)));
if (!wouldBeMasterKey) {
choices.add(new Choice(Id.choice.algorithm.elgamal,
getResources().getString(R.string.elgamal)));
}
choices.add(new Choice(Id.choice.algorithm.rsa,
getResources().getString(R.string.rsa)));
ArrayAdapter<Choice> adapter =
new ArrayAdapter<Choice>(getContext(),
android.R.layout.simple_spinner_item,
choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
algorithm.setAdapter(adapter);
// make RSA the default
for (int i = 0; i < choices.size(); ++i) {
if (choices.get(i).getId() == Id.choice.algorithm.rsa) {
algorithm.setSelection(i);
break;
}
}
final EditText keySize = (EditText) view.findViewById(R.id.size);
dialog.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface di, int id) {
di.dismiss();
try {
mNewKeySize = Integer.parseInt("" + keySize.getText());
} catch (NumberFormatException e) {
mNewKeySize = 0;
}
mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem();
createKey();
}
});
dialog.setCancelable(true);
dialog.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface di, int id) {
di.dismiss();
}
});
dialog.create().show();
break;
}
default: {
break;
}
}
this.updateEditorsVisible();
}
public void setUserIds(Vector<String> list) {
if (mType != Id.type.user_id) {
return;
}
mEditors.removeAllViews();
for (String userId : list) {
UserIdEditor view =
(UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item, mEditors, false);
view.setEditorListener(this);
view.setValue(userId);
if (mEditors.getChildCount() == 0) {
view.setIsMainUserId(true);
}
mEditors.addView(view);
}
this.updateEditorsVisible();
}
public void setKeys(Vector<PGPSecretKey> list) {
if (mType != Id.type.key) {
return;
}
mEditors.removeAllViews();
for (PGPSecretKey key : list) {
KeyEditor view =
(KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, mEditors, false);
view.setEditorListener(this);
boolean isMasterKey = (mEditors.getChildCount() == 0);
view.setValue(key, isMasterKey);
mEditors.addView(view);
}
this.updateEditorsVisible();
}
private void createKey() {
mProgressDialog = new ProgressDialog(getContext());
mProgressDialog.setMessage(getContext().getString(R.string.progress_generating));
mProgressDialog.setCancelable(false);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.show();
mRunningThread = new Thread(this);
mRunningThread.start();
}
public void run() {
String error = null;
try {
PGPSecretKey masterKey = null;
String passPhrase;
if (mEditors.getChildCount() > 0) {
masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue();
passPhrase = Apg.getCachedPassPhrase(masterKey.getKeyID());
} else {
passPhrase = "";
}
mNewKey = Apg.createKey(getContext(),
mNewKeyAlgorithmChoice.getId(),
mNewKeySize, passPhrase,
masterKey);
} catch (NoSuchProviderException e) {
error = "" + e;
} catch (NoSuchAlgorithmException e) {
error = "" + e;
} catch (PGPException e) {
error = "" + e;
} catch (InvalidParameterException e) {
error = "" + e;
} catch (InvalidAlgorithmParameterException e) {
error = "" + e;
} catch (Apg.GeneralException e) {
error = "" + e;
}
Message message = new Message();
Bundle data = new Bundle();
data.putBoolean("closeProgressDialog", true);
if (error != null) {
data.putString(Apg.EXTRA_ERROR, error);
} else {
data.putBoolean("gotNewKey", true);
}
message.setData(data);
mHandler.sendMessage(message);
}
}

View File

@ -1,194 +1,194 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.ui.widget;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.thialfihar.android.apg.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RadioButton;
public class UserIdEditor extends LinearLayout implements Editor, OnClickListener {
private EditorListener mEditorListener = null;
private ImageButton mDeleteButton;
private RadioButton mIsMainUserId;
private EditText mName;
private EditText mEmail;
private EditText mComment;
private static final Pattern EMAIL_PATTERN =
Pattern.compile("^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+[.]([a-zA-Z])+([a-zA-Z])+",
Pattern.CASE_INSENSITIVE);
public static class NoNameException extends Exception {
static final long serialVersionUID = 0xf812773343L;
public NoNameException(String message) {
super(message);
}
}
public static class NoEmailException extends Exception {
static final long serialVersionUID = 0xf812773344L;
public NoEmailException(String message) {
super(message);
}
}
public static class InvalidEmailException extends Exception {
static final long serialVersionUID = 0xf812773345L;
public InvalidEmailException(String message) {
super(message);
}
}
public UserIdEditor(Context context) {
super(context);
}
public UserIdEditor(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
setDrawingCacheEnabled(true);
setAlwaysDrawnWithCacheEnabled(true);
mDeleteButton = (ImageButton) findViewById(R.id.delete);
mDeleteButton.setOnClickListener(this);
mIsMainUserId = (RadioButton) findViewById(R.id.isMainUserId);
mIsMainUserId.setOnClickListener(this);
mName = (EditText) findViewById(R.id.name);
mEmail = (EditText) findViewById(R.id.email);
mComment = (EditText) findViewById(R.id.comment);
super.onFinishInflate();
}
public void setValue(String userId) {
mName.setText("");
mComment.setText("");
mEmail.setText("");
Pattern withComment = Pattern.compile("^(.*) [(](.*)[)] <(.*)>$");
Matcher matcher = withComment.matcher(userId);
if (matcher.matches()) {
mName.setText(matcher.group(1));
mComment.setText(matcher.group(2));
mEmail.setText(matcher.group(3));
return;
}
Pattern withoutComment = Pattern.compile("^(.*) <(.*)>$");
matcher = withoutComment.matcher(userId);
if (matcher.matches()) {
mName.setText(matcher.group(1));
mEmail.setText(matcher.group(2));
return;
}
}
public String getValue() throws NoNameException, NoEmailException, InvalidEmailException {
String name = ("" + mName.getText()).trim();
String email = ("" + mEmail.getText()).trim();
String comment = ("" + mComment.getText()).trim();
if (email.length() > 0) {
Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
if (!emailMatcher.matches()) {
throw new InvalidEmailException(
getContext().getString(R.string.error_invalidEmail, email));
}
}
String userId = name;
if (comment.length() > 0) {
userId += " (" + comment + ")";
}
if (email.length() > 0) {
userId += " <" + email + ">";
}
if (userId.equals("")) {
// ok, empty one...
return userId;
}
// otherwise make sure that name and email exist
if (name.equals("")) {
throw new NoNameException("need a name");
}
if (email.equals("")) {
throw new NoEmailException("need an email");
}
return userId;
}
@Override
public void onClick(View v) {
final ViewGroup parent = (ViewGroup)getParent();
if (v == mDeleteButton) {
boolean wasMainUserId = mIsMainUserId.isChecked();
parent.removeView(this);
if (mEditorListener != null) {
mEditorListener.onDeleted(this);
}
if (wasMainUserId && parent.getChildCount() > 0) {
UserIdEditor editor = (UserIdEditor) parent.getChildAt(0);
editor.setIsMainUserId(true);
}
} else if (v == mIsMainUserId) {
for (int i = 0; i < parent.getChildCount(); ++i) {
UserIdEditor editor = (UserIdEditor) parent.getChildAt(i);
if (editor == this) {
editor.setIsMainUserId(true);
} else {
editor.setIsMainUserId(false);
}
}
}
}
public void setIsMainUserId(boolean value) {
mIsMainUserId.setChecked(value);
}
public boolean isMainUserId() {
return mIsMainUserId.isChecked();
}
@Override
public void setEditorListener(EditorListener listener) {
mEditorListener = listener;
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.ui.widget;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.thialfihar.android.apg.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RadioButton;
public class UserIdEditor extends LinearLayout implements Editor, OnClickListener {
private EditorListener mEditorListener = null;
private ImageButton mDeleteButton;
private RadioButton mIsMainUserId;
private EditText mName;
private EditText mEmail;
private EditText mComment;
private static final Pattern EMAIL_PATTERN =
Pattern.compile("^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+[.]([a-zA-Z])+([a-zA-Z])+",
Pattern.CASE_INSENSITIVE);
public static class NoNameException extends Exception {
static final long serialVersionUID = 0xf812773343L;
public NoNameException(String message) {
super(message);
}
}
public static class NoEmailException extends Exception {
static final long serialVersionUID = 0xf812773344L;
public NoEmailException(String message) {
super(message);
}
}
public static class InvalidEmailException extends Exception {
static final long serialVersionUID = 0xf812773345L;
public InvalidEmailException(String message) {
super(message);
}
}
public UserIdEditor(Context context) {
super(context);
}
public UserIdEditor(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
setDrawingCacheEnabled(true);
setAlwaysDrawnWithCacheEnabled(true);
mDeleteButton = (ImageButton) findViewById(R.id.delete);
mDeleteButton.setOnClickListener(this);
mIsMainUserId = (RadioButton) findViewById(R.id.isMainUserId);
mIsMainUserId.setOnClickListener(this);
mName = (EditText) findViewById(R.id.name);
mEmail = (EditText) findViewById(R.id.email);
mComment = (EditText) findViewById(R.id.comment);
super.onFinishInflate();
}
public void setValue(String userId) {
mName.setText("");
mComment.setText("");
mEmail.setText("");
Pattern withComment = Pattern.compile("^(.*) [(](.*)[)] <(.*)>$");
Matcher matcher = withComment.matcher(userId);
if (matcher.matches()) {
mName.setText(matcher.group(1));
mComment.setText(matcher.group(2));
mEmail.setText(matcher.group(3));
return;
}
Pattern withoutComment = Pattern.compile("^(.*) <(.*)>$");
matcher = withoutComment.matcher(userId);
if (matcher.matches()) {
mName.setText(matcher.group(1));
mEmail.setText(matcher.group(2));
return;
}
}
public String getValue() throws NoNameException, NoEmailException, InvalidEmailException {
String name = ("" + mName.getText()).trim();
String email = ("" + mEmail.getText()).trim();
String comment = ("" + mComment.getText()).trim();
if (email.length() > 0) {
Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
if (!emailMatcher.matches()) {
throw new InvalidEmailException(
getContext().getString(R.string.error_invalidEmail, email));
}
}
String userId = name;
if (comment.length() > 0) {
userId += " (" + comment + ")";
}
if (email.length() > 0) {
userId += " <" + email + ">";
}
if (userId.equals("")) {
// ok, empty one...
return userId;
}
// otherwise make sure that name and email exist
if (name.equals("")) {
throw new NoNameException("need a name");
}
if (email.equals("")) {
throw new NoEmailException("need an email");
}
return userId;
}
@Override
public void onClick(View v) {
final ViewGroup parent = (ViewGroup)getParent();
if (v == mDeleteButton) {
boolean wasMainUserId = mIsMainUserId.isChecked();
parent.removeView(this);
if (mEditorListener != null) {
mEditorListener.onDeleted(this);
}
if (wasMainUserId && parent.getChildCount() > 0) {
UserIdEditor editor = (UserIdEditor) parent.getChildAt(0);
editor.setIsMainUserId(true);
}
} else if (v == mIsMainUserId) {
for (int i = 0; i < parent.getChildCount(); ++i) {
UserIdEditor editor = (UserIdEditor) parent.getChildAt(i);
if (editor == this) {
editor.setIsMainUserId(true);
} else {
editor.setIsMainUserId(false);
}
}
}
}
public void setIsMainUserId(boolean value) {
mIsMainUserId.setChecked(value);
}
public boolean isMainUserId() {
return mIsMainUserId.isChecked();
}
@Override
public void setEditorListener(EditorListener listener) {
mEditorListener = listener;
}
}

View File

@ -1,44 +1,44 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.utils;
public class Choice {
private String mName;
private int mId;
public Choice() {
mId = -1;
mName = "";
}
public Choice(int id, String name) {
mId = id;
mName = name;
}
public int getId() {
return mId;
}
public String getName() {
return mName;
}
public String toString() {
return mName;
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.utils;
public class Choice {
private String mName;
private int mId;
public Choice() {
mId = -1;
mName = "";
}
public Choice(int id, String name) {
mId = id;
mName = name;
}
public int getId() {
return mId;
}
public String getName() {
return mName;
}
public String toString() {
return mName;
}
}

View File

@ -1,31 +1,31 @@
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.utils;
import java.util.Iterator;
public class IterableIterator<T> implements Iterable<T> {
private Iterator<T> mIter;
public IterableIterator(Iterator<T> iter) {
mIter = iter;
}
public Iterator<T> iterator() {
return mIter;
}
}
/*
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thialfihar.android.apg.utils;
import java.util.Iterator;
public class IterableIterator<T> implements Iterable<T> {
private Iterator<T> mIter;
public IterableIterator(Iterator<T> iter) {
mIter = iter;
}
public Iterator<T> iterator() {
return mIter;
}
}