#6: implement IMAP IDLE (RFC 2177) and CONDSTORE (RFC 7162)
This commit is contained in:
1 parent
0ec0698079
commit
6b1e4dc00a
20 files changed
+539
-95
No files matched your search
@@ -18,55 +18,79 @@ func NewFlagRepository(pool *pgxpool.Pool) *FlagRepository {
|
||||
return &FlagRepository{pool: pool}
|
||||
}
|
||||
|
||||
func (r *FlagRepository) SetFlags(ctx context.Context, folderID string, uid uint32, op port.FlagOp, flags []string) error {
|
||||
func (r *FlagRepository) SetFlags(ctx context.Context, folderID string, uid uint32, op port.FlagOp, flags []string, unchangedSince uint64) (bool, error) {
|
||||
tx, err := r.pool.Begin(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("begin transaction: %w", err)
|
||||
return false, fmt.Errorf("begin transaction: %w", err)
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
|
||||
var messageID string
|
||||
var receivedAt any
|
||||
var currentModSeq uint64
|
||||
if err := tx.QueryRow(ctx, `
|
||||
SELECT id, received_at FROM email_messages WHERE folder_id = $1 AND uid = $2
|
||||
`, folderID, uid).Scan(&messageID, &receivedAt); err != nil {
|
||||
return fmt.Errorf("find message folder=%s uid=%d: %w", folderID, uid, err)
|
||||
SELECT modseq FROM email_messages WHERE folder_id = $1 AND uid = $2 AND expunged_at IS NULL
|
||||
`, folderID, uid).Scan(¤tModSeq); err != nil {
|
||||
return false, fmt.Errorf("find message folder=%s uid=%d: %w", folderID, uid, err)
|
||||
}
|
||||
|
||||
if unchangedSince > 0 && currentModSeq > unchangedSince {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var newModSeq uint64
|
||||
if err := tx.QueryRow(ctx, `
|
||||
UPDATE folders SET highest_modseq = highest_modseq + 1 WHERE id = $1 RETURNING highest_modseq
|
||||
`, folderID).Scan(&newModSeq); err != nil {
|
||||
return false, fmt.Errorf("advance highest_modseq for folder %s: %w", folderID, err)
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(ctx, `
|
||||
UPDATE email_messages SET modseq = $1 WHERE folder_id = $2 AND uid = $3 AND expunged_at IS NULL
|
||||
`, newModSeq, folderID, uid); err != nil {
|
||||
return false, fmt.Errorf("update message modseq: %w", err)
|
||||
}
|
||||
|
||||
switch op {
|
||||
case port.FlagOpAdd:
|
||||
for _, flag := range flags {
|
||||
if _, err := tx.Exec(ctx, `
|
||||
INSERT INTO message_flags (message_id, received_at, flag) VALUES ($1, $2, $3)
|
||||
INSERT INTO message_flags (message_id, received_at, flag)
|
||||
SELECT id, received_at, $3 FROM email_messages WHERE folder_id = $1 AND uid = $2 AND expunged_at IS NULL
|
||||
ON CONFLICT DO NOTHING
|
||||
`, messageID, receivedAt, flag); err != nil {
|
||||
return fmt.Errorf("add flag %q: %w", flag, err)
|
||||
`, folderID, uid, flag); err != nil {
|
||||
return false, fmt.Errorf("add flag %q: %w", flag, err)
|
||||
}
|
||||
}
|
||||
case port.FlagOpDel:
|
||||
for _, flag := range flags {
|
||||
if _, err := tx.Exec(ctx, `
|
||||
DELETE FROM message_flags WHERE message_id = $1 AND received_at = $2 AND flag = $3
|
||||
`, messageID, receivedAt, flag); err != nil {
|
||||
return fmt.Errorf("delete flag %q: %w", flag, err)
|
||||
DELETE FROM message_flags WHERE (message_id, received_at) IN (
|
||||
SELECT id, received_at FROM email_messages WHERE folder_id = $1 AND uid = $2 AND expunged_at IS NULL
|
||||
) AND flag = $3
|
||||
`, folderID, uid, flag); err != nil {
|
||||
return false, fmt.Errorf("delete flag %q: %w", flag, err)
|
||||
}
|
||||
}
|
||||
case port.FlagOpSet:
|
||||
if _, err := tx.Exec(ctx, `DELETE FROM message_flags WHERE message_id = $1 AND received_at = $2`, messageID, receivedAt); err != nil {
|
||||
return fmt.Errorf("clear flags before set: %w", err)
|
||||
if _, err := tx.Exec(ctx, `
|
||||
DELETE FROM message_flags WHERE (message_id, received_at) IN (
|
||||
SELECT id, received_at FROM email_messages WHERE folder_id = $1 AND uid = $2 AND expunged_at IS NULL
|
||||
)
|
||||
`, folderID, uid); err != nil {
|
||||
return false, fmt.Errorf("clear flags before set: %w", err)
|
||||
}
|
||||
for _, flag := range flags {
|
||||
if _, err := tx.Exec(ctx, `
|
||||
INSERT INTO message_flags (message_id, received_at, flag) VALUES ($1, $2, $3)
|
||||
INSERT INTO message_flags (message_id, received_at, flag)
|
||||
SELECT id, received_at, $3 FROM email_messages WHERE folder_id = $1 AND uid = $2 AND expunged_at IS NULL
|
||||
ON CONFLICT DO NOTHING
|
||||
`, messageID, receivedAt, flag); err != nil {
|
||||
return fmt.Errorf("set flag %q: %w", flag, err)
|
||||
`, folderID, uid, flag); err != nil {
|
||||
return false, fmt.Errorf("set flag %q: %w", flag, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
return fmt.Errorf("commit: %w", err)
|
||||
return false, fmt.Errorf("commit: %w", err)
|
||||
}
|
||||
return nil
|
||||
return true, nil
|
||||
}
|
||||
Reference in new issue
Block a user