Bool HandleLookNewsgroup(char *ptr, long len) { ID resource_id; WORD newsgroup; BYTE permission; char message[MAXMESSAGE + 1]; char* msg = message; int temp_len; object_node obj; temp_len = SIZE_NEWSGROUP_ID + 1 + SIZE_ID * 4 + SIZE_ANIMATE; if (len < temp_len) return False; Extract(&ptr, &newsgroup, SIZE_NEWSGROUP_ID); Extract(&ptr, &permission, 1); ExtractObject(&ptr, &obj); Extract(&ptr, &resource_id, SIZE_ID); /* Remove format string id # & other ids from length */ if (!CheckServerMessage(&msg, &ptr, len - temp_len, resource_id)) return False; UserReadNews(&obj, msg, newsgroup, permission); return True; }
Bool HandleMail(char *ptr, long len) { long index; WORD num_recipients, i; char message[MAXMESSAGE + MAX_SUBJECT + 200]; char* msg = message; char sender[MAXUSERNAME + 1]; char recipients[MAX_RECIPIENTS][MAXUSERNAME + 1]; ID resource_id; long msg_time; char *start = ptr; Extract(&ptr, &index, 4); len -= 4; len = ExtractString(&ptr, len, sender, MAXUSERNAME); if (len == -1) return False; Extract(&ptr, &msg_time, SIZE_TIME); Extract(&ptr, &num_recipients, SIZE_NUM_RECIPIENTS); len -= SIZE_TIME + SIZE_NUM_RECIPIENTS; // If somehow mail message is screwed up, delete it if (num_recipients > MAX_RECIPIENTS) { RequestDeleteMail(index); return False; } /* If no recipients, then there is no more mail */ if (num_recipients == 0) { MailNewMessage(0, sender, 0, NULL, NULL, 0); return True; } for (i=0; i < num_recipients; i++) { len = ExtractString(&ptr, len, recipients[i], MAXUSERNAME); if (len == -1) return False; } Extract(&ptr, &resource_id, SIZE_ID); len -= SIZE_ID; /* Remove format string id # & other ids from length */ if (!CheckServerMessage(&msg, &ptr, len, resource_id)) return False; MailNewMessage(index, sender, num_recipients, recipients, msg, msg_time); return True; }
/* * CheckServerMessage: Assemble a set of printf-style strings into a resultant * string. The initial format string is given by the fmt_id resource, and the * parameters are in params. The result is placed in message. Len is the # of bytes * in params. * Returns True iff len bytes of parameters are used in assembling message, otherwise * False, which indicates an error in the message from the server. * The allowed printf-style format characters are: * %d or %i a literal integer * %q a literal string * %s an integer which specifies a string resource. This resource may * contain other format characters. If so, they are matched with * parameters from params AFTER the initial string's parameters. * %r specifies that the next resource in the message should be concatenated * into the place of this format character (calls CheckServerMessage) */ Bool CheckServerMessage(char** msg, char **params, long *len, ID fmt_id) { char *fmt, *next_ptr; /* next_ptr points into format string fmt */ char tempfmt[MAXMESSAGE], format[MAXMESSAGE], *param_ptr = *params; char* message; char message2[MAXMESSAGE]; char* msg2 = message2; /* Pointer to message2 */ char *rsc, type_char, *orig_message; DWORD field, num_chars; WORD string_len; Bool done = False; /* qparams are %q parameters; we need to save their positions and replace them last, * even after %s (in case replacement %q string contains a literal %s) */ /* Each element of the qparams array points to the place in params where the string for to replace the corresponding %q begins */ char *qparams[MAXQPARAMS + 1]; int num_qparams = 1; /* Start counting at 1 to avoid null character */ /* Get the buffer to send back the message. * If it turns out we have no formatting to do, then we'll send back * the resource string itself instead of filling the caller's limited buffer. */ if (!msg || !*msg) return False; // Set the first character of msg to null terminator, so we can check // the length of msg. *msg[0] = '\0'; message = *msg; /* Get format string from resources */ fmt = LookupRsc(fmt_id); if (fmt == NULL) return False; /* Is there anything to format at all? * Or can we return the "format" resource as-is? */ rsc = fmt; while (*rsc) { if (rsc[0] == '%') { if (rsc[1] == '%') rsc++; else break; } rsc++; } if (!*rsc) { *msg = fmt; return True; } /* Prepare to format into the caller's message buffer. */ orig_message = message; /* Keep looping through string until there's nothing left to replace */ while (!done) { done = True; /* We'll be done if we don't find any %s's */ /* Find first format field */ next_ptr = strchr(fmt, '%'); /* Invariant: len is # of bytes remaining in params */ while (next_ptr != NULL) { next_ptr++; /* Move to type character */ type_char = *next_ptr; /* If string ends with %, done */ if (type_char == '\0') break; /* Skip marked %q parameters */ if (type_char <= MAXQPARAMS) { next_ptr = strchr(next_ptr, '%'); continue; } next_ptr++; /* Move past field specification char */ /* Make temporary buffer for this section of format string */ strncpy(tempfmt, fmt, next_ptr - fmt); tempfmt[next_ptr - fmt] = '\0'; switch (type_char) { case '%': /* %% ==> % */ *message++ = '%'; break; case 'r': if (*len < SIZE_ID) { PostMessage(hMain, BK_NORESOURCE, 0, 0); return False; } // Get the next resource in the server message, increment param_ptr. memcpy(&field, param_ptr, SIZE_ID); param_ptr += SIZE_ID; *len -= SIZE_ID; // Process the next resource as if it were a complete message. if (!CheckServerMessage(&msg2, ¶m_ptr, len, field)) return False; // Check if we're going to write outside the bounds of msg. if (strlen(*msg) + strlen(msg2) >= MAXMESSAGE) { PostMessage(hMain, BK_NORESOURCE, 0, 0); return False; } // This block of code adds the current message 'part' into message, // but we have to remove the 'r' and add %s as %r isn't a valid // sprintf formatter, while %s is. // Copy the part before the %r modifier into message. num_chars = sprintf(message, tempfmt); // Increment message, but remove the 'r' character. message += (num_chars - 1); // Copy the msg2 string into message. num_chars = sprintf(message, "%s", msg2); message += num_chars; // Reset message2 and msg2. message2[MAXMESSAGE]; msg2 = message2; // Get rid of any numbered parameter formatters. if (*next_ptr == '$') { next_ptr++; if (*next_ptr != '$') { next_ptr++; } } break; case 'd': case 'i': case 's': /* See if there are enough bytes left */ if (*len < SIZE_ID) return False; /* Interpret next field as an integer */ memcpy(&field, param_ptr, SIZE_ID); param_ptr += SIZE_ID; *len -= SIZE_ID; /* Look up resource strings; use integers immediately */ if (type_char == 's') { done = False; if ((rsc = LookupRsc(field)) == NULL) return False; num_chars = sprintf(message, tempfmt, rsc); } else { num_chars = sprintf(message, tempfmt, field); } // Get rid of any numbered parameter formatters. if (*next_ptr == '$') { next_ptr++; if (*next_ptr != '$') { next_ptr++; } } message += num_chars; /* Overwrite null char next time */ break; case 'q': /* Literal string from server */ /* Store location; we will perform replacement later */ if (*len < SIZE_STRING_LEN) return False; /* We can only hold a certain # of qparams */ if (num_qparams <= MAXQPARAMS) { /* Save current location in parameters */ qparams[num_qparams] = param_ptr; } memcpy(&string_len, param_ptr, SIZE_STRING_LEN); param_ptr += SIZE_STRING_LEN; *len -= SIZE_STRING_LEN; if (*len < string_len) return False; /* Mark this position with qparam # */ if (num_qparams <= MAXQPARAMS) { tempfmt[(next_ptr - fmt) - 1] = (char) num_qparams; num_qparams++; } /* Copy this section of format string */ strncpy(message, tempfmt, (next_ptr - fmt)); message += (next_ptr - fmt); // Add a null terminator here so we can check length of string // if there is an %r formatter next. *message = '\0'; /* Skip string */ param_ptr += string_len; *len -= string_len; // Get rid of any numbered parameter formatters. if (*next_ptr == '$') { next_ptr++; if (*next_ptr != '$') { next_ptr++; } } break; } /* Find next format field */ fmt = next_ptr; next_ptr = strchr(fmt, '%'); } /* Copy over last part of string */ strcpy(message, fmt); /* Prepare for next pass */ message = orig_message; strcpy(format, message); fmt = format; } // Set params to remainder of server message *params = param_ptr; /* Now fill in marked %q fields. Note that format cotains copy of message */ fmt = format; next_ptr = strchr(format, '%'); while (next_ptr != NULL) { next_ptr++; /* Move to type character */ type_char = *next_ptr; /* If string ends with %, done */ if (type_char == '\0') break; /* See if this is a marked %q field */ if (type_char > MAXQPARAMS) { next_ptr = strchr(next_ptr, '%'); continue; } next_ptr++; /* Move past field specification char */ /* Make temporary buffer for this section of format string */ strncpy(tempfmt, fmt, next_ptr - fmt); tempfmt[next_ptr - fmt] = '\0'; /* Get length of string */ param_ptr = qparams[type_char]; memcpy(&string_len, param_ptr, SIZE_STRING_LEN); param_ptr += SIZE_STRING_LEN; /* Hack off %q from format string */ tempfmt[(next_ptr - fmt) - 2] = '\0'; /* Add tempfmt and then literal string to end of message */ strcpy(message, tempfmt); message += strlen(tempfmt); strncpy(message, param_ptr, string_len); message += string_len; fmt = next_ptr; next_ptr = strchr(fmt, '%'); } /* Copy over last part of string */ strcpy(message, fmt); return True; }