mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-31 04:59:21 +03:00
Improved FolderCollection handling
This commit is contained in:
parent
a61ef0fa1c
commit
33c10365f0
10 changed files with 79 additions and 97 deletions
|
|
@ -227,8 +227,6 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
|||
name: name,
|
||||
fullName: parentName,
|
||||
delimiter: delimiter,
|
||||
exists: false,
|
||||
isSubscribed: false,
|
||||
flags: ['\\nonexistent']
|
||||
});
|
||||
setFolder(pfolder);
|
||||
|
|
@ -380,6 +378,8 @@ export class FolderModel extends AbstractModel {
|
|||
isFlagged: () => FolderUserStore.currentFolder() === this
|
||||
&& MessagelistUserStore.listSearch().includes('flagged'),
|
||||
|
||||
// isSubscribed: () => this.flags().includes('\\subscribed'),
|
||||
|
||||
hasVisibleSubfolders: () => !!this.subFolders().find(folder => folder.visible()),
|
||||
|
||||
hasSubscriptions: () => this.isSubscribed() | !!this.subFolders().find(
|
||||
|
|
@ -535,6 +535,10 @@ export class FolderModel extends AbstractModel {
|
|||
path.pop();
|
||||
folder.parentName = path.join(folder.delimiter);
|
||||
|
||||
folder.isSubscribed(folder.flags.includes('\\subscribed'));
|
||||
folder.exists = !folder.flags.includes('\\nonexistent');
|
||||
folder.selectable(folder.exists && !folder.flags.includes('\\noselect'));
|
||||
|
||||
type && 'mail' != type && folder.kolabType(type);
|
||||
}
|
||||
return folder;
|
||||
|
|
|
|||
|
|
@ -476,6 +476,9 @@ html.sm-msgView-bottom {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@media all and (display-mode: fullscreen) {
|
||||
*/
|
||||
html.rl-fullscreen {
|
||||
|
||||
#rl-left,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ abstract class Collection extends \ArrayObject implements \JsonSerializable
|
|||
}
|
||||
}
|
||||
|
||||
public function keys() : array
|
||||
{
|
||||
return \array_keys($this->getArrayCopy());
|
||||
}
|
||||
|
||||
public function Add($mItem, bool $bToTop = false) : self
|
||||
{
|
||||
$this->append($mItem, $bToTop);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
namespace MailSo\Imap\Commands;
|
||||
|
||||
use MailSo\Imap\Folder;
|
||||
use MailSo\Imap\FolderCollection;
|
||||
use MailSo\Imap\FolderInformation;
|
||||
use MailSo\Imap\SequenceSet;
|
||||
use MailSo\Imap\Enumerations\FolderStatus;
|
||||
|
|
@ -171,7 +172,7 @@ trait Folders
|
|||
$oFolderInfo = $this->oCurrentFolderInfo;
|
||||
$bReselect = false;
|
||||
$bWritable = false;
|
||||
if ($oFolderInfo && $sFolderName === $oFolderInfo->FolderName) {
|
||||
if ($oFolderInfo && $sFolderName === $oFolderInfo->FullName) {
|
||||
if ($oFolderInfo->hasStatus) {
|
||||
return $oFolderInfo;
|
||||
}
|
||||
|
|
@ -351,7 +352,7 @@ trait Folders
|
|||
{
|
||||
if (!$bForceReselect
|
||||
&& $this->oCurrentFolderInfo
|
||||
&& $sFolderName === $this->oCurrentFolderInfo->FolderName
|
||||
&& $sFolderName === $this->oCurrentFolderInfo->FullName
|
||||
&& ($bIsWritable === $this->oCurrentFolderInfo->IsWritable || $this->oCurrentFolderInfo->IsWritable)
|
||||
) {
|
||||
return $this->oCurrentFolderInfo;
|
||||
|
|
@ -444,7 +445,7 @@ trait Folders
|
|||
* @throws \MailSo\Net\Exceptions\*
|
||||
* @throws \MailSo\Imap\Exceptions\*
|
||||
*/
|
||||
public function FolderList(string $sParentFolderName, string $sListPattern, bool $bIsSubscribeList = false, bool $bUseListStatus = false) : array
|
||||
public function FolderList(string $sParentFolderName, string $sListPattern, bool $bIsSubscribeList = false, bool $bUseListStatus = false) : FolderCollection
|
||||
{
|
||||
$sCmd = 'LIST';
|
||||
|
||||
|
|
@ -504,16 +505,17 @@ trait Folders
|
|||
$aMetadata = $bMetadata ? $this->getAllMetadata() : null;
|
||||
|
||||
$this->SendRequest($sCmd, $aParameters);
|
||||
$aReturn = array();
|
||||
$aFolders = array();
|
||||
$oFolderCollection = new FolderCollection;
|
||||
$sDelimiter = '';
|
||||
$bInbox = false;
|
||||
foreach ($this->yieldUntaggedResponses() as $oResponse) {
|
||||
if ('STATUS' === $oResponse->StatusOrIndex && isset($oResponse->ResponseList[2])) {
|
||||
$sFullName = $this->toUTF8($oResponse->ResponseList[2]);
|
||||
if (!isset($aReturn[$sFullName])) {
|
||||
$aReturn[$sFullName] = new Folder($sFullName);
|
||||
if (!isset($oFolderCollection[$sFullName])) {
|
||||
$oFolderCollection[$sFullName] = new Folder($sFullName);
|
||||
}
|
||||
$aReturn[$sFullName]->setStatusFromResponse($oResponse);
|
||||
$oFolderCollection[$sFullName]->setStatusFromResponse($oResponse);
|
||||
}
|
||||
else if ($sCmd === $oResponse->StatusOrIndex && 5 === \count($oResponse->ResponseList)) {
|
||||
try
|
||||
|
|
@ -527,18 +529,16 @@ trait Folders
|
|||
* $oResponse->ResponseList[3] = Delimiter
|
||||
* $oResponse->ResponseList[4] = FullName
|
||||
*/
|
||||
if (isset($aReturn[$sFullName])) {
|
||||
$oFolder = $aReturn[$sFullName];
|
||||
if (isset($oFolderCollection[$sFullName])) {
|
||||
$oFolder = $oFolderCollection[$sFullName];
|
||||
$oFolder->setDelimiter($oResponse->ResponseList[3]);
|
||||
$oFolder->setFlags($oResponse->ResponseList[2]);
|
||||
} else {
|
||||
$oFolder = new Folder($sFullName, $oResponse->ResponseList[3], $oResponse->ResponseList[2]);
|
||||
$aReturn[$sFullName] = $oFolder;
|
||||
$oFolderCollection[$sFullName] = $oFolder;
|
||||
}
|
||||
|
||||
if ($oFolder->IsInbox()) {
|
||||
$bInbox = true;
|
||||
}
|
||||
$bInbox = $bInbox || $oFolder->IsInbox();
|
||||
|
||||
if (!$sDelimiter) {
|
||||
$sDelimiter = $oFolder->Delimiter();
|
||||
|
|
@ -547,8 +547,6 @@ trait Folders
|
|||
if (isset($aMetadata[$oResponse->ResponseList[4]])) {
|
||||
$oFolder->SetAllMetadata($aMetadata[$oResponse->ResponseList[4]]);
|
||||
}
|
||||
|
||||
$aReturn[$sFullName] = $oFolder;
|
||||
}
|
||||
catch (\Throwable $oException)
|
||||
{
|
||||
|
|
@ -557,13 +555,16 @@ trait Folders
|
|||
}
|
||||
}
|
||||
|
||||
// $iOptimizationLimit = $this->Settings->folder_list_limit;
|
||||
// $oFolderCollection->Optimized = 10 < $iOptimizationLimit && $oFolderCollection->count() > $iOptimizationLimit;
|
||||
|
||||
// RFC 5464
|
||||
if ($bMetadata && !$aMetadata /*&& 50 < \count($aReturn)*/) {
|
||||
foreach ($aReturn as $oFolder) {
|
||||
// if (2 > \substr_count($oFolder->FullName(), $oFolder->Delimiter()))
|
||||
if ($bMetadata && !$aMetadata /*&& 50 < $oFolderCollection->count()*/) {
|
||||
foreach ($oFolderCollection as $oFolder) {
|
||||
// if (2 > \substr_count($oFolder->FullName, $oFolder->Delimiter()))
|
||||
try {
|
||||
$oFolder->SetAllMetadata(
|
||||
$this->getMetadata($oFolder->FullName(), ['/shared', '/private'], ['DEPTH'=>'infinity'])
|
||||
$this->getMetadata($oFolder->FullName, ['/shared', '/private'], ['DEPTH'=>'infinity'])
|
||||
);
|
||||
} catch (\Throwable $oException) {
|
||||
// Ignore error
|
||||
|
|
@ -571,11 +572,11 @@ trait Folders
|
|||
}
|
||||
}
|
||||
|
||||
if (!$bInbox && !$sParentFolderName && !isset($aReturn['INBOX'])) {
|
||||
$aReturn['INBOX'] = new Folder('INBOX', $sDelimiter);
|
||||
if (!$bInbox && !$sParentFolderName && !isset($oFolderCollection['INBOX'])) {
|
||||
$oFolderCollection['INBOX'] = new Folder('INBOX', $sDelimiter);
|
||||
}
|
||||
|
||||
return $aReturn;
|
||||
return $oFolderCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -583,7 +584,7 @@ trait Folders
|
|||
* @throws \MailSo\Net\Exceptions\*
|
||||
* @throws \MailSo\Imap\Exceptions\*
|
||||
*/
|
||||
public function FolderSubscribeList(string $sParentFolderName, string $sListPattern) : array
|
||||
public function FolderSubscribeList(string $sParentFolderName, string $sListPattern) : FolderCollection
|
||||
{
|
||||
return $this->FolderList($sParentFolderName, $sListPattern, true);
|
||||
}
|
||||
|
|
@ -593,7 +594,7 @@ trait Folders
|
|||
* @throws \MailSo\Net\Exceptions\*
|
||||
* @throws \MailSo\Imap\Exceptions\*
|
||||
*/
|
||||
public function FolderStatusList(string $sParentFolderName, string $sListPattern) : array
|
||||
public function FolderStatusList(string $sParentFolderName, string $sListPattern) : FolderCollection
|
||||
{
|
||||
return $this->FolderList($sParentFolderName, $sListPattern, false, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class Folder implements \JsonSerializable
|
|||
if (!\strlen($sFullName)) {
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
$this->FolderName = $sFullName;
|
||||
$this->FullName = $sFullName;
|
||||
$this->setDelimiter($sDelimiter);
|
||||
$this->setFlags($aFlags);
|
||||
/*
|
||||
|
|
@ -68,7 +68,7 @@ class Folder implements \JsonSerializable
|
|||
|
||||
public function Name() : string
|
||||
{
|
||||
$sNameRaw = $this->FolderName;
|
||||
$sNameRaw = $this->FullName;
|
||||
if ($this->sDelimiter) {
|
||||
$aNames = \explode($this->sDelimiter, $sNameRaw);
|
||||
return \end($aNames);
|
||||
|
|
@ -76,11 +76,6 @@ class Folder implements \JsonSerializable
|
|||
return $sNameRaw;
|
||||
}
|
||||
|
||||
public function FullName() : string
|
||||
{
|
||||
return $this->FolderName;
|
||||
}
|
||||
|
||||
public function Delimiter() : ?string
|
||||
{
|
||||
return $this->sDelimiter;
|
||||
|
|
@ -91,14 +86,10 @@ class Folder implements \JsonSerializable
|
|||
return $this->aFlagsLowerCase;
|
||||
}
|
||||
|
||||
public function Exists() : bool
|
||||
{
|
||||
return !\in_array('\\nonexistent', $this->aFlagsLowerCase);
|
||||
}
|
||||
|
||||
public function Selectable() : bool
|
||||
{
|
||||
return !\in_array('\\noselect', $this->aFlagsLowerCase) && $this->Exists();
|
||||
return !\in_array('\\noselect', $this->aFlagsLowerCase)
|
||||
&& !\in_array('\\nonexistent', $this->aFlagsLowerCase);
|
||||
}
|
||||
|
||||
public function IsSubscribed() : bool
|
||||
|
|
@ -108,7 +99,7 @@ class Folder implements \JsonSerializable
|
|||
|
||||
public function IsInbox() : bool
|
||||
{
|
||||
return 'INBOX' === \strtoupper($this->FolderName) || \in_array('\\inbox', $this->aFlagsLowerCase);
|
||||
return 'INBOX' === \strtoupper($this->FullName) || \in_array('\\inbox', $this->aFlagsLowerCase);
|
||||
}
|
||||
|
||||
public function SetMetadata(string $sName, string $sData) : void
|
||||
|
|
@ -150,7 +141,7 @@ class Folder implements \JsonSerializable
|
|||
if ($match) {
|
||||
$role = \array_shift($match);
|
||||
}
|
||||
if (!$role && 'INBOX' === \strtoupper($this->FolderName)) {
|
||||
if (!$role && 'INBOX' === \strtoupper($this->FullName)) {
|
||||
return 'inbox';
|
||||
}
|
||||
}
|
||||
|
|
@ -179,17 +170,14 @@ class Folder implements \JsonSerializable
|
|||
/*
|
||||
if ($this->ImapClient->hasCapability('ACL') || $this->ImapClient->CapabilityValue('RIGHTS')) {
|
||||
// MailSo\Imap\Responses\ACL
|
||||
$rights = $this->ImapClient->FolderMyRights($this->FolderName);
|
||||
$rights = $this->ImapClient->FolderMyRights($this->FullName);
|
||||
}
|
||||
*/
|
||||
return array(
|
||||
'@Object' => 'Object/Folder',
|
||||
'name' => $this->Name(),
|
||||
'fullName' => $this->FolderName,
|
||||
'fullName' => $this->FullName,
|
||||
'delimiter' => (string) $this->sDelimiter,
|
||||
'isSubscribed' => $this->IsSubscribed(),
|
||||
'exists' => $this->Exists(),
|
||||
'selectable' => $this->Selectable(),
|
||||
'flags' => $this->aFlagsLowerCase,
|
||||
// 'extended' => $aExtended,
|
||||
// 'permanentFlags' => $this->PermanentFlags,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace MailSo\Mail;
|
||||
namespace MailSo\Imap;
|
||||
|
||||
/**
|
||||
* @category MailSo
|
||||
|
|
@ -21,22 +21,16 @@ class FolderCollection extends \MailSo\Base\Collection
|
|||
|
||||
public function append($oFolder, bool $bToTop = false) : void
|
||||
{
|
||||
assert($oFolder instanceof \MailSo\Imap\Folder);
|
||||
assert($oFolder instanceof Folder);
|
||||
parent::append($oFolder, $bToTop);
|
||||
}
|
||||
|
||||
public function FindDelimiter() : string
|
||||
{
|
||||
$oFolder = $this['INBOX'] ?? $this[0] ?? null;
|
||||
return $oFolder ? $oFolder->Delimiter() : '/';
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return array(
|
||||
'@Object' => 'Collection/FolderCollection',
|
||||
'@Collection' => $this->getArrayCopy(),
|
||||
'@Collection' => \array_values($this->getArrayCopy()),
|
||||
// 'optimized' => $this->Optimized
|
||||
);
|
||||
}
|
||||
|
|
@ -33,9 +33,9 @@ class FolderInformation implements \JsonSerializable
|
|||
*/
|
||||
public array $PermanentFlags = array();
|
||||
|
||||
function __construct(string $sFolderName, bool $bIsWritable)
|
||||
function __construct(string $sFullName, bool $bIsWritable)
|
||||
{
|
||||
$this->FolderName = $sFolderName;
|
||||
$this->FullName = $sFullName;
|
||||
$this->IsWritable = $bIsWritable;
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ class FolderInformation implements \JsonSerializable
|
|||
{
|
||||
$result = array(
|
||||
'id' => $this->MAILBOXID,
|
||||
'name' => $this->FolderName,
|
||||
'name' => $this->FullName,
|
||||
'flags' => $this->Flags,
|
||||
'permanentFlags' => $this->PermanentFlags,
|
||||
'uidNext' => $this->UIDNEXT,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace MailSo\Imap\Traits;
|
|||
*/
|
||||
trait Status
|
||||
{
|
||||
public string $FolderName;
|
||||
public string $FullName;
|
||||
|
||||
public bool $hasStatus = false;
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ trait Status
|
|||
return null;
|
||||
}
|
||||
return \md5('FolderHash/'. \implode('-', [
|
||||
$this->FolderName,
|
||||
$this->FullName,
|
||||
$this->MESSAGES,
|
||||
$this->UIDNEXT,
|
||||
$this->UIDVALIDITY,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
namespace MailSo\Mail;
|
||||
|
||||
use MailSo\Imap\FolderCollection;
|
||||
use MailSo\Imap\FolderInformation;
|
||||
use MailSo\Imap\Enumerations\FetchType;
|
||||
use MailSo\Imap\Enumerations\MessageFlag;
|
||||
|
|
@ -794,45 +795,32 @@ class MailClient
|
|||
|
||||
public function Folders(string $sParent, string $sListPattern, bool $bUseListSubscribeStatus) : ?FolderCollection
|
||||
{
|
||||
$aImapSubscribedFoldersHelper = null;
|
||||
if ($this->oImapClient->hasCapability('LIST-EXTENDED')) {
|
||||
$bUseListSubscribeStatus = false;
|
||||
} else if ($bUseListSubscribeStatus) {
|
||||
// $this->oImapClient->Settings->disable_list_status
|
||||
$oFolderCollection = $this->oImapClient->FolderStatusList($sParent, $sListPattern);
|
||||
if (!$oFolderCollection->count()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($bUseListSubscribeStatus && !$this->oImapClient->hasCapability('LIST-EXTENDED')) {
|
||||
// $this->oLogger && $this->oLogger->Write('RFC5258 not supported, using LSUB');
|
||||
// \SnappyMail\Log::warning('IMAP', 'RFC5258 not supported, using LSUB');
|
||||
try
|
||||
{
|
||||
$aSubscribedFolders = $this->oImapClient->FolderSubscribeList($sParent, $sListPattern);
|
||||
$aImapSubscribedFoldersHelper = array();
|
||||
foreach ($aSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) {
|
||||
$aImapSubscribedFoldersHelper[] = $oImapFolder->FullName();
|
||||
$oSubscribedFolders = $this->oImapClient->FolderSubscribeList($sParent, $sListPattern);
|
||||
foreach ($oSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) {
|
||||
isset($oFolderCollection[$oImapFolder->FullName])
|
||||
&& $oFolderCollection[$oImapFolder->FullName]->setSubscribed();
|
||||
}
|
||||
}
|
||||
catch (\Throwable $oException)
|
||||
{
|
||||
\SnappyMail\Log::error('IMAP', 'FolderSubscribeList: ' . $oException->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// $this->oImapClient->Settings->disable_list_status
|
||||
$aFolders = $this->oImapClient->FolderStatusList($sParent, $sListPattern);
|
||||
if (!$aFolders) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($bUseListSubscribeStatus) {
|
||||
foreach ($aFolders as $sFullName => /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) {
|
||||
if (null === $aImapSubscribedFoldersHelper || \in_array($sFullName, $aImapSubscribedFoldersHelper)) {
|
||||
foreach ($oFolderCollection as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) {
|
||||
$oImapFolder->setSubscribed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oFolderCollection = new FolderCollection;
|
||||
// $iOptimizationLimit = $this->oImapClient->Settings->folder_list_limit;
|
||||
// $oFolderCollection->Optimized = 10 < $iOptimizationLimit && \count($aFolders) > $iOptimizationLimit;
|
||||
$oFolderCollection->exchangeArray(\array_values($aFolders));
|
||||
|
||||
return $oFolderCollection;
|
||||
}
|
||||
|
||||
|
|
@ -930,23 +918,22 @@ class MailClient
|
|||
throw new \InvalidArgumentException;
|
||||
}
|
||||
|
||||
$aSubscribeFolders = array();
|
||||
$oSubscribedFolders = array();
|
||||
if ($bSubscribe) {
|
||||
$aSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullName, '*');
|
||||
foreach ($aSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) {
|
||||
$this->oImapClient->FolderUnsubscribe($oFolder->FullName());
|
||||
$oSubscribedFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullName, '*');
|
||||
foreach ($oSubscribedFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) {
|
||||
$this->oImapClient->FolderUnsubscribe($oFolder->FullName);
|
||||
}
|
||||
}
|
||||
|
||||
$this->oImapClient->FolderRename($sPrevFolderFullName, $sNewFolderFullName);
|
||||
|
||||
foreach ($aSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) {
|
||||
$sFolderFullNameForResubscribe = $oFolder->FullName();
|
||||
foreach ($oSubscribedFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) {
|
||||
$sFolderFullNameForResubscribe = $oFolder->FullName;
|
||||
if (\str_starts_with($sFolderFullNameForResubscribe, $sPrevFolderFullName)) {
|
||||
$sNewFolderFullNameForResubscribe = $sNewFolderFullName.
|
||||
\substr($sFolderFullNameForResubscribe, \strlen($sPrevFolderFullName));
|
||||
|
||||
$this->oImapClient->FolderSubscribe($sNewFolderFullNameForResubscribe);
|
||||
$this->oImapClient->FolderSubscribe(
|
||||
$sNewFolderFullName . \substr($sFolderFullNameForResubscribe, \strlen($sPrevFolderFullName))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ trait Response
|
|||
);
|
||||
$this->aCheckableFolder = \is_array($aCheckable) ? $aCheckable : array();
|
||||
}
|
||||
$aResult['checkable'] = \in_array($mResponse->FullName(), $this->aCheckableFolder);
|
||||
$aResult['checkable'] = \in_array($mResponse->FullName, $this->aCheckableFolder);
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
|
@ -216,7 +216,7 @@ trait Response
|
|||
return \array_slice($mResult['@Collection'], 0, 100);
|
||||
}
|
||||
if ($mResponse instanceof \MailSo\Mail\AttachmentCollection
|
||||
|| $mResponse instanceof \MailSo\Mail\FolderCollection
|
||||
|| $mResponse instanceof \MailSo\Imap\FolderCollection
|
||||
|| $mResponse instanceof \MailSo\Mail\MessageCollection
|
||||
) {
|
||||
return $mResult;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue