k9mail源码分析.docx
- 文档编号:4083126
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:31
- 大小:398.51KB
k9mail源码分析.docx
《k9mail源码分析.docx》由会员分享,可在线阅读,更多相关《k9mail源码分析.docx(31页珍藏版)》请在冰点文库上搜索。
k9mail源码分析
privatevoidfinishAutoSetup(){
Stringemail=mEmailView.getText().toString();
Stringpassword=mPasswordView.getText().toString();
String[]emailParts=splitEmail(email);
Stringuser=emailParts[0];
Stringdomain=emailParts[1];
URIincomingUri=null;
URIoutgoingUri=null;
try{
StringuserEnc=URLEncoder.encode(user,"UTF-8");
StringpasswordEnc=URLEncoder.encode(password,"UTF-8");
StringincomingUsername=mProvider.incomingUsernameTemplate;
incomingUsername=incomingUsername.replaceAll("\\$email",email);
incomingUsername=incomingUsername.replaceAll("\\$user",userEnc);
incomingUsername=incomingUsername.replaceAll("\\$domain",domain);
URIincomingUriTemplate=mProvider.incomingUriTemplate;
incomingUri=newURI(incomingUriTemplate.getScheme(),incomingUsername+":
"
+passwordEnc,incomingUriTemplate.getHost(),incomingUriTemplate.getPort(),null,
null,null);
StringoutgoingUsername=mProvider.outgoingUsernameTemplate;
URIoutgoingUriTemplate=mProvider.outgoingUriTemplate;
if(outgoingUsername!
=null){
outgoingUsername=outgoingUsername.replaceAll("\\$email",email);
outgoingUsername=outgoingUsername.replaceAll("\\$user",userEnc);
outgoingUsername=outgoingUsername.replaceAll("\\$domain",domain);
outgoingUri=newURI(outgoingUriTemplate.getScheme(),outgoingUsername+":
"
+passwordEnc,outgoingUriTemplate.getHost(),outgoingUriTemplate.getPort(),null,
null,null);
}else{
outgoingUri=newURI(outgoingUriTemplate.getScheme(),
null,outgoingUriTemplate.getHost(),outgoingUriTemplate.getPort(),null,
null,null);
}
if(mAccount==null){
mAccount=Preferences.getPreferences(this).newAccount();
}
mAccount.setName(getOwnerName());
mAccount.setEmail(email);
mAccount.setStoreUri(incomingUri.toString());
mAccount.setTransportUri(outgoingUri.toString());
mAccount.setDraftsFolderName(getString(R.string.special_mailbox_name_drafts));
mAccount.setTrashFolderName(getString(R.string.special_mailbox_name_trash));
mAccount.setArchiveFolderName(getString(R.string.special_mailbox_name_archive));
//Yahoo!
hasaspecialfolderforSpam,called"BulkMail".
if(incomingUriTemplate.getHost().toLowerCase().endsWith("")){
mAccount.setSpamFolderName("BulkMail");
}else{
mAccount.setSpamFolderName(getString(R.string.special_mailbox_name_spam));
}
mAccount.setSentFolderName(getString(R.string.special_mailbox_name_sent));
if(incomingUri.toString().startsWith("imap")){
mAccount.setDeletePolicy(Account.DELETE_POLICY_ON_DELETE);
}elseif(incomingUri.toString().startsWith("pop3")){
mAccount.setDeletePolicy(Account.DELETE_POLICY_NEVER);
}
//Checkincominghere.ThencheckoutgoinginonActivityResult()
AccountSetupCheckSettings.actionCheckSettings(this,mAccount,CheckDirection.INCOMING);
}catch(UnsupportedEncodingExceptionenc){
//Thisreallyshouldn'thappensincetheencodingishardcodedtoUTF-8
Log.e(K9.LOG_TAG,"Couldn'turlencodeusernameorpassword.",enc);
}catch(URISyntaxExceptionuse){
/*
*IfthereissomeproblemwiththeURIwegiveupandgoonto
*manualsetup.
*/
onManualSetup();
}
}
MIME邮件的构成
MIME消息(邮件,对应k9mail的MimeMessage类),由消息头(对应k9mai的MimeHeader类)和消息体(body对应k9mail的Body接口)两大部分组成。
邮件头中不允许出现空行。
邮件头包含了发件人、收件人、主题、时间、MIME版本、邮件内容的类型等重要信息。
每条信息称为一个域,由域名后加“:
”和信息的内容构成,可以是一行,较长的也可以占用多行。
域的首行必须“顶头”写,即左边不能有空白字符(空格和制表符);续行则必须以空白字符打头,且第一个空白字符不是信息本身固有的,解码时要过滤掉。
邮件头信息中各个字段及其含义的说明如下表:
邮件体(body)指的是邮件的内容,它的类型由邮件头的“Content-Type”域指出,常见的简单类型有text/plain(纯文本)和text/html(超文本)。
multipart类型是MIME邮件的精髓,对应k9mail的MultiPart类。
邮件体被分为多个段或者多个部分,对应k9mail的Part接口,每个段又包含段头和段体两部分,这两部分之间也以空行分隔。
常见的multipart类型有三种:
multipart/mixed,multipart/related和multipart/alternative。
从它们的名称,不难推知这些类型各自的含义和用处。
它们之间的层次关系如下图所示,从中可以看出,如果在邮件中要添加附件,必须定义multipart/mixed段;如果存在内嵌资源,至少要定义multipart/related段;如果纯文本与超文本共存,至少要定义multipart/alternative段。
为什么说是“至少”?
举个例子说,如果只有纯文本与超文本正文,那么在邮件头中将类型扩大化,定义为multipart/related,甚至multipart/mixed,都是允许的。
k-9-4.804\src\com\fsck\k9\mail
地址:
address.java
地址和通讯录名字之间的转换
身份认证:
Authentication.java
函数作用:
计算对CRAM-MD5认证机制的响应,给用户提供认证信息和服务器提供随机数。
packagecom.fsck.k9.mail;
importjava.security.MessageDigest;
importcom.fsck.k9.mail.filter.Base64;
importcom.fsck.k9.mail.filter.Hex;
publicclassAuthentication{
privatestaticfinalStringUS_ASCII="US-ASCII";
/**
*ComputestheresponseforCRAM-MD5authenticationmechanismgiventheusercredentialsand
*theserver-providednonce.
*
*@paramusernameTheusername.
*@parampasswordThepassword.
*@paramb64NonceThenonceasbase64-encodedstring.
*@returnTheCRAM-MD5response.
*
*@throwsAuthenticationFailedExceptionIfsomethingwentwrong.
*
*@seeAuthentication#computeCramMd5Bytes(String,String,byte[])
*/
publicstaticStringcomputeCramMd5(Stringusername,Stringpassword,Stringb64Nonce)
throwsAuthenticationFailedException{
try{
byte[]b64NonceBytes=b64Nonce.getBytes(US_ASCII);
byte[]b64CRAM=computeCramMd5Bytes(username,password,b64NonceBytes);
returnnewString(b64CRAM,US_ASCII);
}catch(AuthenticationFailedExceptione){
throwe;
}catch(Exceptione){
thrownewAuthenticationFailedException("Thisshouldn'thappen",e);
}
}
/**
*ComputestheresponseforCRAM-MD5authenticationmechanismgiventheusercredentialsand
*theserver-providednonce.
*
*@paramusernameTheusername.
*@parampasswordThepassword.
*@paramb64NonceThenonceasbase64-encodedbytearray.
*@returnTheCRAM-MD5responseasbytearray.
*
*@throwsAuthenticationFailedExceptionIfsomethingwentwrong.
*
*@see //tools.ietf.org/html/rfc2195">RFC2195 */ publicstaticbyte[]computeCramMd5Bytes(Stringusername,Stringpassword,byte[]b64Nonce) throwsAuthenticationFailedException{ try{ byte[]nonce=Base64.decodeBase64(b64Nonce); byte[]secretBytes=password.getBytes(US_ASCII); MessageDigestmd=MessageDigest.getInstance("MD5"); if(secretBytes.length>64){ secretBytes=md.digest(secretBytes); } byte[]ipad=newbyte[64]; byte[]opad=newbyte[64]; System.arraycopy(secretBytes,0,ipad,0,secretBytes.length); System.arraycopy(secretBytes,0,opad,0,secretBytes.length); for(inti=0;i for(inti=0;i md.update(ipad); byte[]firstPass=md.digest(nonce); md.update(opad); byte[]result=md.digest(firstPass); StringplainCRAM=username+""+newString(Hex.encodeHex(result)); byte[]b64CRAM=Base64.encodeBase64(plainCRAM.getBytes(US_ASCII)); returnb64CRAM; }catch(Exceptione){ thrownewAuthenticationFailedException("SomethingwentwrongduringCRAM-MD5computation",e); } } } k-9-.fsck.k9.mail.transport; SmtpTransport.java WebDavTransport.java k-9-4.804\src\com\fsck\k9\mail\transport\imap ImapSettings.java com.fsck.k9: Account.java 这是个实体类,也是android平台上MVC模式中的Model类,它除了封装Email账户的信息外,还被设计用于保存账户的各种设置,包括账户身份认证设置Identity、字体设置FontSizes、通知设置NotificationSetting和邮件收发地址、草稿箱、垃圾箱、总是密送到的账户、反垃圾用的文件夹、各种网络(3g、WiFi等)连接下是否启用压缩等,这些数据使用android平台的SharedPreferences保存,SharedPreferences是平台下除了SQLite外另外一种方便好用的数据持久化方式,应该是android平台上最简单的读写外部数据的方法,特别适用于保存客户端不同用户的个性化设置信息。 一个账户用一个UUID定义,可以通过mUuid属性的值来区分两个账户。 Accou类实现了接口BaseAccount,这个接口定义了获取、设置Email账户的及其描述的String类型的数据,还定义了获取账户UUID值的方法。 通过Account可以获得账户对应的LocalStore实例,然后可以进一步获得该账户在SQLite数据库里面保存的一切信息,包括邮件文件夹、邮件等,还可以获得远程邮件服务器的代理(RemoteStore,包括ImapStore、Pop3Store和WebDavStore,这些组件封装了对远程服务器的访问),并进一步获得其内部类(例如ImapStore的内部类ImapFolder),实现对远程服务器上相应对象的操作。 Account的类型怎么区分的? 通过Account类的属性mStoreUri,不同类型的Account的mStoreUri的值以不同的前缀开头,k9mail分别使用pop3、imap和webdav表示相应的三种Email账户类型,该属性的值的形式如下: imap: //PLAIN: 帐号: 密码@: 143/1%7C 这些数据变化后,k9mail会调用Account类的save方法通过SharedPreferences.Editor把这些数据保存到xml配置文件中。 该类存储了一个账号的所有信息。 Accountstoresallofthesettingsforasingleaccountdefinedbytheuser.ItisabletosaveanddeleteitselfgivenaPreferencestoworkwith.EachaccountisdefinedbyaUUID. (1)Account的默认信息: 收发件箱、删除策略、网络类型、消息类型、键值、颜色、排序类、数据库ID等等 (2)protectedAccount(Contextcontext) 设置账户的基本信息: (3)privateintpickColor(Contextcontext) *PickaniceAndroidguidelinescolorifwehaven'tusedthemallyet. (4)protectedAccount(Preferencespreferences,Stringuuid){ this.mUuid=uuid; loadAccount(preferences); } (5)privatesynchronizedvoidloadAccount(Preferencespreferences) *Loadstoredsettingsforthisaccount. (6)protectedsynchronizedvoiddelete(Preferencespreferences) 删除一个账户 (7)publicstaticintfindNewAccountNumber(List 为新账户建立一个AccountNumber (8)publicstaticList 获得存在的所有帐户的AccountNumber列表 (9)publicstaticintgenerateAccountNumber(Preferencespreferences) 生成一个AccountNumber (10)publicvoidmove(Preferencespreferences,booleanmoveUp) 移动账户的位置,上移或下移一位 (11)publicsynchronizedvoidsave(Preferencespreferences) 保存账户的配置信息。 当账户被创建时,我们会为其分配一个唯一的AccountNumber (12)publicvoidresetVisibleLimits() 重置可以显示的账户的个数 (13)publicAccountStatsgetStats(Contextcontext)throwsMessagingException 获得帐户状态 (14)颜色相关的函数 publicsynchronizedvoidsetChipColor(intcolor) publicsynchronizedvoidcacheChips() publicColorChipgetCheckmarkChip(){ returnmCheckmarkChip; } publicsynchronizedintgetChipColor(){ returnmChipColor; } publicColorChipgenerateColorChip(booleanmessageRead,booleantoMe,booleanccMe,booleanfromMe,booleanmessageFlagged) publicColorChipgenerateColorChip(){ returnnewColorChip(mChipColor,false,ColorChip.CIRCULAR); } (15)publicStringgetUuid(){ returnmUuid; } 获得当前账户的Uuid (16)publicUrigetContentUri(){ returnUri.parse("content: //accounts/"+getUuid()); } 获得当前账户的ContentUri (16)publicsynchronizedStringgetStoreUri(){ returnmStoreUri; } 获得当前账户的StoreUri (17)publicsynchronizedvoidsetStoreUri(StringstoreUri){ this.mStoreUri=storeUri; } 设置当前账户的Store
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- k9mail 源码 分析