作者 邓超

m

@@ -9,6 +9,20 @@ use Lib\Imap\Request\Msg; @@ -9,6 +9,20 @@ use Lib\Imap\Request\Msg;
9 * @author:dc 9 * @author:dc
10 * @time 2024/9/18 11:30 10 * @time 2024/9/18 11:30
11 * @property Body $body 11 * @property Body $body
  12 + * @method bool seen() 标记为 已读
  13 + * @method bool unseen() 标记为 未读
  14 + * @method bool deleted() 标记为 删除
  15 + * @method bool undeleted() 标记为 取消删除
  16 + * @method bool flagged() 标记为 星标
  17 + * @method bool unflagged() 标记为 取消星标
  18 + * @method bool recent() 标记为 最近
  19 + * @method bool unrecent() 标记为 取消最近
  20 + * @method bool answered() 标记为 已回复
  21 + * @method bool unanswered() 标记为 取消已回复
  22 + * @method bool draft() 标记为 草稿
  23 + * @method bool undraft() 标记为 取消草稿
  24 + * @method bool move(string $folder,bool $utf7 = true) 移动当前邮件到指定目录
  25 + * @method bool copy(string $folder,bool $utf7 = true) 复制当前邮件到指定目录
12 * Class MessageItem 26 * Class MessageItem
13 * @package Lib\Imap\Parse 27 * @package Lib\Imap\Parse
14 */ 28 */
@@ -165,6 +179,31 @@ class MessageItem { @@ -165,6 +179,31 @@ class MessageItem {
165 } 179 }
166 } 180 }
167 181
  182 +
  183 +
  184 + public function __call(string $name, array $arguments)
  185 + {
  186 + switch ($name){
  187 + case 'seen':{return $this->msg->uid($this->uid)->seen();} // 已读
  188 + case 'unseen':{return $this->msg->uid($this->uid)->unseen();} // 未读
  189 + case 'deleted':{return $this->msg->uid($this->uid)->deleted();}//删除
  190 + case 'undeleted':{return $this->msg->uid($this->uid)->undeleted();}//取消删除
  191 + case 'flagged':{return $this->msg->uid($this->uid)->flagged();}//星标
  192 + case 'unflagged':{return $this->msg->uid($this->uid)->unflagged();}//取消星标
  193 + case 'recent':{return $this->msg->uid($this->uid)->recent();}//最近
  194 + case 'unrecent':{return $this->msg->uid($this->uid)->unrecent();}// 取消最近
  195 + case 'answered':{return $this->msg->uid($this->uid)->answered();} // 已回复
  196 + case 'unanswered':{return $this->msg->uid($this->uid)->unanswered();}// 取消已回复
  197 + case 'draft':{return $this->msg->uid($this->uid)->draft();}// 草稿
  198 + case 'undraft':{return $this->msg->uid($this->uid)->undraft();}//取消草稿
  199 + case 'move':{return $this->msg->uid($this->uid)->move(...$arguments);}//移动当前邮件到指定目录
  200 + case 'copy':{return $this->msg->uid($this->uid)->copy(...$arguments);}//移动当前邮件到指定目录
  201 + default:{
  202 + throw new \Exception('未定义函数 '.$name);
  203 + }
  204 + }
  205 + }
  206 +
168 } 207 }
169 208
170 209
  1 +<?php
  2 +
  3 +
  4 +namespace Lib\Imap\Request;
  5 +
  6 +/**
  7 + * 这个是清除状态,比如标记了删除的,会进行删除而不是标记,是找不回来的那种
  8 + * @author:dc
  9 + * @time 2024/9/24 9:33
  10 + * Class Expunge
  11 + * @package Lib\Imap\Request
  12 + */
  13 +class Expunge extends Request{
  14 +
  15 +
  16 + public function exec(): static
  17 + {
  18 +
  19 + $this->cmd('EXPUNGE');
  20 +
  21 + return $this;
  22 + }
  23 +
  24 +
  25 +
  26 +
  27 +}
@@ -116,48 +116,67 @@ class Folder extends Request{ @@ -116,48 +116,67 @@ class Folder extends Request{
116 116
117 117
118 /** 118 /**
  119 + * 当前文件夹 可以使用的标签
119 * @return array 120 * @return array
120 */ 121 */
121 public function getFlags(): array 122 public function getFlags(): array
122 { 123 {
123 - if(!$this->isInit){  
124 - $this->exec();  
125 - }  
126 - return $this->flags; 124 + return $this->getData('flags');
127 } 125 }
128 126
129 /** 127 /**
  128 + * 最近收到的邮件 数量
130 * @return int 129 * @return int
131 */ 130 */
132 public function getRecent(): int 131 public function getRecent(): int
133 { 132 {
134 - if(!$this->isInit){  
135 - $this->exec();  
136 - }  
137 - return $this->recent; 133 + return $this->getData('recent');
138 } 134 }
139 135
140 /** 136 /**
  137 + * 当前文件夹有多少未读数量
141 * @return int 138 * @return int
142 */ 139 */
143 public function getSeen(): int 140 public function getSeen(): int
144 { 141 {
145 - if(!$this->isInit){  
146 - $this->exec();  
147 - }  
148 - return $this->seen; 142 + return $this->getData('seen');
149 } 143 }
150 144
151 145
152 /** 146 /**
  147 + * 读取 文件夹 下面有多少 邮件 总数
153 * @return int 148 * @return int
154 */ 149 */
155 public function getTotal(): int 150 public function getTotal(): int
156 { 151 {
  152 + return $this->getData('total');
  153 + }
  154 +
  155 + /**
  156 + * 读取文件夹属性
  157 + * @param string $name
  158 + * @return int|array
  159 + * @author:dc
  160 + * @time 2024/9/24 9:20
  161 + */
  162 + public function getData(string $name=''):int|array {
157 if(!$this->isInit){ 163 if(!$this->isInit){
158 $this->exec(); 164 $this->exec();
159 } 165 }
160 - return $this->total; 166 + switch ($name){
  167 + case 'total':{return $this->total;}
  168 + case 'seen':{return $this->seen;}
  169 + case 'recent':{return $this->recent;}
  170 + case 'flags':{return $this->flags;}
  171 + default:{
  172 + return [
  173 + 'total'=>$this->total,
  174 + 'seen'=>$this->seen,
  175 + 'recent'=> $this->recent,
  176 + 'flags'=> $this->flags
  177 + ];
  178 + }
  179 + }
161 } 180 }
162 181
163 182
@@ -219,5 +238,39 @@ class Folder extends Request{ @@ -219,5 +238,39 @@ class Folder extends Request{
219 } 238 }
220 239
221 240
  241 + /**
  242 + * 清除 已标记为删除的邮件 不可逆
  243 + * @return bool
  244 + * @author:dc
  245 + * @time 2024/3/14 14:12
  246 + */
  247 + public function expunge():bool {
  248 + return (new Expunge($this->imap))->isOk();
  249 + }
  250 +
  251 + /**
  252 + * 订阅
  253 + * @return bool
  254 + * @author:dc
  255 + * @time 2024/9/24 10:40
  256 + */
  257 + public function subscribe(){
  258 + $this->cmd('SUBSCRIBE "%s"',$this->folder);
  259 +
  260 + return $this->isOk();
  261 + }
  262 +
  263 + /**
  264 + * 取消订阅
  265 + * @return bool
  266 + * @author:dc
  267 + * @time 2024/9/24 10:40
  268 + */
  269 + public function unsubscribe(){
  270 + $this->cmd('UNSUBSCRIBE "%s"',$this->folder);
  271 +
  272 + return $this->isOk();
  273 + }
  274 +
222 275
223 } 276 }
@@ -135,7 +135,7 @@ class Msg extends Request{ @@ -135,7 +135,7 @@ class Msg extends Request{
135 * @author:dc 135 * @author:dc
136 * @time 2024/9/20 17:09 136 * @time 2024/9/20 17:09
137 */ 137 */
138 - public function getBody(MessageItem $msg){ 138 + public function getBody(MessageItem $msg):ParseBody {
139 $this->folder->exec(); // 防止在其他文件夹下面 139 $this->folder->exec(); // 防止在其他文件夹下面
140 140
141 $this->cmd("UID FETCH %s (RFC822.TEXT)", $msg->uid); 141 $this->cmd("UID FETCH %s (RFC822.TEXT)", $msg->uid);
@@ -145,5 +145,186 @@ class Msg extends Request{ @@ -145,5 +145,186 @@ class Msg extends Request{
145 } 145 }
146 146
147 147
  148 + /**
  149 + * 添加/删除 标签
  150 + * @param string $flag
  151 + * @param bool $unset
  152 + * @return bool
  153 + * @author:dc
  154 + * @time 2024/9/24 9:51
  155 + */
  156 + public function setFlags(string $flag, bool $unset = false):bool {
  157 + // FLAGS.SILENT 和 FLAGS 前者不返回新的标签 后者返回新的标签列表
  158 + // UID STORE 1 +FLAGS (\Seen) 这个是添加为已读
  159 + // UID STORE 1 -FLAGS (\Seen) 这个是标记为未读
  160 + $this->cmd("%sSTORE %s %sFLAGS.SILENT (\%s)",
  161 + $this->isUid ? 'UID ' : '',
  162 + implode(',',$this->number),
  163 + $unset ? '-' : '+',
  164 + $flag
  165 + );
  166 + return $this->isOk();
  167 + }
  168 +
  169 +
  170 +
  171 + /**
  172 + * 标记为删除
  173 + * @return bool
  174 + * @author:dc
  175 + * @time 2024/9/18 11:52
  176 + */
  177 + public function deleted():bool {
  178 + return $this->setFlags('\Deleted');
  179 + }
  180 +
  181 + /**
  182 + * 取消删除标记
  183 + * @return bool
  184 + * @author:dc
  185 + * @time 2024/9/24 9:57
  186 + */
  187 + public function undeleted():bool {
  188 + return $this->setFlags('\Deleted',true);
  189 + }
  190 +
  191 + /**
  192 + * 标记为 已读
  193 + * @return bool
  194 + * @author:dc
  195 + * @time 2024/9/18 17:53
  196 + */
  197 + public function seen():bool {
  198 + return $this->setFlags('\Seen');
  199 + }
  200 +
  201 + /**
  202 + * 未读
  203 + * @return bool
  204 + * @author:dc
  205 + * @time 2024/9/24 9:58
  206 + */
  207 + public function unseen():bool {
  208 + return $this->setFlags('\Seen',true);
  209 + }
  210 +
  211 + /**
  212 + * 标记为 草稿
  213 + * @return bool
  214 + * @author:dc
  215 + * @time 2024/9/18 17:53
  216 + */
  217 + public function draft():bool {
  218 + return $this->setFlags('\Draft');
  219 + }
  220 +
  221 + public function undraft():bool {
  222 + return $this->setFlags('\Draft',true);
  223 + }
  224 +
  225 + /**
  226 + * 标记为 星标
  227 + * @return bool
  228 + * @author:dc
  229 + * @time 2024/9/18 17:53
  230 + */
  231 + public function flagged():bool {
  232 + return $this->setFlags('\Flagged');
  233 + }
  234 +
  235 + /**
  236 + * 取消星标
  237 + * @return bool
  238 + * @author:dc
  239 + * @time 2024/9/24 9:59
  240 + */
  241 + public function unflagged():bool {
  242 + return $this->setFlags('\Flagged',true);
  243 + }
  244 +
  245 + /**
  246 + * 标记为已回复
  247 + * @return bool
  248 + * @author:dc
  249 + * @time 2024/9/18 17:52
  250 + */
  251 + public function answered():bool {
  252 + return $this->setFlags('\Answered');
  253 + }
  254 +
  255 + /**
  256 + * 取消标记 已回复
  257 + * @return bool
  258 + * @author:dc
  259 + * @time 2024/9/24 10:00
  260 + */
  261 + public function unanswered():bool {
  262 + return $this->setFlags('\Answered',true);
  263 + }
  264 +
  265 + /**
  266 + * 标记为最近
  267 + * @return bool
  268 + * @author:dc
  269 + * @time 2024/9/18 17:54
  270 + */
  271 + public function recent():bool {
  272 + return $this->setFlags('\recent');
  273 + }
  274 +
  275 + /**
  276 + * 取消最近标记
  277 + * @return bool
  278 + * @author:dc
  279 + * @time 2024/9/24 10:01
  280 + */
  281 + public function unrecent():bool {
  282 + return $this->setFlags('\recent',true);
  283 + }
  284 +
  285 +
  286 + /**
  287 + * 移动邮件 到指定目录
  288 + * @param string $folder
  289 + * @param bool $utf7
  290 + * @return bool
  291 + * @author:dc
  292 + * @time 2024/9/24 10:47
  293 + */
  294 + public function move(string $folder, bool $utf7 = true):bool {
  295 + if(!$utf7) $folder = mb_convert_encoding($folder,"UTF7-IMAP","UTF-8");
  296 +// "UID MOVE {$uids} \"{$folder}\""
  297 + $this->cmd('%s MOVE %s "%s"',
  298 + $this->isUid?'UID ':'',
  299 + implode(',',$this->number),
  300 + $folder
  301 + );
  302 +
  303 + return $this->isOk();
  304 + }
  305 +
  306 + /**
  307 + * 复制邮件到指定目录
  308 + * @param string $folder 目标文件夹
  309 + * @param bool $utf7 是否已转码
  310 + * @return bool
  311 + * @author:dc
  312 + * @time 2024/9/24 10:51
  313 + */
  314 + public function copy(string $folder, bool $utf7 = true):bool {
  315 + if(!$utf7) $folder = mb_convert_encoding($folder,"UTF7-IMAP","UTF-8");
  316 +// "UID COPY {$uids} \"{$folder}\""
  317 + $this->cmd('%s COPY %s "%s"',
  318 + $this->isUid?'UID ':'',
  319 + implode(',',$this->number),
  320 + $folder
  321 + );
  322 +
  323 + return $this->isOk();
  324 +
  325 + }
  326 +
  327 +
  328 +
148 329
149 } 330 }
此 diff 太大无法显示。
  1 +
  2 +
  3 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  4 +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  5 +<head>
  6 + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  7 + <meta name="robots" content="index,follow" />
  8 + <meta name="creator" content="rfchandler version 0.2" />
  9 + <meta name="citation_author" content="A. Gulbrandsen"/>
  10 + <meta name="citation_author" content="N. Freed"/>
  11 + <meta name="citation_publication_date" content="January, 2013"/>
  12 + <meta name="citation_title" content="Internet Message Access Protocol (IMAP) - MOVE Extension"/>
  13 + <meta name="citation_doi" content="10.17487/RFC6851"/>
  14 + <meta name="citation_issn" content="2070-1721"/>
  15 + <meta name="citation_technical_report_number" content="rfc6851"/>
  16 + <meta name="citation_pdf_url" content="https://www.rfc-editor.org/rfc/pdfrfc/rfc6851.txt.pdf"/>
  17 + <title>RFC 6851: Internet Message Access Protocol (IMAP) - MOVE Extension</title>
  18 +
  19 +
  20 + <style type="text/css">
  21 + @media only screen
  22 + and (min-width: 992px)
  23 + and (max-width: 1199px) {
  24 + body { font-size: 14pt; }
  25 + div.content { width: 96ex; margin: 0 auto; }
  26 + }
  27 + @media only screen
  28 + and (min-width: 768px)
  29 + and (max-width: 991px) {
  30 + body { font-size: 14pt; }
  31 + div.content { width: 96ex; margin: 0 auto; }
  32 + }
  33 + @media only screen
  34 + and (min-width: 480px)
  35 + and (max-width: 767px) {
  36 + body { font-size: 11pt; }
  37 + div.content { width: 96ex; margin: 0 auto; }
  38 + }
  39 + @media only screen
  40 + and (max-width: 479px) {
  41 + body { font-size: 8pt; }
  42 + div.content { width: 96ex; margin: 0 auto; }
  43 + }
  44 + @media only screen
  45 + and (min-device-width : 375px)
  46 + and (max-device-width : 667px) {
  47 + body { font-size: 9.5pt; }
  48 + div.content { width: 96ex; margin: 0; }
  49 + }
  50 + @media only screen
  51 + and (min-device-width: 1200px) {
  52 + body { font-size: 10pt; margin: 0 4em; }
  53 + div.content { width: 96ex; margin: 0; }
  54 + }
  55 + h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
  56 + font-weight: bold;
  57 + /* line-height: 0pt; */
  58 + display: inline;
  59 + white-space: pre;
  60 + font-family: monospace;
  61 + font-size: 1em;
  62 + font-weight: bold;
  63 + }
  64 + pre {
  65 + font-size: 1em;
  66 + margin-top: 0px;
  67 + margin-bottom: 0px;
  68 + }
  69 + .pre {
  70 + white-space: pre;
  71 + font-family: monospace;
  72 + }
  73 + .header{
  74 + font-weight: bold;
  75 + }
  76 + .newpage {
  77 + page-break-before: always;
  78 + }
  79 + .invisible {
  80 + text-decoration: none;
  81 + color: white;
  82 + }
  83 + a.selflink {
  84 + color: black;
  85 + text-decoration: none;
  86 + }
  87 + @media print {
  88 + body {
  89 + font-family: monospace;
  90 + font-size: 10.5pt;
  91 + }
  92 + h1, h2, h3, h4, h5, h6 {
  93 + font-size: 1em;
  94 + }
  95 +
  96 + a:link, a:visited {
  97 + color: inherit;
  98 + text-decoration: none;
  99 + }
  100 + .noprint {
  101 + display: none;
  102 + }
  103 + }
  104 + @media screen {
  105 + .grey, .grey a:link, .grey a:visited {
  106 + color: #777;
  107 + }
  108 + .docinfo {
  109 + background-color: #EEE;
  110 + }
  111 + .top {
  112 + border-top: 7px solid #EEE;
  113 + }
  114 + .bgwhite { background-color: white; }
  115 + .bgred { background-color: #F44; }
  116 + .bggrey { background-color: #666; }
  117 + .bgbrown { background-color: #840; }
  118 + .bgorange { background-color: #FA0; }
  119 + .bgyellow { background-color: #EE0; }
  120 + .bgmagenta{ background-color: #F4F; }
  121 + .bgblue { background-color: #66F; }
  122 + .bgcyan { background-color: #4DD; }
  123 + .bggreen { background-color: #4F4; }
  124 +
  125 + .legend { font-size: 90%; }
  126 + .cplate { font-size: 70%; border: solid grey 1px; }
  127 + }
  128 + </style>
  129 + <!--[if IE]>
  130 + <style>
  131 + body {
  132 + font-size: 13px;
  133 + margin: 10px 10px;
  134 + }
  135 + </style>
  136 + <![endif]--> <script type="text/javascript"><!--
  137 +function addHeaderTags() {
  138 + var spans = document.getElementsByTagName("span");
  139 + for (var i=0; i < spans.length; i++) {
  140 + var elem = spans[i];
  141 + if (elem) {
  142 + var level = elem.getAttribute("class");
  143 + if (level == "h1" || level == "h2" || level == "h3" || level == "h4" || level == "h5" || level == "h6") {
  144 + elem.innerHTML = "<"+level+">"+elem.innerHTML+"</"+level+">";
  145 + }
  146 + }
  147 + }
  148 +}
  149 +var legend_html = "Colour legend:<br /> <table> <tr><td>Unknown:</td> <td><span class='cplate bgwhite'>&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> <tr><td>Draft:</td> <td><span class='cplate bgred'>&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> <tr><td>Informational:</td> <td><span class='cplate bgorange'>&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> <tr><td>Experimental:</td> <td><span class='cplate bgyellow'>&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> <tr><td>Best Common Practice:</td> <td><span class='cplate bgmagenta'>&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> <tr><td>Proposed Standard:</td> <td><span class='cplate bgblue'>&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> <tr><td>Draft Standard (old designation):</td> <td><span class='cplate bgcyan'>&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> <tr><td>Internet Standard:</td> <td><span class='cplate bggreen'>&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> <tr><td>Historic:</td> <td><span class='cplate bggrey'>&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> <tr><td>Obsolete:</td> <td><span class='cplate bgbrown'>&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> </table>";
  150 +function showElem(id) {
  151 + var elem = document.getElementById(id);
  152 + elem.innerHTML = eval(id+"_html");
  153 + elem.style.visibility='visible';
  154 +}
  155 +function hideElem(id) {
  156 + var elem = document.getElementById(id);
  157 + elem.style.visibility='hidden';
  158 + elem.innerHTML = "";
  159 +}
  160 +// -->
  161 +</script></head>
  162 +<body>
  163 +<span class="pre noprint docinfo">[<a href="https://www.rfc-editor.org" title="RFC Editor">RFC Home</a>] [<a href="/rfc/rfc6851.txt">TEXT</a>|<a href="/rfc/pdfrfc/rfc6851.txt.pdf">PDF</a>|<a href="/rfc/rfc6851.html">HTML</a>] [<a href='https://datatracker.ietf.org/doc/rfc6851' title='IETF Datatracker information for this document'>Tracker</a>] [<a href="https://datatracker.ietf.org/ipr/search/?rfc=6851&amp;submit=rfc" title="IPR disclosures related to this document">IPR</a>] [<a href='https://www.rfc-editor.org/info/rfc6851' title='Info page'>Info page</a>] </span><br/><span class="pre noprint docinfo"> </span><br /><span class="pre noprint docinfo"> PROPOSED STANDARD</span><br /><span class="pre noprint docinfo"> </span><pre>Internet Engineering Task Force (IETF) A. Gulbrandsen
  164 +Request for Comments: 6851
  165 +Category: Standards Track N. Freed, Ed.
  166 +ISSN: 2070-1721 Oracle
  167 + January 2013
  168 +
  169 +
  170 + <span class="h1">Internet Message Access Protocol (IMAP) - MOVE Extension</span>
  171 +
  172 +Abstract
  173 +
  174 + This document defines an IMAP extension consisting of two new
  175 + commands, MOVE and UID MOVE, that are used to move messages from one
  176 + mailbox to another.
  177 +
  178 +Status of This Memo
  179 +
  180 + This is an Internet Standards Track document.
  181 +
  182 + This document is a product of the Internet Engineering Task Force
  183 + (IETF). It represents the consensus of the IETF community. It has
  184 + received public review and has been approved for publication by the
  185 + Internet Engineering Steering Group (IESG). Further information on
  186 + Internet Standards is available in <a href="./rfc5741#section-2">Section&nbsp;2 of RFC 5741</a>.
  187 +
  188 + Information about the current status of this document, any errata,
  189 + and how to provide feedback on it may be obtained at
  190 + <a href="http://www.rfc-editor.org/info/rfc6851">http://www.rfc-editor.org/info/rfc6851</a>.
  191 +
  192 +Copyright Notice
  193 +
  194 + Copyright (c) 2013 IETF Trust and the persons identified as the
  195 + document authors. All rights reserved.
  196 +
  197 + This document is subject to <a href="https://www.rfc-editor.org/bcp/bcp78">BCP 78</a> and the IETF Trust's Legal
  198 + Provisions Relating to IETF Documents
  199 + (<a href="http://trustee.ietf.org/license-info">http://trustee.ietf.org/license-info</a>) in effect on the date of
  200 + publication of this document. Please review these documents
  201 + carefully, as they describe your rights and restrictions with respect
  202 + to this document. Code Components extracted from this document must
  203 + include Simplified BSD License text as described in Section 4.e of
  204 + the Trust Legal Provisions and are provided without warranty as
  205 + described in the Simplified BSD License.
  206 +
  207 +
  208 +
  209 +
  210 +
  211 +
  212 +
  213 +
  214 +<span class="grey">Gulbrandsen &amp; Freed Standards Track [Page 1]</span></pre>
  215 +<hr class='noprint'/><!--NewPage--><pre class='newpage'><span id="page-2" ></span>
  216 +<span class="grey"><a href="./rfc6851">RFC 6851</a> IMAP - MOVE Extension January 2013</span>
  217 +
  218 +
  219 +<span class="h2"><a class="selflink" id="section-1" href="#section-1">1</a>. Introduction</span>
  220 +
  221 + This document defines an IMAP [<a href="./rfc3501" title="&quot;INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1&quot;">RFC3501</a>] extension to facilitate
  222 + moving messages from one mailbox to another. This is accomplished by
  223 + defining a new MOVE command and extending the UID command to allow
  224 + UID MOVE.
  225 +
  226 + A move function is not provided in the base IMAP specification, so
  227 + clients have instead had to use a combination of the COPY, STORE, and
  228 + EXPUNGE commands to perform this very common operation.
  229 +
  230 + Implementors have long pointed out some shortcomings with this
  231 + approach. Because the moving of a message is not an atomic process,
  232 + interruptions can leave messages in intermediate states. Because
  233 + multiple clients can be accessing the mailboxes at the same time,
  234 + clients can see messages in intermediate states even without
  235 + interruptions. If the source mailbox contains other messages that
  236 + are flagged for deletion, the third step can have the side effect of
  237 + expunging more than just the set of moved messages. Additionally,
  238 + servers with certain types of back-end message stores might have
  239 + efficient ways of moving messages, which don't involve the actual
  240 + copying of data. Such efficiencies are often not available to the
  241 + COPY/STORE/EXPUNGE process.
  242 +
  243 + The MOVE extension is present in any IMAP implementation that returns
  244 + "MOVE" as one of the supported capabilities to the CAPABILITY
  245 + command.
  246 +
  247 +<span class="h2"><a class="selflink" id="section-2" href="#section-2">2</a>. Conventions Used in This Document</span>
  248 +
  249 + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  250 + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  251 + document are to be interpreted as described in [<a href="./rfc2119" title="&quot;Key words for use in RFCs to Indicate Requirement Levels&quot;">RFC2119</a>].
  252 +
  253 + Formal syntax is specified using ABNF [<a href="./rfc5234" title="&quot;Augmented BNF for Syntax Specifications: ABNF&quot;">RFC5234</a>].
  254 +
  255 + Example lines prefaced by "C:" are sent by the client and ones
  256 + prefaced by "S:" by the server.
  257 +
  258 +
  259 +
  260 +
  261 +
  262 +
  263 +
  264 +
  265 +
  266 +
  267 +
  268 +
  269 +
  270 +<span class="grey">Gulbrandsen &amp; Freed Standards Track [Page 2]</span></pre>
  271 +<hr class='noprint'/><!--NewPage--><pre class='newpage'><span id="page-3" ></span>
  272 +<span class="grey"><a href="./rfc6851">RFC 6851</a> IMAP - MOVE Extension January 2013</span>
  273 +
  274 +
  275 +<span class="h2"><a class="selflink" id="section-3" href="#section-3">3</a>. MOVE and UID MOVE</span>
  276 +
  277 +<span class="h3"><a class="selflink" id="section-3.1" href="#section-3.1">3.1</a>. MOVE Command</span>
  278 +
  279 + Arguments: sequence set
  280 + mailbox name
  281 +
  282 + Responses: no specific responses for this command
  283 +
  284 + Result: OK - move completed
  285 +
  286 + NO - move error: can't move those messages or to that name
  287 +
  288 + BAD - command unknown or arguments invalid
  289 +
  290 +<span class="h3"><a class="selflink" id="section-3.2" href="#section-3.2">3.2</a>. UID MOVE Command</span>
  291 +
  292 + This extends the first form of the UID command (see <a href="./rfc3501#section-6.4.8">[RFC3501],
  293 + Section&nbsp;6.4.8</a>) to add the MOVE command defined above as a valid
  294 + argument.
  295 +
  296 +<span class="h3"><a class="selflink" id="section-3.3" href="#section-3.3">3.3</a>. Semantics of MOVE and UID MOVE</span>
  297 +
  298 + The MOVE command takes two arguments: a message set (sequence numbers
  299 + for MOVE, UIDs for UID MOVE) and a named mailbox. Each message
  300 + included in the set is moved, rather than copied, from the selected
  301 + (source) mailbox to the named (target) mailbox.
  302 +
  303 + This means that a new message is created in the target mailbox with a
  304 + new UID, the original message is removed from the source mailbox, and
  305 + it appears to the client as a single action. This has the same
  306 + effect for each message as this sequence:
  307 +
  308 + 1. [UID] COPY
  309 +
  310 + 2. [UID] STORE +FLAGS.SILENT \DELETED
  311 +
  312 + 3. UID EXPUNGE
  313 +
  314 + Although the effect of the MOVE is the same as the preceding steps,
  315 + the semantics are not identical: The intermediate states produced by
  316 + those steps do not occur, and the response codes are different. In
  317 + particular, though the COPY and EXPUNGE response codes will be
  318 + returned, response codes for a STORE MUST NOT be generated and the
  319 + \DELETED flag MUST NOT be set for any message.
  320 +
  321 +
  322 +
  323 +
  324 +
  325 +
  326 +<span class="grey">Gulbrandsen &amp; Freed Standards Track [Page 3]</span></pre>
  327 +<hr class='noprint'/><!--NewPage--><pre class='newpage'><span id="page-4" ></span>
  328 +<span class="grey"><a href="./rfc6851">RFC 6851</a> IMAP - MOVE Extension January 2013</span>
  329 +
  330 +
  331 + Because a MOVE applies to a set of messages, it might fail partway
  332 + through the set. Regardless of whether the command is successful in
  333 + moving the entire set, each individual message SHOULD either be moved
  334 + or unaffected. The server MUST leave each message in a state where
  335 + it is in at least one of the source or target mailboxes (no message
  336 + can be lost or orphaned). The server SHOULD NOT leave any message in
  337 + both mailboxes (it would be bad for a partial failure to result in a
  338 + bunch of duplicate messages). This is true even if the server
  339 + returns a tagged NO response to the command.
  340 +
  341 + Because of the similarity of MOVE to COPY, extensions that affect
  342 + COPY affect MOVE in the same way. Response codes such as TRYCREATE
  343 + (see <a href="./rfc3501#section-6.4.7">[RFC3501], Section&nbsp;6.4.7</a>), as well as those defined by
  344 + extensions, are sent as appropriate. See <a href="#section-4">Section 4</a> for more
  345 + information about how MOVE interacts with other IMAP extensions.
  346 +
  347 + An example:
  348 +
  349 + C: a UID MOVE 42:69 foo
  350 + S: * OK [COPYUID 432432 42:69 1202:1229]
  351 + S: * 22 EXPUNGE
  352 + S: (more expunges)
  353 + S: a OK Done
  354 +
  355 + Note that the server may send unrelated EXPUNGE responses as well, if
  356 + any happen to have been expunged at the same time; this is normal
  357 + IMAP operation.
  358 +
  359 + Implementers will need to read [<a href="./rfc4315" title="&quot;Internet Message Access Protocol (IMAP) - UIDPLUS extension&quot;">RFC4315</a>] to understand what UID
  360 + EXPUNGE does, though full implementation of [<a href="./rfc4315" title="&quot;Internet Message Access Protocol (IMAP) - UIDPLUS extension&quot;">RFC4315</a>] is not
  361 + necessary.
  362 +
  363 + Note that moving a message to the currently selected mailbox (that
  364 + is, where the source and target mailboxes are the same) is allowed
  365 + when copying the message to the currently selected mailbox is
  366 + allowed.
  367 +
  368 + The server may send EXPUNGE (or VANISHED) responses before the tagged
  369 + response, so the client cannot safely send more commands with message
  370 + sequence number arguments while the server is processing MOVE or UID
  371 + MOVE.
  372 +
  373 + Both MOVE and UID MOVE can be pipelined with other commands, but care
  374 + has to be taken. Both commands modify sequence numbers and also
  375 + allow unrelated EXPUNGE responses. The renumbering of other messages
  376 + in the source mailbox following any EXPUNGE response can be
  377 + surprising and makes it unsafe to pipeline any command that relies on
  378 + message sequence numbers after a MOVE or UID MOVE. Similarly, MOVE
  379 +
  380 +
  381 +
  382 +<span class="grey">Gulbrandsen &amp; Freed Standards Track [Page 4]</span></pre>
  383 +<hr class='noprint'/><!--NewPage--><pre class='newpage'><span id="page-5" ></span>
  384 +<span class="grey"><a href="./rfc6851">RFC 6851</a> IMAP - MOVE Extension January 2013</span>
  385 +
  386 +
  387 + cannot be pipelined with a command that might cause message
  388 + renumbering. See <a href="./rfc3501#section-5.5">[RFC3501], Section&nbsp;5.5</a>, for more information about
  389 + ambiguities as well as handling requirements for both clients and
  390 + servers.
  391 +
  392 +<span class="h2"><a class="selflink" id="section-4" href="#section-4">4</a>. Interaction with Other Extensions</span>
  393 +
  394 + This section describes how MOVE interacts with some other IMAP
  395 + extensions.
  396 +
  397 +<span class="h3"><a class="selflink" id="section-4.1" href="#section-4.1">4.1</a>. <a href="./rfc2087">RFC 2087</a>, QUOTA</span>
  398 +
  399 + The QUOTA extension (defined by [<a href="./rfc2087" title="&quot;IMAP4 QUOTA extension&quot;">RFC2087</a>]) may interact with MOVE on
  400 + some servers, in the sense that a MOVE command may succeed where COPY
  401 + would cause a quota overrun.
  402 +
  403 +<span class="h3"><a class="selflink" id="section-4.2" href="#section-4.2">4.2</a>. <a href="./rfc4314">RFC 4314</a>, Access Control List (ACL)</span>
  404 +
  405 + The ACL rights [<a href="./rfc4314" title="&quot;IMAP4 Access Control List (ACL) Extension&quot;">RFC4314</a>] required for MOVE and UID MOVE are the union
  406 + of the ACL rights required for UID STORE, UID COPY, and UID EXPUNGE.
  407 +
  408 +<span class="h3"><a class="selflink" id="section-4.3" href="#section-4.3">4.3</a>. <a href="./rfc4315">RFC 4315</a>, UIDPLUS</span>
  409 +
  410 + Servers supporting UIDPLUS [<a href="./rfc4315" title="&quot;Internet Message Access Protocol (IMAP) - UIDPLUS extension&quot;">RFC4315</a>] SHOULD send COPYUID in response
  411 + to a UID MOVE command. For additional information see <a href="./rfc4315#section-3">Section&nbsp;3 of
  412 + [RFC4315]</a>.
  413 +
  414 + Servers implementing UIDPLUS are also advised to send the COPYUID
  415 + response code in an untagged OK before sending EXPUNGE or moved
  416 + responses. (Sending COPYUID in the tagged OK, as described in the
  417 + UIDPLUS specification, means that clients first receive an EXPUNGE
  418 + for a message and afterwards COPYUID for the same message. It can be
  419 + unnecessarily difficult to process that sequence usefully.)
  420 +
  421 +<span class="h3"><a class="selflink" id="section-4.4" href="#section-4.4">4.4</a>. <a href="./rfc5162">RFC 5162</a>, QRESYNC</span>
  422 +
  423 + The QRESYNC extension [<a href="./rfc5162" title="&quot;IMAP4 Extensions for Quick Mailbox Resynchronization&quot;">RFC5162</a>] states that the server SHOULD send
  424 + VANISHED rather than EXPUNGE in response to the UID EXPUNGE command.
  425 + The same requirement applies to MOVE, and a QRESYNC-enabled client
  426 + needs to handle both VANISHED and EXPUNGE responses to a UID MOVE
  427 + command.
  428 +
  429 + If the server is capable of storing modification sequences for the
  430 + selected mailbox, it MUST increment the per-mailbox mod-sequence if
  431 + at least one message was permanently moved due to the execution of
  432 + the MOVE/UID MOVE command. For each permanently removed message, the
  433 + server MUST remember the incremented mod-sequence and corresponding
  434 + UID. If at least one message was moved, the server MUST send the
  435 +
  436 +
  437 +
  438 +<span class="grey">Gulbrandsen &amp; Freed Standards Track [Page 5]</span></pre>
  439 +<hr class='noprint'/><!--NewPage--><pre class='newpage'><span id="page-6" ></span>
  440 +<span class="grey"><a href="./rfc6851">RFC 6851</a> IMAP - MOVE Extension January 2013</span>
  441 +
  442 +
  443 + updated per-mailbox modification sequence using the HIGHESTMODSEQ
  444 + response code (defined in [<a href="./rfc4551" title="&quot;IMAP Extension for Conditional STORE Operation or Quick Flag Changes Resynchronization&quot;">RFC4551</a>]) in the tagged or untagged OK
  445 + response.
  446 +
  447 + When one or more messages are moved to a target mailbox, if the
  448 + server is capable of storing modification sequences for the mailbox,
  449 + the server MUST generate and assign new modification sequence numbers
  450 + to the moved messages that are higher than the highest modification
  451 + sequence of the messages originally in the mailbox.
  452 +
  453 +<span class="h3"><a class="selflink" id="section-4.5" href="#section-4.5">4.5</a>. IMAP Events in Sieve</span>
  454 +
  455 + MOVE applies to IMAP events in Sieve [<a href="./rfc6785" title="&quot;Support for Internet Message Access Protocol (IMAP) Events in Sieve&quot;">RFC6785</a>] in the same way as
  456 + COPY does. Therefore, MOVE can cause a Sieve script to be invoked
  457 + with the imap.cause set to "COPY". Because MOVE does not cause flags
  458 + to be changed, a MOVE command will not result in a script invocation
  459 + with the imap.cause set to "FLAG".
  460 +
  461 +<span class="h2"><a class="selflink" id="section-5" href="#section-5">5</a>. Formal Syntax</span>
  462 +
  463 + The following syntax specification uses the Augmented Backus-Naur
  464 + Form (ABNF) notation as specified in [<a href="./rfc5234" title="&quot;Augmented BNF for Syntax Specifications: ABNF&quot;">RFC5234</a>]. [<a href="./rfc3501" title="&quot;INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1&quot;">RFC3501</a>] defines
  465 + the non-terminals "capability", "command-select", "sequence-set", and
  466 + "mailbox".
  467 +
  468 + Except as noted otherwise, all alphabetic characters are case
  469 + insensitive. The use of upper or lower case characters to define
  470 + token strings is for editorial clarity only. Implementations MUST
  471 + accept these strings in a case-insensitive fashion.
  472 +
  473 + capability =/ "MOVE"
  474 +
  475 + command-select =/ move
  476 + move = "MOVE" SP sequence-set SP mailbox
  477 + uid = "UID" SP (copy / fetch / search / store / move)
  478 +
  479 +<span class="h2"><a class="selflink" id="section-6" href="#section-6">6</a>. Security Considerations</span>
  480 +
  481 + MOVE does not introduce any new capabilities to IMAP, and this limits
  482 + the security impact. However, the transactional semantics of MOVE
  483 + may interact with specific implementations in ways that could have
  484 + unexpected consequences. For example, moving messages between
  485 + mailboxes under the quota root may require temporary suspension of
  486 + quota checking.
  487 +
  488 + An additional area of concern is interaction with antispam,
  489 + antivirus, and other security scanning and auditing mechanisms.
  490 + Different mailboxes may have different security policies that could
  491 +
  492 +
  493 +
  494 +<span class="grey">Gulbrandsen &amp; Freed Standards Track [Page 6]</span></pre>
  495 +<hr class='noprint'/><!--NewPage--><pre class='newpage'><span id="page-7" ></span>
  496 +<span class="grey"><a href="./rfc6851">RFC 6851</a> IMAP - MOVE Extension January 2013</span>
  497 +
  498 +
  499 + interact with MOVE in complex ways. Scanning with updated rules may
  500 + also be required when messages are moved even when the underlying
  501 + policy has not changed.
  502 +
  503 + MOVE does relieve a problem with the base specification, since client
  504 + authors currently have to devise and implement complicated algorithms
  505 + to handle partial failures of the STORE/COPY/EXPUNGE trio.
  506 + Incomplete or improper implementation of these algorithms can lead to
  507 + mail loss.
  508 +
  509 +<span class="h2"><a class="selflink" id="section-7" href="#section-7">7</a>. IANA Considerations</span>
  510 +
  511 + The IANA has added MOVE to the "IMAP 4 Capabilities" registry,
  512 + &lt;<a href="http://www.iana.org/assignments/imap4-capabilities">http://www.iana.org/assignments/imap4-capabilities</a>&gt;.
  513 +
  514 +<span class="h2"><a class="selflink" id="section-8" href="#section-8">8</a>. Acknowledgments</span>
  515 +
  516 + This document is dedicated to the memory of Mark Crispin, the
  517 + inventor of the IMAP protocol, author of the IMAP protocol
  518 + specification [<a href="./rfc3501" title="&quot;INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1&quot;">RFC3501</a>], and contributor to many other email
  519 + specifications in the IETF.
  520 +
  521 + An extension like this has been proposed many times, by many people.
  522 + This document is based on several of those proposals, most recently
  523 + that by Witold Krecicki. Witold, Benoit Claise, Adrien W. de Croy,
  524 + Stephen Farrell, Bron Gondwana, Dan Karp, Christian Ketterer, Murray
  525 + Kucherawy, Jan Kundrat, Barry Leiba, Alexey Melnikov, Kathleen
  526 + Moriarty, Zoltan Ordogh, Pete Resnick, Timo Sirainen, Michael
  527 + Slusarz, and others provided valuable comments.
  528 +
  529 +<span class="h2"><a class="selflink" id="section-9" href="#section-9">9</a>. References</span>
  530 +
  531 +<span class="h3"><a class="selflink" id="section-9.1" href="#section-9.1">9.1</a>. Normative References</span>
  532 +
  533 + [<a id="ref-RFC2119">RFC2119</a>] Bradner, S., "Key words for use in RFCs to Indicate
  534 + Requirement Levels", <a href="https://www.rfc-editor.org/bcp/bcp14">BCP 14</a>, <a href="./rfc2119">RFC 2119</a>, March 1997.
  535 +
  536 + [<a id="ref-RFC3501">RFC3501</a>] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
  537 + 4rev1", <a href="./rfc3501">RFC 3501</a>, March 2003.
  538 +
  539 + [<a id="ref-RFC4314">RFC4314</a>] Melnikov, A., "IMAP4 Access Control List (ACL) Extension",
  540 + <a href="./rfc4314">RFC 4314</a>, December 2005.
  541 +
  542 + [<a id="ref-RFC4315">RFC4315</a>] Crispin, M., "Internet Message Access Protocol (IMAP) -
  543 + UIDPLUS extension", <a href="./rfc4315">RFC 4315</a>, December 2005.
  544 +
  545 +
  546 +
  547 +
  548 +
  549 +
  550 +<span class="grey">Gulbrandsen &amp; Freed Standards Track [Page 7]</span></pre>
  551 +<hr class='noprint'/><!--NewPage--><pre class='newpage'><span id="page-8" ></span>
  552 +<span class="grey"><a href="./rfc6851">RFC 6851</a> IMAP - MOVE Extension January 2013</span>
  553 +
  554 +
  555 + [<a id="ref-RFC4551">RFC4551</a>] Melnikov, A. and S. Hole, "IMAP Extension for Conditional
  556 + STORE Operation or Quick Flag Changes Resynchronization",
  557 + <a href="./rfc4551">RFC 4551</a>, June 2006.
  558 +
  559 + [<a id="ref-RFC5162">RFC5162</a>] Melnikov, A., Cridland, D., and C. Wilson, "IMAP4
  560 + Extensions for Quick Mailbox Resynchronization", <a href="./rfc5162">RFC 5162</a>,
  561 + March 2008.
  562 +
  563 + [<a id="ref-RFC5234">RFC5234</a>] Crocker, D. and P. Overell, "Augmented BNF for Syntax
  564 + Specifications: ABNF", STD 68, <a href="./rfc5234">RFC 5234</a>, January 2008.
  565 +
  566 +<span class="h3"><a class="selflink" id="section-9.2" href="#section-9.2">9.2</a>. Informative References</span>
  567 +
  568 + [<a id="ref-RFC2087">RFC2087</a>] Myers, J., "IMAP4 QUOTA extension", <a href="./rfc2087">RFC 2087</a>,
  569 + January 1997.
  570 +
  571 + [<a id="ref-RFC6785">RFC6785</a>] Leiba, B., "Support for Internet Message Access Protocol
  572 + (IMAP) Events in Sieve", <a href="./rfc6785">RFC 6785</a>, November 2012.
  573 +
  574 +Authors' Addresses
  575 +
  576 + Arnt Gulbrandsen
  577 + Schweppermannstr. 8
  578 + D-81671 Muenchen
  579 + Germany
  580 +
  581 + Fax: +49 89 4502 9758
  582 + EMail: arnt@gulbrandsen.priv.no
  583 +
  584 +
  585 + Ned Freed (editor)
  586 + Oracle
  587 + 800 Royal Oaks
  588 + Monrovia, CA 91016-6347
  589 + USA
  590 +
  591 + EMail: ned+ietf@mrochek.com
  592 +
  593 +
  594 +
  595 +
  596 +
  597 +
  598 +
  599 +
  600 +
  601 +
  602 +
  603 +
  604 +
  605 +
  606 +Gulbrandsen &amp; Freed Standards Track [Page 8]
  607 +</pre>
  608 +
  609 +</body>
  610 +</html>
  611 +
@@ -49,6 +49,10 @@ if($login->isOk()){// 登录成功 @@ -49,6 +49,10 @@ if($login->isOk()){// 登录成功
49 49
50 50
51 /************************ start 获取某个文件夹下面的邮件 *******************************/ 51 /************************ start 获取某个文件夹下面的邮件 *******************************/
  52 + // uid标记为已读
  53 + $imap->folder('INBOX')->msg()->uid(1)->seen();
  54 + $imap->folder('INBOX')->msg()->uid(1)->flagged(); // 星标
  55 +
52 // 选择文件夹 预备读取 使用分页 查询 56 // 选择文件夹 预备读取 使用分页 查询
53 $msgs = $imap->folder('INBOX')->msg()->forPage()->get(); 57 $msgs = $imap->folder('INBOX')->msg()->forPage()->get();
54 // 1.使用foreach 58 // 1.使用foreach
@@ -68,6 +72,10 @@ if($login->isOk()){// 登录成功 @@ -68,6 +72,10 @@ if($login->isOk()){// 登录成功
68 $msg->isFlagged();//星标 72 $msg->isFlagged();//星标
69 $msg->isRecent();//最近 73 $msg->isRecent();//最近
70 $msg->isSeen();// 已读 74 $msg->isSeen();// 已读
  75 + $msg->seen(); //已读
  76 + $msg->unseen();// 未读
  77 + $msg->flagged();// 星标
  78 + $msg->unflagged();// 取消星标
71 /** 头部信息 @see \Lib\Imap\Parse\Header */ 79 /** 头部信息 @see \Lib\Imap\Parse\Header */
72 $msg->header->getSubject();// 已解析的主题 80 $msg->header->getSubject();// 已解析的主题
73 $msg->header->getFrom();// 已解析的发件人 81 $msg->header->getFrom();// 已解析的发件人
@@ -90,6 +98,8 @@ if($login->isOk()){// 登录成功 @@ -90,6 +98,8 @@ if($login->isOk()){// 登录成功
90 $attachment->getExtension(); 98 $attachment->getExtension();
91 } 99 }
92 100
  101 + $msg->move('回收站',false);
  102 +
93 }); 103 });
94 104
95 105