Changeset 5501:e0f0a7915711 for imap
Legend:
- Unmodified
- Added
- Removed
-
imap/command.c
r5499 r5501 197 197 * for checking for a mailbox on append and login 198 198 * IMAP_CMD_PASS: command contains a password. Suppress logging. 199 * IMAP_CMD_QUEUE: only queue command, do not execute. 199 200 * Return 0 on success, -1 on Failure, -2 on OK Failure 200 201 */ -
imap/imap.c
r5499 r5501 857 857 } 858 858 859 /* imap_make_msg_set: make an IMAP4rev1 UID message set out of a set of 860 * headers, given a flag enum to filter on. 861 * Params: idata: IMAP_DATA containing context containing header set 862 * buf: to write message set into 863 * flag: enum of flag type on which to filter 864 * changed: include only changed messages in message set 865 * invert: invert sense of flag, eg M_READ matches unread messages 866 * Returns: number of messages in message set (0 if no matches) */ 867 int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag, int changed, 868 int invert) 869 { 870 HEADER** hdrs; /* sorted local copy */ 859 /* Note: headers must be in SORT_ORDER. See imap_exec_msgset for args. 860 * Pos is an opaque pointer a la strtok. It should be 0 at first call. */ 861 static int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag, 862 int changed, int invert, int* pos) 863 { 864 HEADER** hdrs = idata->ctx->hdrs; 871 865 int count = 0; /* number of messages in message set */ 872 866 int match = 0; /* whether current message matches flag condition */ 873 867 unsigned int setstart = 0; /* start of current message range */ 874 868 int n; 875 short oldsort; /* we clobber reverse, must restore it */876 869 int started = 0; 877 870 878 if (Sort != SORT_ORDER) 879 { 880 hdrs = safe_calloc (idata->ctx->msgcount, sizeof (HEADER*)); 881 memcpy (hdrs, idata->ctx->hdrs, idata->ctx->msgcount * sizeof (HEADER*)); 882 883 oldsort = Sort; 884 Sort = SORT_ORDER; 885 qsort ((void*) hdrs, idata->ctx->msgcount, sizeof (HEADER*), 886 mutt_get_sort_func (SORT_ORDER)); 887 Sort = oldsort; 888 } 889 else 890 hdrs = idata->ctx->hdrs; 871 hdrs = idata->ctx->hdrs; 891 872 892 for (n = 0; n < idata->ctx->msgcount; n++) 873 for (n = *pos; 874 n < idata->ctx->msgcount && buf->dptr - buf->data < IMAP_MAX_CMDLEN; 875 n++) 893 876 { 894 877 match = 0; … … 952 935 } 953 936 937 *pos = n; 938 939 return count; 940 } 941 942 /* Prepares commands for all messages matching conditions (must be flushed 943 * with imap_exec) 944 * Params: 945 * idata: IMAP_DATA containing context containing header set 946 * pre, post: commands are of the form "%s %s %s %s", tag, 947 * pre, message set, post 948 * flag: enum of flag type on which to filter 949 * changed: include only changed messages in message set 950 * invert: invert sense of flag, eg M_READ matches unread messages 951 * Returns: number of matched messages, or -1 on failure */ 952 int imap_exec_msgset (IMAP_DATA* idata, const char* pre, const char* post, 953 int flag, int changed, int invert) 954 { 955 HEADER** hdrs = NULL; 956 short oldsort; 957 BUFFER* cmd; 958 int pos; 959 int rc; 960 int count = 0; 961 962 if (! (cmd = mutt_buffer_init (NULL))) 963 { 964 dprint (1, (debugfile, "imap_exec_msgset: unable to allocate buffer\n")); 965 return -1; 966 } 967 968 /* We make a copy of the headers just in case resorting doesn't give 969 exactly the original order (duplicate messages?), because other parts of 970 the ctx are tied to the header order. This may be overkill. */ 971 oldsort = Sort; 954 972 if (Sort != SORT_ORDER) 955 FREE (&hdrs); 956 957 return count; 973 { 974 hdrs = idata->ctx->hdrs; 975 idata->ctx->hdrs = safe_malloc (idata->ctx->msgcount * sizeof (HEADER*)); 976 memcpy (idata->ctx->hdrs, hdrs, idata->ctx->msgcount * sizeof (HEADER*)); 977 978 oldsort = Sort; 979 Sort = SORT_ORDER; 980 qsort (idata->ctx->hdrs, idata->ctx->msgcount, sizeof (HEADER*), 981 mutt_get_sort_func (SORT_ORDER)); 982 } 983 984 pos = 0; 985 986 do 987 { 988 cmd->dptr = cmd->data; 989 mutt_buffer_printf (cmd, "%s ", pre); 990 rc = imap_make_msg_set (idata, cmd, flag, changed, invert, &pos); 991 if (rc > 0) 992 { 993 mutt_buffer_printf (cmd, " %s", post); 994 if (imap_exec (idata, cmd->data, IMAP_CMD_QUEUE)) 995 { 996 rc = -1; 997 goto out; 998 } 999 count += rc; 1000 } 1001 } 1002 while (rc > 0); 1003 1004 rc = count; 1005 1006 out: 1007 mutt_buffer_free (&cmd); 1008 if (oldsort != Sort) 1009 { 1010 Sort = oldsort; 1011 FREE (&idata->ctx->hdrs); 1012 idata->ctx->hdrs = hdrs; 1013 } 1014 1015 return rc; 958 1016 } 959 1017 … … 978 1036 979 1037 /* Update the IMAP server to reflect the flags a single message. */ 980 981 1038 int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd, 982 1039 int *err_continue) … … 1056 1113 } 1057 1114 1058 static int sync_helper (IMAP_DATA* idata, BUFFER* buf, int right, int flag, 1059 const char* name) 1060 { 1061 int rc = 0; 1115 static int sync_helper (IMAP_DATA* idata, int right, int flag, const char* name) 1116 { 1117 int count = 0; 1118 int rc; 1119 1120 char buf[LONG_STRING]; 1062 1121 1063 1122 if (!mutt_bit_isset (idata->ctx->rights, right)) 1064 1123 return 0; 1065 1124 1066 1125 if (right == M_ACL_WRITE && !imap_has_flag (idata->flags, name)) 1067 1126 return 0; 1068 1127 1069 buf->dptr = buf->data; 1070 mutt_buffer_addstr (buf, "UID STORE "); 1071 if (imap_make_msg_set (idata, buf, flag, 1, 0)) 1072 { 1073 rc++; 1074 mutt_buffer_printf (buf, " +FLAGS.SILENT (%s)", name); 1075 imap_exec (idata, buf->data, IMAP_CMD_QUEUE); 1076 } 1077 buf->dptr = buf->data; 1078 mutt_buffer_addstr (buf, "UID STORE "); 1079 if (imap_make_msg_set (idata, buf, flag, 1, 1)) 1080 { 1081 rc++; 1082 mutt_buffer_printf (buf, " -FLAGS.SILENT (%s)", name); 1083 imap_exec (idata, buf->data, IMAP_CMD_QUEUE); 1084 } 1085 1086 return rc; 1128 snprintf (buf, sizeof(buf), "+FLAGS.SILENT (%s)", name); 1129 if ((rc = imap_exec_msgset (idata, "UID STORE", buf, flag, 1, 0)) < 0) 1130 return rc; 1131 count += rc; 1132 1133 buf[0] = '-'; 1134 if ((rc = imap_exec_msgset (idata, "UID STORE", buf, flag, 1, 1)) < 0) 1135 return rc; 1136 count += rc; 1137 1138 return count; 1087 1139 } 1088 1140 … … 1096 1148 IMAP_DATA* idata; 1097 1149 CONTEXT* appendctx = NULL; 1098 BUFFER cmd;1099 1150 HEADER* h; 1100 1151 HEADER** hdrs = NULL; 1101 1152 int oldsort; 1102 int deleted;1103 1153 int n; 1104 1154 int rc; … … 1119 1169 return rc; 1120 1170 1121 memset (&cmd, 0, sizeof (cmd));1122 1123 1171 /* if we are expunging anyway, we can do deleted messages very quickly... */ 1124 1172 if (expunge && mutt_bit_isset (idata->ctx->rights, M_ACL_DELETE)) 1125 1173 { 1126 mutt_buffer_addstr (&cmd, "UID STORE "); 1127 deleted = imap_make_msg_set (idata, &cmd, M_DELETED, 1, 0); 1128 1129 /* if we have a message set, then let's delete */ 1130 if (deleted) 1131 { 1132 mutt_message (_("Marking %d messages deleted..."), deleted); 1133 mutt_buffer_addstr (&cmd, " +FLAGS.SILENT (\\Deleted)"); 1174 if ((rc = imap_exec_msgset (idata, "UID STORE", "+FLAGS.SILENT (\\Deleted)", 1175 M_DELETED, 1, 0)) < 0) 1176 { 1177 mutt_error (_("Expunge failed")); 1178 mutt_sleep (1); 1179 goto out; 1180 } 1181 1182 if (rc > 0) 1183 { 1134 1184 /* mark these messages as unchanged so second pass ignores them. Done 1135 1185 * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */ 1136 1186 for (n = 0; n < ctx->msgcount; n++) 1137 if (ctx->hdrs[n]->deleted && ctx->hdrs[n]->changed) 1138 ctx->hdrs[n]->active = 0; 1139 if (imap_exec (idata, cmd.data, 0) != 0) 1140 { 1141 mutt_error (_("Expunge failed")); 1142 mutt_sleep (1); 1143 rc = -1; 1144 goto out; 1145 } 1187 if (ctx->hdrs[n]->deleted && ctx->hdrs[n]->changed) 1188 ctx->hdrs[n]->active = 0; 1189 mutt_message (_("Marking %d messages deleted..."), rc); 1146 1190 } 1147 1191 } … … 1177 1221 appendctx = mx_open_mailbox (ctx->path, M_APPEND | M_QUIET, NULL); 1178 1222 if (!appendctx) 1179 {1180 1223 dprint (1, (debugfile, "imap_sync_mailbox: Error opening mailbox in append mode\n")); 1181 }1182 1224 else 1183 1225 _mutt_save_message (h, appendctx, 1, 0, 0); … … 1193 1235 rc = 0; 1194 1236 1195 /* presort here to avoid doing 10 resorts in imap_ make_msg_set */1237 /* presort here to avoid doing 10 resorts in imap_exec_msgset */ 1196 1238 oldsort = Sort; 1197 1239 if (Sort != SORT_ORDER) … … 1207 1249 } 1208 1250 1209 rc += sync_helper (idata, &cmd,M_ACL_DELETE, M_DELETED, "\\Deleted");1210 rc += sync_helper (idata, &cmd,M_ACL_WRITE, M_FLAG, "\\Flagged");1211 rc += sync_helper (idata, &cmd,M_ACL_WRITE, M_OLD, "Old");1212 rc += sync_helper (idata, &cmd,M_ACL_SEEN, M_READ, "\\Seen");1213 rc += sync_helper (idata, &cmd,M_ACL_WRITE, M_REPLIED, "\\Answered");1251 rc += sync_helper (idata, M_ACL_DELETE, M_DELETED, "\\Deleted"); 1252 rc += sync_helper (idata, M_ACL_WRITE, M_FLAG, "\\Flagged"); 1253 rc += sync_helper (idata, M_ACL_WRITE, M_OLD, "Old"); 1254 rc += sync_helper (idata, M_ACL_SEEN, M_READ, "\\Seen"); 1255 rc += sync_helper (idata, M_ACL_WRITE, M_REPLIED, "\\Answered"); 1214 1256 1215 1257 if (oldsort != Sort) … … 1220 1262 } 1221 1263 1222 if (rc )1223 { 1224 if ( (rc = imap_exec (idata, NULL, 0)) != IMAP_CMD_OK)1225 { 1226 if ( ctx->closing)1264 if (rc && (imap_exec (idata, NULL, 0) != IMAP_CMD_OK)) 1265 { 1266 if (ctx->closing) 1267 { 1268 if (mutt_yesorno (_("Error saving flags. Close anyway?"), 0) == M_YES) 1227 1269 { 1228 if (mutt_yesorno (_("Error saving flags. Close anyway?"), 0) == M_YES) 1229 { 1230 rc = 0; 1231 idata->state = IMAP_AUTHENTICATED; 1232 goto out; 1233 } 1270 rc = 0; 1271 idata->state = IMAP_AUTHENTICATED; 1272 goto out; 1234 1273 } 1235 else 1236 mutt_error _("Error saving flags"); 1237 goto out; 1238 } 1239 } 1274 } 1275 else 1276 mutt_error _("Error saving flags"); 1277 goto out; 1278 } 1279 1240 1280 for (n = 0; n < ctx->msgcount; n++) 1241 1281 ctx->hdrs[n]->changed = 0; … … 1269 1309 1270 1310 out: 1271 if (cmd.data)1272 FREE (&cmd.data);1273 1311 if (appendctx) 1274 1312 { -
imap/imap_private.h
r5499 r5501 56 56 57 57 #define SEQLEN 5 58 /* maximum length of command lines before they must be split (for 59 * lazy servers) */ 60 #define IMAP_MAX_CMDLEN 1024 58 61 59 62 #define IMAP_REOPEN_ALLOW (1<<0) … … 226 229 int create); 227 230 void imap_mboxcache_free (IMAP_DATA* idata); 228 int imap_ make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag, int changed,229 int invert);231 int imap_exec_msgset (IMAP_DATA* idata, const char* pre, const char* post, 232 int flag, int changed, int invert); 230 233 int imap_open_connection (IMAP_DATA* idata); 231 234 void imap_close_connection (IMAP_DATA* idata); -
imap/message.c
r5499 r5501 689 689 IMAP_DATA* idata; 690 690 BUFFER cmd, sync_cmd; 691 char uid[11];692 691 char mbox[LONG_STRING]; 693 692 char mmbox[LONG_STRING]; 693 char prompt[LONG_STRING]; 694 694 int rc; 695 695 int n; 696 696 IMAP_MBOX mx; 697 697 int err_continue = M_NO; 698 int triedcreate = 0; 698 699 699 700 idata = (IMAP_DATA*) ctx->data; … … 720 721 721 722 imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox)); 722 723 memset (&sync_cmd, 0, sizeof (sync_cmd)); 724 memset (&cmd, 0, sizeof (cmd)); 725 mutt_buffer_addstr (&cmd, "UID COPY "); 726 727 /* Null HEADER* means copy tagged messages */ 728 if (!h) 729 { 730 /* if any messages have attachments to delete, fall through to FETCH 731 * and APPEND. TODO: Copy what we can with COPY, fall through for the 732 * remainder. */ 733 for (n = 0; n < ctx->msgcount; n++) 734 { 735 if (ctx->hdrs[n]->tagged && ctx->hdrs[n]->attach_del) 723 imap_munge_mbox_name (mmbox, sizeof (mmbox), mbox); 724 725 /* loop in case of TRYCREATE */ 726 do 727 { 728 memset (&sync_cmd, 0, sizeof (sync_cmd)); 729 memset (&cmd, 0, sizeof (cmd)); 730 731 /* Null HEADER* means copy tagged messages */ 732 if (!h) 733 { 734 /* if any messages have attachments to delete, fall through to FETCH 735 * and APPEND. TODO: Copy what we can with COPY, fall through for the 736 * remainder. */ 737 for (n = 0; n < ctx->msgcount; n++) 736 738 { 737 dprint (3, (debugfile, "imap_copy_messages: Message contains attachments to be deleted\n")); 738 return 1; 739 if (ctx->hdrs[n]->tagged && ctx->hdrs[n]->attach_del) 740 { 741 dprint (3, (debugfile, "imap_copy_messages: Message contains attachments to be deleted\n")); 742 return 1; 743 } 744 745 if (ctx->hdrs[n]->tagged && ctx->hdrs[n]->active && 746 ctx->hdrs[n]->changed) 747 { 748 rc = imap_sync_message (idata, ctx->hdrs[n], &sync_cmd, &err_continue); 749 if (rc < 0) 750 { 751 dprint (1, (debugfile, "imap_copy_messages: could not sync\n")); 752 goto fail; 753 } 754 } 739 755 } 740 756 741 if (ctx->hdrs[n]->tagged && ctx->hdrs[n]->active &&742 ctx->hdrs[n]->changed)757 rc = imap_exec_msgset (idata, "UID COPY", mmbox, M_TAG, 0, 0); 758 if (!rc) 743 759 { 744 rc = imap_sync_message (idata, ctx->hdrs[n], &sync_cmd, &err_continue); 745 if (rc < 0) 746 { 747 dprint (1, (debugfile, "imap_copy_messages: could not sync\n")); 748 goto fail; 749 } 760 dprint (1, (debugfile, "imap_copy_messages: No messages tagged\n")); 761 goto fail; 750 762 } 751 } 752 753 rc = imap_make_msg_set (idata, &cmd, M_TAG, 0, 0); 754 if (!rc) 755 { 756 dprint (1, (debugfile, "imap_copy_messages: No messages tagged\n")); 757 goto fail; 758 } 759 mutt_message (_("Copying %d messages to %s..."), rc, mbox); 760 } 761 else 762 { 763 mutt_message (_("Copying message %d to %s..."), h->index+1, mbox); 764 snprintf (uid, sizeof (uid), "%u", HEADER_DATA (h)->uid); 765 mutt_buffer_addstr (&cmd, uid); 766 767 if (h->active && h->changed) 768 { 769 rc = imap_sync_message (idata, h, &sync_cmd, &err_continue); 770 if (rc < 0) 763 else if (rc < 0) 771 764 { 772 dprint (1, (debugfile, "imap_copy_messages: could not sync\n"));773 goto fail;765 dprint (1, (debugfile, "could not queue copy\n")); 766 goto fail; 774 767 } 775 } 776 } 777 778 /* let's get it on */ 779 mutt_buffer_addstr (&cmd, " "); 780 imap_munge_mbox_name (mmbox, sizeof (mmbox), mbox); 781 mutt_buffer_addstr (&cmd, mmbox); 782 783 rc = imap_exec (idata, cmd.data, IMAP_CMD_FAIL_OK); 784 if (rc == -2) 785 { 786 /* bail out if command failed for reasons other than nonexistent target */ 787 if (ascii_strncasecmp (imap_get_qualifier (idata->buf), "[TRYCREATE]", 11)) 788 { 789 imap_error ("imap_copy_messages", idata->buf); 790 goto fail; 791 } 792 dprint (2, (debugfile, "imap_copy_messages: server suggests TRYCREATE\n")); 793 snprintf (mmbox, sizeof (mmbox), _("Create %s?"), mbox); 794 if (option (OPTCONFIRMCREATE) && mutt_yesorno (mmbox, 1) < 1) 795 { 796 mutt_clear_error (); 797 goto fail; 798 } 799 if (imap_create_mailbox (idata, mbox) < 0) 800 goto fail; 801 802 /* try again */ 803 rc = imap_exec (idata, cmd.data, 0); 804 } 768 else 769 mutt_message (_("Copying %d messages to %s..."), rc, mbox); 770 } 771 else 772 { 773 mutt_message (_("Copying message %d to %s..."), h->index+1, mbox); 774 mutt_buffer_printf (&cmd, "UID COPY %u %s", HEADER_DATA (h)->uid, mmbox); 775 776 if (h->active && h->changed) 777 { 778 rc = imap_sync_message (idata, h, &sync_cmd, &err_continue); 779 if (rc < 0) 780 { 781 dprint (1, (debugfile, "imap_copy_messages: could not sync\n")); 782 goto fail; 783 } 784 } 785 if ((rc = imap_exec (idata, cmd.data, IMAP_CMD_QUEUE)) < 0) 786 { 787 dprint (1, (debugfile, "could not queue copy\n")); 788 goto fail; 789 } 790 } 791 792 /* let's get it on */ 793 rc = imap_exec (idata, NULL, IMAP_CMD_FAIL_OK); 794 if (rc == -2) 795 { 796 if (triedcreate) 797 { 798 dprint (1, (debugfile, "Already tried to create mailbox %s\n", mbox)); 799 break; 800 } 801 /* bail out if command failed for reasons other than nonexistent target */ 802 if (ascii_strncasecmp (imap_get_qualifier (idata->buf), "[TRYCREATE]", 11)) 803 break; 804 dprint (3, (debugfile, "imap_copy_messages: server suggests TRYCREATE\n")); 805 snprintf (prompt, sizeof (prompt), _("Create %s?"), mbox); 806 if (option (OPTCONFIRMCREATE) && mutt_yesorno (prompt, 1) < 1) 807 { 808 mutt_clear_error (); 809 break; 810 } 811 if (imap_create_mailbox (idata, mbox) < 0) 812 break; 813 triedcreate = 1; 814 } 815 } 816 while (rc == -2); 817 805 818 if (rc != 0) 806 819 {
